Compare commits

...

342 Commits

Author SHA1 Message Date
Kelvin Harron 088c021cbc Update README.md for SPM instructions
specified the target to select as part of the SPM installation process
2023-06-03 14:39:07 +02:00
Matyáš Kříž 475322e609 Bump version. 2023-04-17 17:30:01 +02:00
nanashiki 9676d7e374 Up DEPLOYMENT_TARGETs 2023-04-17 17:27:11 +02:00
nanashiki 75a209c3ba Fix String index is out of bounds crash 2023-04-17 17:24:25 +02:00
Matyáš Kříž e29f10eac6 Bump version. 2023-04-11 23:19:48 +02:00
Kabir Oberai 4148a6a7ff Support effectful properties 2023-04-11 23:17:51 +02:00
Kabir Oberai a71ba74df1 Fix generator crashing for property wrappers with empty type. 2023-04-01 10:19:13 +02:00
Matyáš Kříž fa66b6a0a0 Bump version. 2023-03-26 14:22:04 +02:00
Seth Deckard 6f41152d83
Fix Generator to handle reserved keywords
Allows for reserved keywords to be used as argument labels / parameters
in mocked types.

Fixes: https://github.com/Brightify/Cuckoo/issues/452

- Moves escaping util function to Utils and makes it internal since it
  now needs to be used outside of `Generator`.
- Uses escaping function in areas affected by the bug.
- Renames set of reserved names to reflect the larger scope (no longer
  used for just function names).
- Some minor clean-up to style and formatting on areas touched.

Example of the problem:

Generate a mock for a protocol with the function:

```
func escape(for: String) -> String
```

This would result in `for` as a function parameter used within the body
of the function for the mock and verification and stubbing proxies,
which would not compile. This change escapes keywords like this so the
generated code will compile.

See `TestedProtocol.withReservedKeywords` for a test example. An example
was added to `TestedClass` as well, but the real motivation for this is
protocols since conforming types can and often do use a different
parameter name so the argument label like `for` would never be used
within the body of the function.
2023-03-23 08:31:12 -04:00
Matyáš Kříž a9469909b7 Bump version. 2023-03-17 16:26:12 +01:00
Matyáš Kříž 7d51beb752 Update CI. 2023-03-17 16:23:34 +01:00
Matyáš Kříž 41a70422fb Update pbxproj. 2023-03-17 16:21:39 +01:00
David Steinacher f0f77397a5 add missing () when closure is an autoclosure 2023-02-12 16:30:21 +01:00
Matyáš Kříž 835c61246a Completely convert project to Tuist. 2023-01-07 18:58:48 +01:00
Farid Mammadov cbb5f5d416 Add support async/await in Protocol with Associated Type. 2023-01-03 16:46:43 +01:00
Matyáš Kříž 102c9b3a10 Add forgotten file to the project. 2023-01-03 16:39:53 +01:00
sk409 8d7b893bc2 Support NSObjectProtocol inheritance for protocol. 2022-09-19 17:39:55 +02:00
Matyáš Kříž 64b1681e37 Bump version. 2022-09-01 17:04:31 +02:00
sk409 5a9301b97c Remove closure argument name. 2022-09-01 17:00:52 +02:00
Matyáš Kříž 4b5a397f58 Bump version. 2022-08-16 19:40:27 +02:00
Antonio J Pallares 55149ddee9 test: add tests with `OCMQuantifier`s 2022-08-16 16:49:01 +02:00
Antonio J Pallares a84978a0c1 feat: enable OCMock's OCMQuantifier for objcVerify function. Fixes #366 2022-08-16 16:48:58 +02:00
Yoji Ueda 0ff327d675 Remove unnecessary await expression in MockTemplate. 2022-08-16 16:42:21 +02:00
Matyáš Kříž 3df9608f5a Bump version. 2022-07-24 16:18:58 +02:00
Roland Kakonyi 1b0af7cc4a Fix missing attributes for Stubs. 2022-07-24 16:14:15 +02:00
Matyáš Kříž efa47f2afa Update Fastlane. 2022-06-20 21:43:35 +02:00
Matyáš Kříž d3de8c0bfd Bump version. 2022-06-20 21:29:45 +02:00
Tyler Thompson 5d52a7f75b Add support for nested classes. 2022-06-17 19:06:07 +02:00
sk409 3f6e9a84e8 Add support for multiline method signatures. 2022-06-17 18:23:07 +02:00
Roland Kakonyi a3c4ad13f7 Add support for unavailable platforms from available attributes. 2022-06-17 17:49:03 +02:00
Matyáš Kříž 6af1b4d09f Remove duplicate attributes. 2022-05-30 20:28:33 +02:00
Matyáš Kříž 69c1c9aee6 Bump version. 2022-03-18 13:03:35 +01:00
Matyáš Kříž de28aa5f3c Revert "Add SPM support for Cuckoo+OCMock." because of SPM instability.
This reverts commit e4a0153485.
2022-03-18 13:01:22 +01:00
Matyáš Kříž 084f5dbdc3 Fix automatic generator binary upload. 2022-03-17 21:14:20 +01:00
Matyáš Kříž 83b5c4e83b Bump version. 2022-03-17 18:55:22 +01:00
Matyáš Kříž dd8db792ba Don't require a name range for method parameters. 2022-03-17 18:40:48 +01:00
Antonio J Pallares e4a0153485 Add SPM support for Cuckoo+OCMock. 2022-03-10 19:53:38 +01:00
sk409 b1da946216 Ignore missing input paths. 2022-02-23 20:53:08 +01:00
sk409 2775830d13 Escape reserved keywords. 2022-02-13 17:46:04 +01:00
Matyáš Kříž fe7b56381c Bump version. 2022-01-19 17:28:56 +01:00
Matyáš Kříž 21a4fc39df Update `.gitignore`. 2022-01-19 17:22:52 +01:00
Matyáš Kříž 249aba0930 Update `Podfile.lock`. 2022-01-19 17:22:09 +01:00
Ailton Vieira Pinto Filho 53b8ff4428 Add support for concurrency mocking. 2022-01-18 19:37:21 +01:00
Matyáš Kříž 6c6c7fa83c Update PathKit, Spectre, Stencil. 2021-11-29 13:29:29 +01:00
Matyáš Kříž 6473adac0d Make deployed binaries work for both Intel and M1 Macs. 2021-11-29 13:29:14 +01:00
Matyáš Kříž 79b13331e5 Bump version. 2021-11-19 08:05:56 +01:00
Matyáš Kříž b7ff314d6b Raise minimum deployment targets.
iOS to 9.0; Mac OS to 11.0
2021-11-19 08:04:03 +01:00
Matyáš Kříž df8847df2d Update gem dependencies. 2021-11-19 07:55:56 +01:00
Boris Spinner 7da80b2321 Skip cuckoo for SwiftUI preview builds 2021-11-19 07:47:25 +01:00
Akihiro Sakahara eb1502c657 Bump Stencil version to 0.14.2. 2021-11-18 17:10:30 +01:00
Tadeas Kriz 8f1d1f1d09
Add check for index build to the example run script. 2021-10-08 12:49:55 +02:00
Matyáš Kříž d266c2bc68 Update `README.md`. 2021-07-27 13:12:45 +02:00
Matyáš Kříž 0259cd8730 Remove unnecessary whitespace in tests. 2021-07-22 16:24:45 +02:00
Matyáš Kříž 10b480320c Update OCMock to `3.8.1`. 2021-07-22 14:50:00 +02:00
Matyáš Kříž 39e05cdf56 Bump version. 2021-05-25 17:12:33 +02:00
Andreas Ganske 6c59599fc0 Use constant action 2021-05-19 14:37:43 +02:00
Andreas Ganske 798ea3fcdc Make stubbing more thread safe 2021-05-19 14:37:43 +02:00
Tyler Poland 7ca53fb53c Disable bitcode compiler translation to fix linking for Carthage distribution 2021-04-29 10:43:21 -05:00
Tyler Poland 96ff0d11d0 Fix local build failure for Cuckoo-iOS, -macOS, and -tvOS targets 2021-04-28 16:33:15 -05:00
Matyáš Kříž 71d7423add Bump version. 2021-04-28 09:49:19 +02:00
Winnie Teichmann 531f4d403a Update podspec to fix library not found for -lswiftXCTestin Xocde 12.5 2021-04-27 20:57:51 +02:00
Matyáš Kříž 58ec81375b Bump version. 2021-04-15 14:27:47 +02:00
Matty Cross d85e2dd8e7
Remove Slack from `README.md` for now. 2020-08-22 18:49:55 +02:00
dependabot[bot] 1d31d53b04 Bump json from 2.2.0 to 2.3.0
Bumps [json](https://github.com/flori/json) from 2.2.0 to 2.3.0.
- [Release notes](https://github.com/flori/json/releases)
- [Changelog](https://github.com/flori/json/blob/master/CHANGES.md)
- [Commits](https://github.com/flori/json/compare/v2.2.0...v2.3.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-31 19:34:15 +02:00
Michael Gray 6373c81dd2
Update README.md
Co-authored-by: Matty Cross <kriz.matyas8.10@gmail.com>
2020-07-31 13:30:40 -04:00
Michael Gray cacef807d2
Update README.md
Co-authored-by: Matty Cross <kriz.matyas8.10@gmail.com>
2020-07-31 13:25:28 -04:00
Mike Gray bc085e23cf Add example for verify generic return to README.md 2020-07-31 13:14:37 -04:00
Mike Gray f6429bb757 Add tests for verify generic return 2020-07-31 13:14:32 -04:00
Mike Gray 60f2cc0006 Include GeneratedMocks in macOS and tvOS test targets 2020-07-31 11:49:31 -04:00
Mike Gray 403b225770 Allow verify to specify return type for generic functions 2020-07-31 11:39:12 -04:00
Matyáš Kříž 4d8e999f37 Update `.xcodeproj`. 2020-07-31 17:33:39 +02:00
Matyáš Kříž a508ab347f Fix tuist configuration. 2020-07-31 08:11:22 +02:00
Matty Cross bf197c4ccb
Update CHANGELOG.md 2020-07-08 10:49:19 +02:00
Matty Cross 296c14b610
Update syntax highlighting in examples. 2020-07-08 10:47:03 +02:00
Matty Cross 1d302ede70
Use Swift syntax highlight in ObjC example. 2020-07-08 10:45:22 +02:00
Matyáš Kříž 0ef473893c Bump version. 2020-07-08 10:25:36 +02:00
Matyáš Kříž a0a7c82526 Sidestep `SourceKitten`'s off-by-one bug when parsing generic parameter inheritance. 2020-06-28 16:45:16 +02:00
Matyáš Kříž e2bb73412f Fix incorrect `where` clause parsing. 2020-06-28 16:44:48 +02:00
Matyáš Kříž b3bec5f8ff Clean up project. 2020-06-28 16:43:22 +02:00
Matyáš Kříž 8abe3f2091 Add a note about "Input Files". 2020-06-28 13:22:08 +02:00
Matty Cross 07b4a701a4
Update CHANGELOG.md 2020-06-18 20:40:06 +02:00
Matyáš Kříž a732857b79 Bump version. 2020-06-18 20:32:58 +02:00
Matyáš Kříž bfc893657e Add a note about build parallelization. 2020-06-18 20:13:29 +02:00
Matyáš Kříž 3b533e15a0 Add type inference information to README. 2020-06-18 20:03:25 +02:00
Matyáš Kříž c2ff12851f Clean up `MockManager`. 2020-06-18 19:41:58 +02:00
Matyáš Kříž db48119479 Add generic closure test. 2020-06-18 19:41:47 +02:00
Matyáš Kříž 5a1f5f35d9 Add tvOS targets and schemes. 2020-04-01 15:07:38 +02:00
Matyáš Kříž 5afae85bbe Integrate `tuist`. 2020-04-01 15:07:38 +02:00
Matyáš Kříž b1c7c77dbb Fix type equality check to rule out whitespace inconsistencies. 2020-04-01 15:07:13 +02:00
Matty Cross ce2de127e6
Update README.md 2020-03-10 19:38:20 +01:00
Matyáš Kříž 24f743f950 Add `then` with `return` to the tests.
Add missing space.
2020-03-09 19:34:07 +01:00
nisin 826e5c4427 Compare on arrays containing values (OCMock test) 2020-03-09 19:34:07 +01:00
nisin 972f0594f7 add test Sequence Type result by OCMock extention 2020-03-09 19:34:07 +01:00
nisin f81c04b504 add Sequence OCMock extension 2020-03-09 19:34:07 +01:00
Matty Cross 264d2ebb50
Update .travis.yml 2020-03-09 15:01:28 +01:00
Matty Cross d16b4e6635
Remove obsolete sentence from README. 2020-02-29 19:37:52 +01:00
Matty Cross ee447e93c0
Add SwiftPM badge to README. 2020-02-29 19:35:24 +01:00
Matty Cross 9cc13cc195
Update CHANGELOG.md 2020-02-29 19:29:14 +01:00
Matty Cross 6cb87a423f
Update CI badge. 2020-02-29 19:17:51 +01:00
Matyáš Kříž bbdd3304b0 Bump version. 2020-02-23 22:25:53 +01:00
Matyáš Kříž 7fa3d75aee Fix `image not found` error for iOS 13 and beyond. 2020-02-23 22:21:50 +01:00
dependabot[bot] 01fb627626 Bump excon from 0.68.0 to 0.71.0
Bumps [excon](https://github.com/excon/excon) from 0.68.0 to 0.71.0.
- [Release notes](https://github.com/excon/excon/releases)
- [Changelog](https://github.com/excon/excon/blob/master/changelog.txt)
- [Commits](https://github.com/excon/excon/compare/v0.68.0...v0.71.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-02-23 20:07:59 +01:00
Matyáš Kříž 9f6f3e04e6 Bump version. 2020-02-23 19:52:59 +01:00
Matyáš Kříž f3dcdb0edc Update SwiftPM info in README. 2020-02-22 22:22:03 +01:00
Matyáš Kříž 5600ca3d96 Drastically shorten needed command to get the `run` script. 2020-02-22 21:13:01 +01:00
Matyáš Kříž 9e8cdfde9a Add instructions on how to obtain the `run` script. 2020-02-22 21:13:01 +01:00
Matyáš Kříž 4a51ddd885 Remove unwanted space. 2020-02-22 21:13:01 +01:00
Matyáš Kříž 5d68a586de Add SwiftPM section to the `README.md`. 2020-02-22 21:13:01 +01:00
Matyáš Kříž caf0db428f Add Swift Package Manager support. 2020-02-22 21:13:01 +01:00
dependabot[bot] 491ff8dff8 Bump ffi from 1.9.10 to 1.9.25 in /Generator/Tests
Bumps [ffi](https://github.com/ffi/ffi) from 1.9.10 to 1.9.25.
- [Release notes](https://github.com/ffi/ffi/releases)
- [Changelog](https://github.com/ffi/ffi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ffi/ffi/compare/1.9.10...1.9.25)

Signed-off-by: dependabot[bot] <support@github.com>
2020-02-20 21:07:47 +01:00
Matyáš Kříž 1ef420cad8 Add tests to `run` scheme of tvOS. 2020-02-20 21:06:40 +01:00
Rodrigo F. Fernandes 60525cc68f Adds tvOS target 2020-02-20 21:06:40 +01:00
Tadeas Kriz fb9e2ea421 Fix compilation issue introduced by a wrong merge. 2020-02-20 21:05:29 +01:00
Tadeas Kriz 619d8c73dd Adjust accessibility to match enclosing container. 2020-02-20 21:05:29 +01:00
Kevin Wojniak f49e47ee7b Fail immediately if any command fails
I was having issues where the `swift build` command was failing but the script itself wouldn't fail. Using `set -x` will cause the shell script to immediately stop and exit if any command in the script itself fails.
2020-02-20 21:05:18 +01:00
Matyáš Kříž 0a3b667e4f Restructure README. 2020-02-20 21:03:06 +01:00
Matyáš Kříž e763706be7 Ignore `Pods` folder. 2020-02-20 21:00:31 +01:00
Matyáš Kříž 54a86c37da Reduce sentence complexity about unsupportable code structures. 2019-12-31 13:26:19 +01:00
Matyáš Kříž cd58a7f09e Bump version. 2019-11-06 14:33:08 +01:00
Matyáš Kříž 81e1cb59a5 Update Fastlane. 2019-11-06 14:13:43 +01:00
Matyáš Kříž 6a2f9596fb Update `README.md`. 2019-11-06 14:11:05 +01:00
Matyáš Kříž ed1e947e1f Improve code stylistically. 2019-11-06 13:45:16 +01:00
Matyáš Kříž 674ecd9de6 Fix ObjC warning. 2019-11-06 13:42:16 +01:00
Matyáš Kříž cc5afef8f7 Add test cases for closures. 2019-11-06 13:42:04 +01:00
Matyáš Kříž 44dedd3859 Improve code stylistically. 2019-11-05 16:00:49 +01:00
Pubbus 808a19f920 Code cleaning 2019-11-05 16:00:49 +01:00
Pubbus ff4c627d42 Add tests for closure return type extraction. 2019-11-05 16:00:49 +01:00
Pubbus fc91ef5e1c Refactor and fix closure return type matcher 2019-11-05 16:00:49 +01:00
Pubbus 69facb06bb Fix closure generation, return type is required in `withoutActuallyEscaping` from swift 5.1 (XCode11) 2019-11-05 16:00:49 +01:00
Artyom Y. Razinov 67f91fdad6 Switch swift_version to 5.0 and add LIBRARY_SEARCH_PATHS in xcconfig
It is a minimal required fix to avoid a runtime linking error while running tests on iOS versions prior to 13 after building with Xcode 11
2019-11-05 15:59:57 +01:00
Matyáš Kříž e1682c7888 Ignore 32b workspace check flag. 2019-11-01 09:58:22 +01:00
Matyáš Kříž b0e46c78e2 Bump version. 2019-09-11 15:56:34 +02:00
Matyáš Kříž 7eb5517b27 After-rebase fix. 2019-09-11 15:54:13 +02:00
Matyáš Kříž b49d23a6ce Update some gems. 2019-09-11 15:41:47 +02:00
Matyáš Kříž c3af210aff Fix a word. 2019-09-11 15:25:03 +02:00
Matyáš Kříž ba7f7049f4 Add documentation to ObjC matchers and functions. 2019-09-11 11:47:11 +02:00
Matyáš Kříž 60d8aa1597 Add example `Cuckoo/OCMock` usage to README.md. 2019-09-11 11:43:41 +02:00
Matyáš Kříž 308cb86548 Finalize ObjC mocking. 2019-09-11 11:43:41 +02:00
Matyáš Kříž 2228a9bea7 Change buildable name. 2019-09-11 11:43:41 +02:00
Matyáš Kříž f10f174357 Add macOS target for CI testing. 2019-09-11 11:43:41 +02:00
Matyáš Kříž 30c664f744 Add a test with Swift class with dynamic method. 2019-09-11 11:43:41 +02:00
Matyáš Kříž d2f83928ba Add possibility to use `objectiveAny` with String.
by @TadeasKriz
2019-09-11 11:43:41 +02:00
Matyáš Kříž d42fc414f6 Remove useless `Info.plist` files. 2019-09-11 11:43:41 +02:00
Matyáš Kříž 3a42272199 Add initial ObjC mocking functionality utilizing OCMock. 2019-09-11 11:43:41 +02:00
Matyáš Kříž d48f2ab5cc Add swiftdoc for convenience matchers as well as some info to README.md. 2019-09-10 17:44:23 +02:00
Matyáš Kříž c5f6d0cd25 Add verifications for the concrete value matching test. 2019-09-06 10:38:34 +02:00
Matyáš Kříž 0d786501bc Add most common matchers for sequences and dictionaries. 2019-09-05 18:22:12 +02:00
Matyáš Kříž b0c66e7afa Add initial convenience matchers for `Array`, `Dictionary`, and `Set` types. 2019-09-04 17:25:36 +02:00
Matyáš Kříž 4e8abcace6 Bump version. 2019-07-30 16:25:00 +02:00
Matyáš Kříž 9947868805 Add container accessibility to appropriate places in templates. 2019-07-30 16:18:39 +02:00
Matyáš Kříž 18ab4be1d8 Bump version. 2019-07-22 13:15:08 +02:00
Matyáš Kříž 989680cebe Update README with info about a simple type inferrer. 2019-07-22 13:10:48 +02:00
Matyáš Kříž 62befddc20 Add tests for type guesser verification. 2019-07-22 13:10:48 +02:00
Matyáš Kříž 39257d9cc8 Add initial implementation of a type guesser. 2019-07-22 13:10:48 +02:00
Matyáš Kříž e405dbfe0a Copy protocol's accessibility to the implementation caller class. 2019-07-22 13:09:53 +02:00
Matyáš Kříž 86432954a9 Revert accessibility inheritance. 2019-07-22 13:09:53 +02:00
Matthew Cross 76c303797f
Use `master` for reporting CI status. 2019-06-19 17:14:12 +02:00
Matyáš Kříž b5c472b4a2 Remove forgotten return value. 2019-05-29 20:16:56 +02:00
Matyáš Kříž c6965b30ff Bump version. 2019-05-29 20:10:36 +02:00
Matyáš Kříž b3fd0dacfd Some more cleaning along with one more compile test case. 2019-05-29 20:06:10 +02:00
Matyáš Kříž fe3af6709e Clean up and fix a bug where adding a private name to a function made it generate twice and fail the compilation. 2019-05-29 19:44:49 +02:00
Matyáš Kříž 0cb6417067 Make it clear that the `run script` should be above the `Compile Sources` build phase. 2019-05-26 19:13:29 +02:00
Matyáš Kříž 4493b12144 Bump version. 2019-05-26 15:41:07 +02:00
Matyáš Kříž 694bd9c8be Fix generic protocol generation and type erasure with multiple methods of same name. 2019-05-26 15:37:40 +02:00
Matyáš Kříž d69bcd5bdd Fix a bug concerning empty public name methods with no private ones. 2019-05-26 15:36:12 +02:00
Matyáš Kříž ec8c77bd17 Exit `run` script with error if it fails to get generator download URL. 2019-05-20 10:50:37 +02:00
James Hughes efddb1848d use absolute path for cuckoo_generator download location 2019-05-17 10:05:09 -06:00
Matyáš Kříž bbe20871e7 Bump version. 2019-05-17 12:22:38 +02:00
Matyáš Kříž 8412e772fa Don't use `realpath` command not available by default on Mac OS. 2019-05-17 12:18:02 +02:00
Matyáš Kříž 922889ca32 Remove redundant optional classes. 2019-05-16 19:10:40 +02:00
Matyáš Kříž 32b2e3ebf1 Bump version. 2019-05-16 18:53:09 +02:00
Matyáš Kříž e16fb3a383 Add support for optional read only properties. 2019-05-16 18:51:03 +02:00
Dotor, Dr. Alexander f9e035475c Add tests for stubbing optional read only properties. 2019-05-16 18:51:03 +02:00
Matyáš Kříž dda4e2eab6 Bump version. 2019-05-16 13:41:22 +02:00
Matyáš Kříž d0182512e0 Fix `where` that doesn't work in Swift 4. 2019-05-16 13:39:29 +02:00
Matyáš Kříž 0c3333e8d7 Add a future API improvement (it's ambiguous at the moment). 2019-05-16 13:32:38 +02:00
Matyáš Kříž 7a41a928fc Fix some `run` script bugs. 2019-05-16 13:29:44 +02:00
Matyáš Kříž ec10e6bf00 Bump version. 2019-05-15 17:50:57 +02:00
Matyáš Kříž b4c2bbe5b7 Fix incorrect test and simplify two ternary operators. 2019-05-15 17:48:16 +02:00
Matyáš Kříž 449b71e3db Fix `any()` not working anymore by itself with optional parameters in functions. 2019-05-15 17:44:34 +02:00
Matyáš Kříž f3d28b70a9 Fill in changelog and improve readme. 2019-05-15 13:15:32 +02:00
Matyáš Kříž b039aa697f Update fastlane.
It's annoying to see the changelogs every time fastlane is ran.
2019-05-14 19:00:23 +02:00
Matyáš Kříž f4e9608375 Allow warnings of Cocoapods. 2019-05-14 18:57:36 +02:00
Matyáš Kříž 59ac461c98 Bump version. 2019-05-14 18:46:44 +02:00
Matyáš Kříž 1cc26c2ee1 Add `Dictionary` matching. 2019-05-14 18:44:44 +02:00
Matyáš Kříž 51353539bf Revert podspec if it fails validation. 2019-05-14 18:42:51 +02:00
Henrique Gouveia dc0ec1242d Change build_generator to work with swift 5 2019-05-14 17:42:41 +02:00
Matyáš Kříž 935afbfd6a Fix wrong interpolation of github auth token.
Thanks to @jamezilla for noticing this.
2019-05-14 17:41:00 +02:00
Matyáš Kříž 083a6b5c17 Add support for rethrowing functions. 2019-05-14 17:39:15 +02:00
Davide Mazzoni 14afe0a125 Add @available-annotated property to TestedClass 2019-05-14 14:55:20 +02:00
Davide Mazzoni 1b71fcfd2e Add property attributes to stubs and proxies 2019-05-14 14:54:51 +02:00
Matyáš Kříž 2305ec2221 Add necessary types and fix errors. 2019-05-14 14:53:42 +02:00
Matyáš Kříž ec41a4ff97 Add a test class with generic methods to be generated. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 446590b81d Add `GeneratedMocks.swift` to output files for Xcode 10. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 0e894e2b7d Don’t use `UIKit` in tests so that it can be tested on Mac OS. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 732b4f3fed Remove unused gems and add new file to macOS target for tests. 2019-05-14 14:07:54 +02:00
Matyáš Kříž bd28aad894 Use Xcode 10 for testing. 2019-05-14 14:07:54 +02:00
Matyáš Kříž bf8033643c Address PR comments. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 6e869257d3 Make `Optional` tests functional. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 803bd38b58 Add throwing and rethrowing stub functionality. 2019-05-14 14:07:54 +02:00
Matyáš Kříž ffc33ba6db Make closures with no parameters work. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 7cd237c212 Add possibility to mock functions with closures containing up to 7 parameters. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 505da8310f Fix known problems with return type containing “w”. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 58deea7542 Fix optional closure matching. 2019-05-14 14:07:54 +02:00
Matyáš Kříž ae4d42b8d5 After-rebase fixes. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 7d07b486ac Finish generic where clause functionality. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 79c7961e68 Add support for inheritance generic parameters in methods. 2019-05-14 14:07:54 +02:00
Matyáš Kříž ffa15c5a84 Move collision classes to different file, so that they don’t get mocked. 2019-05-14 14:07:54 +02:00
Matyáš Kříž a4e6e5fae6 Remove unnecessary file. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 1118272598 Add documentation. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 31a5a40c0b Fix tests. 2019-05-14 14:07:54 +02:00
Matyáš Kříž 14eaaf945f Add some basic tests for generic class and generic protocol mocks. 2019-05-14 14:07:54 +02:00
Matyáš Kříž f4124a6802 Add generic protocol capability. 2019-05-14 14:07:54 +02:00
Matyáš Kříž f2b492e60e Add generic protocol parsing and generation.
It doesn’t compile yet, though.
2019-05-14 14:07:54 +02:00
Matyáš Kříž b739903983 Add generic class support. 2019-05-14 14:04:47 +02:00
Tadeas Kriz 93a42ccacc Fix not being able to put Optional into functions accepting Optionals. 2019-05-14 14:04:47 +02:00
Matyáš Kříž edb170175e WIP allow non-optional values to be passed as matchers for optionals. 2019-05-14 14:04:47 +02:00
Matyáš Kříž 6affe4029b Add support for inout method parameters. 2019-05-14 14:04:47 +02:00
Matyáš Kříž 170f1b4004 Ignore everything final. 2019-05-14 14:04:47 +02:00
Matyáš Kříž 98559606f8 Generate public variables and functions in public classes. 2019-05-14 14:04:47 +02:00
Tadeas Kriz f70a59169f Bump version. 2019-05-06 10:31:34 +02:00
Tadeas Kriz 9bce92c6bf Update cocoapods. 2019-05-06 10:29:47 +02:00
Tadeas Kriz fa8177c81c Revert version bump. 2019-05-06 10:18:57 +02:00
Tadeas Kriz 5ce0538170 Bump version and remove the deprecated .swift-version file. 2019-05-06 09:59:12 +02:00
Dylan Maryk 6c5501792b Fix warnings when using Swift 5.0 2019-05-06 09:45:50 +02:00
Dylan Maryk 773bc177d4 Fix errors when using Swift 5.0 2019-05-06 09:45:41 +02:00
Tadeas Kriz 18f399097d Improve Xcode 10.2 compatibility. 2019-05-06 09:44:08 +02:00
Davide Mazzoni 31798c0f76 Update FileKit reference 2019-04-08 18:10:08 +02:00
Matyáš Kříž 4d617cd573 Bump version. 2019-02-23 16:39:03 +01:00
Matyáš Kříž 03bf8c1c73 Improve the `run` script. 2019-02-23 15:45:51 +01:00
susan335 87d92153d4 Add about environment variable GITHUB_ACCESS_TOKEN 2019-02-23 12:05:01 +01:00
susan335 63b03cb2d1 Fix indent 2019-02-23 12:05:01 +01:00
susan335 b97e7c3dda Add curl option when download cuckoo_generator
To avoid Github rate limit issues.
In shared environment(like a Circle CI), run script could hit a Github API rate limit.
2019-02-23 12:05:01 +01:00
dmazzoni b0b64cf503 Support spaces in script path in build_generator 2019-02-23 11:58:47 +01:00
Maxim Berezhnoy 6e760b70ce consistent usage across the file 2019-02-23 11:42:23 +01:00
Maxim Berezhnoy 83e79fffd6 consistent variable usage 2019-02-23 11:42:23 +01:00
Matyáš Kříž 349fa1c154 Temporarily fix unintentional collision because of fail-safe classes being in the input file.
It creates way too many merge conflicts if we tried to apply the full fix here.
2019-01-31 13:24:26 +01:00
Matyáš Kříž 6fc3283bfc Check return type for equality as well. 2019-01-24 11:10:21 +01:00
Matthew Cross 944f2c7f8a Change SwiftKit to Brightify. 2019-01-24 11:10:08 +01:00
Matthew Cross 515a91c5ca Update generator and run script usage. 2019-01-24 11:09:54 +01:00
Matyáš Kříž 2bcce595b3 Add `—clean` option to the run script to rebuild the Cuckoo Generator. 2019-01-24 11:09:17 +01:00
Matyáš Kříž 1cd91fb1f4 Finish subimports. 2019-01-24 11:09:03 +01:00
Matyáš Kříž dd252b5b75 Generate correct import. 2019-01-24 11:09:03 +01:00
Matyáš Kříž 4f24586e9c Make regular expressions easier to modify and fix missing backslash. 2019-01-24 11:09:03 +01:00
Matyáš Kříž 312257727f Add support for importing individual types. 2019-01-24 11:09:03 +01:00
Matyáš Kříž e2bc56d7fc Add `FinalClassStub` to the fail-safe. 2019-01-24 11:08:16 +01:00
Matyáš Kříž 75e5ef54a8 Add name conflict in case Cuckoo Generator tries to generate `final` class as a fail-safe. 2019-01-24 11:08:16 +01:00
Matyáš Kříž 233a04fda5 Add `debugMode` capability to `Tokenizer` to output less information in debug mode. 2019-01-24 11:08:16 +01:00
Matyáš Kříž f9f947fc5b Ignore classes marked as `final`. 2019-01-24 11:08:16 +01:00
Matyáš Kříž aa0b7ec77a Use older string subscripting to compile on Xcode 9. 2019-01-24 11:08:16 +01:00
Matyáš Kříž 04c9db0400 Generate attributes for methods and variables. 2019-01-24 11:08:16 +01:00
Matyáš Kříž 5867e24421 Add basic attribute generation. 2019-01-24 11:07:08 +01:00
Matyáš Kříž 1b77516e83 Generate attributes. 2019-01-24 11:07:08 +01:00
Matyáš Kříž 2f6ab41bbc Add `@available` attribute support. 2019-01-24 11:05:37 +01:00
Matyáš Kříž 2961debaba Transform IUO return value as well. 2019-01-24 11:04:30 +01:00
Matyáš Kříž 7ad094cf78 Transform IUO into `Optional` to prevent errors. 2019-01-24 11:04:30 +01:00
Matyáš Kříž 9d6ecf889c Add class accessibility to required places. 2018-11-09 13:36:48 +01:00
Matyáš Kříž d29ab5f839 Show class accessibility. 2018-11-09 13:36:48 +01:00
Matyáš Kříž acf338e4a1 Fix two bugs introduced by code cleaning. 2018-11-09 13:36:14 +01:00
Matyáš Kříž 5c3c305216 Coalesce to `false` if there are no attributes. 2018-11-05 17:29:05 +01:00
Matyáš Kříž b22502a82b Bring back `fallthrough`. 2018-11-05 16:29:04 +01:00
Matyáš Kříž c558179b33 Don’t generate comments if not in debug mode. 2018-11-05 16:25:10 +01:00
Matyáš Kříž 231216b588 Code cleaning. 2018-11-05 15:12:00 +01:00
Tadeas Kriz 7fb9d2d6e8 Bump version. 2018-10-09 14:11:23 +02:00
Tadeas Kriz fa8231105a Fix escaping closure (crashing in Xcode 10). 2018-10-09 13:52:37 +02:00
Tadeas Kriz 12f9bac435 Fix warnings. 2018-10-09 13:52:23 +02:00
Marek Slavik 0fc242dcec Make project compilable. 2018-09-27 15:24:52 +02:00
Tadeas Kriz c6baeda34c Add first draft of a new Mock initialization DSL. 2018-07-06 15:39:08 +02:00
Tadeas Kriz ae465a4689 Add enableDefaultImplementation to protocol Mock. 2018-06-05 16:42:41 +02:00
Tadeas Kriz 59f2240831 Reintroduce support for pre-0.11.0 Cuckoo spies. 2018-06-05 16:35:51 +02:00
Matyáš Kříž 0a5c4f7f1d Remake `ContainerToken` filtering to be more effective and easier to add more filters in the future. (@TadeasKriz) 2018-04-27 13:55:28 +02:00
Matyáš Kříž 76472af91e Add regular expression `class` and `protocol` matching. 2018-04-27 13:55:28 +02:00
Matyáš Kříž 3793af312a Add `glob` switch that parses input paths as globs enabling for easier project scaling. 2018-04-27 13:55:28 +02:00
Matyáš Kříž 8cc707ff7c Build generator by default. Download using `--download [VERSION]` option. 2018-04-13 13:45:27 +02:00
Matyáš Kříž 79e19c6fe3 Modify the `run` bash script to allow the user to build rather than download the `cuckoo_generator`.
The option is `--build`, no shorthand.
2018-04-13 09:29:44 +02:00
Matyáš Kříž 682619c35f Use `Switch` instead of `Option`. 2018-04-06 20:01:30 +02:00
Matyáš Kříž bee9b97bf0 Add a debug flag that generates general info above methods when used. 2018-04-06 19:38:00 +02:00
Tadeas Kriz 5165e3fc52 Bump version. 2018-04-05 17:14:01 +02:00
Tadeas Kriz 7968fdae9d Make sure we keep the `cuckoo_generator` in the `Pods/Cuckoo` dir. 2018-04-05 17:10:27 +02:00
Tadeas Kriz 851a5f9755 Bump version. 2018-04-04 11:27:16 +02:00
Tadeas Kriz e920e14acc Fix handling of access_token and username in Fastfile. 2018-04-04 11:24:07 +02:00
Tadeas Kriz c6e23cdfc8 Make sure we bundle Swift runtime with the released generator. 2018-04-04 10:42:09 +02:00
Jake Van Alstyne 68dae06d96 Disable bitcode 2018-04-04 10:32:57 +02:00
Tadeas Kriz df7138b9f2 Add chmod +x to ensure cuckoo_generator can be executed. 2018-03-26 12:40:53 +02:00
M.Inomata ba9b72b061 clear GREP_OPTIONS environment variable to avoid error. 2018-03-26 12:16:34 +02:00
Matyáš Kříž 72c63071db Bump version. 2018-03-23 21:04:07 +01:00
Matyáš Kříž e81835e64d GitHub doesn't know about the tag until the commit is pushed. That's why it's necessary to push before creating the release. It also must not be a draft. 2018-03-23 21:02:42 +01:00
Matyáš Kříž 81b5bd0e1c Add gemfile.lock changes. 2018-03-23 20:52:57 +01:00
Matyáš Kříž 7aaab444a7 Add Cocoapods to Gemfile. Push only after pod lib lint succeeds. 2018-03-23 20:51:56 +01:00
Matyáš Kříž 853faf631d Lower the version before first bump. 2018-03-23 20:45:30 +01:00
Matyáš Kříž 1aab334a10 Fix passing a parameter to function that takes none. 2018-03-23 20:42:50 +01:00
Matyáš Kříž af699f2ace Remove submodules. 2018-03-23 20:38:24 +01:00
Matyáš Kříž a92d246465 Add pod lib lint check and push the podspec after uploading the cuckoo_generator. 2018-03-23 20:28:42 +01:00
Matyáš Kříž c9e272fccb Finish Fastfile. 2018-03-23 20:19:36 +01:00
Matyáš Kříž 9febf9783d Add build in release mode. Add pod pushing. 2018-03-23 20:02:45 +01:00
Matyáš Kříž 92161a4563 Add pod push to the deploying script. 2018-03-23 19:26:13 +01:00
Matyáš Kříž 1d36cdd55d Codacy review changes. 2018-03-23 18:57:14 +01:00
Jason Gavris 645ba65c73 Add test for sub protocol method 2018-03-23 18:35:49 +01:00
Gyuri Grell ace61bb081 The sort of input files occurred to soon
* The files input via options are mapped to Path objects then sorted. This actually happened too soon, since the array is then converted to a Set, then converted back to an Array. The Set conversion changes the order (since it is unordered) and those we lost the effect of the sort. I move the sort to the correct place, which is on the outermost Array so that the inputPathValues array is now correctly sorted.
2018-03-23 18:18:37 +01:00
Matyáš Kříž cd216972e6 Upgrade Fastfile and podspec. `run` downloads the latest generator if it's deleted. 2018-03-23 18:16:52 +01:00
Matyáš Kříž 6fe686a79e Make the script a bit more resilient. 2018-03-23 18:16:52 +01:00
Matyáš Kříž 3d6bbd31b3 Fix changelog creating and make commit message ignoring broader. 2018-03-23 18:16:52 +01:00
Matyáš Kříž 611f9849a9 Update Gemfile. 2018-03-23 18:16:52 +01:00
Matyáš Kříž 3f1d9c6468 Add initial deployer script for deploying release drafts to github. 2018-03-23 18:16:52 +01:00
Arnaud Lenglet 25d9700f5e fix(readme): fix typos and grammar 2018-03-23 18:13:48 +01:00
Arnaud Lenglet 43a23b4b4f doc(readme): add precision on custom matchers 2018-03-23 18:13:41 +01:00
Wito Chandra e0a1b1f6fe Fix CI-status badge 2018-03-23 17:41:42 +01:00
Ralph Schön 9287e60611 Updated readme run script
This run script should work for the Xcode default structur to get started
2018-03-23 17:40:00 +01:00
Matyáš Kříž 26ba750b2b Make the bash script safe to use with names that contain spaces. 2018-03-19 13:40:26 +01:00
Gyuri Grell f5093adcae Fixes a regression introduced in 96ebbbf
* There was an attempt to make the file order deterministic, but the sorting that was added only worked if all mocks were generated in a single file. If generated to a path, which creates a file per mock, the filenames and the file contents did not match. Solution was to sort the set of paths passed in as options instead, moving the sorting a little earlier than before.
2018-02-21 10:08:02 +01:00
Grant Sheldon b086f6e1f0 Fix sameInstance(as:) ambiguous reference compile-time error. 2018-01-28 20:02:55 -08:00
Arjan Duijzer 614dfaa515 Added test-cases for excluding Classes and Protocols from Mock stub generation 2018-01-02 11:21:21 +01:00
Arjan Duijzer eaab7db26d Added ParameterMatcher for (optional) throwing closures and optionals, e.g. anyThrowingClosure(), anyOptionalThrowingClosure and null()
Added Acceptance test for inheritance stubbing and verifying
2017-12-29 14:14:46 +01:00
Arjan Duijzer f0f31bd0e9 Adding support for overloaded method names 2017-12-29 10:55:11 +01:00
Tadeas Kriz 0f52ceef7e Add a few more tests. 2017-11-15 00:16:23 +01:00
Tadeas Kriz b95d48ecf7 Change `get` in property verification to method instead of a property. 2017-11-14 22:55:23 +01:00
Tadeas Kriz 8e49eefd4d Remove TemplateEncoder and change Spy behavior. 2017-11-14 22:24:18 +01:00
Tadeas Kriz f3190d8bcb Don't test iOS for now. 2017-11-14 17:26:48 +01:00
Tadeas Kriz d179601d9c Disable signing. 2017-11-14 17:13:24 +01:00
Tadeas Kriz 0ecde3fdcd Remove workspace and improve project setup. 2017-11-14 17:03:12 +01:00
Tadeas Kriz eb1992abdb Add Array and Set equalTo functions when Element is Equatable. 2017-11-09 19:55:52 +01:00
Tadeas Kriz 3adcde2fc0 Fix warnings. 2017-11-09 16:05:28 +01:00
Ian Keen 96ebbbf9ca Fix nondeterministic handling of input files 2017-11-09 11:23:02 +01:00
Tadeas Kriz 2bf60e5dc1 Double the maximum of parameters for `call` and `callThrows`. 2017-10-17 15:25:11 +02:00
Tadeas Kriz 52dcdbf17f Fix #151. 2017-10-17 11:55:16 +02:00
Tadeas Kriz 01ee3fa05c Bump version. 2017-10-05 21:19:12 +02:00
KaosDG 75be1e38d7 Adjusted the logic for determining if a closure is implicitly escaping (optional closure)
Adjusted the nested Closure logic so that we can pass whether the parent method `throws`
Adjusted the Mock.swift.stencil to account for the above, and some cleanup
Added a few more test cases in TestedSubclass.swift for closures that throw, etc.
2017-10-02 19:40:03 +02:00
KaosDG 85da0d9fb1 added open/close nested closure filters for the withoutActuallyEscaping(…) portion.
cleaned up the mock stencil a little.
added a sample multi-closure method
2017-10-02 19:40:03 +02:00
KaosDG dec5e08c1e fixes some deprecation warnings, and another attempt at writing good closures. 2017-10-02 19:40:03 +02:00
KaosDG 4ca15ff61d working on the generated mocks.
Closures are a problem :(
2017-10-02 19:40:03 +02:00
KaosDG 1bdc14698c Updating .travis.yml for XCode 9 2017-10-02 19:40:03 +02:00
KaosDG 725e30ef3f Updating Cuckoo for Swift 4.0
- Created new swift 4 Package, and updated to latest API.
- Updated package dependencies.  Note: FileKit points to /develop branch, this should be updated once a Sweift 4 version is released.
- Required code changes to build in Swift-4.0
2017-10-02 19:40:03 +02:00
Tadeas Kriz d9b2614d2b Update template. 2017-04-27 16:26:52 +02:00
Tadeas Kriz cfe0b0189d Fix #103. 2017-04-27 15:45:33 +02:00
Tadeas Kriz 12e8cdcc8b Fix #118. 2017-04-27 15:36:26 +02:00
Tadeas Kriz 9c09ea19d8 Fix crash when using non-ASCII characters. 2017-04-27 14:46:58 +02:00
Arjan Duijzer 8d09211853 Add option to exclude classes and/or protocols from mock generation 2017-04-25 23:13:04 +02:00
Arjan Duijzer e2e7928018 Typo oprional -> optional 2017-04-25 22:46:01 +02:00
Tadeas Kriz dc5610dca9 Bump version. 2017-04-25 18:06:26 +02:00
Tadeas Kriz 25c061a489 Fix build timeouting. 2017-04-25 18:02:57 +02:00
Christian Oberdörfer 0a9a8a3b9d Fixed directory names for case sensitive file systems 2017-04-25 18:02:39 +02:00
Tadeas Kriz 129ba1b9d5 Bump version. 2017-04-19 23:04:22 +02:00
271 changed files with 16310 additions and 5496 deletions

108
.fastlane/Fastfile Normal file
View File

@ -0,0 +1,108 @@
fastlane_version '2.54.1'
default_platform :mac
fastlane_require 'json'
platform :mac do
before_all do
ensure_git_status_clean
ensure_git_branch
end
desc 'Releases build specified by user.'
lane :release do
release_type = UI.select('Select release type: ', %w[major minor patch])
upload_release release_type
end
desc 'Releases major build. (+1).0.0'
lane :major do # fastlane major
upload_release 'major'
end
desc 'Releases minor build. X.(+1).0'
lane :minor do # fastlane minor
upload_release 'minor'
end
desc 'Releases patch build. X.X.(+1)'
lane :patch do # fastlane patch
upload_release 'patch'
end
def upload_release release_type
# Building Cuckoo Generator
sh('../build_generator')
# Settings
binary_name = 'cuckoo_generator'
cuckoo_gen_path = "../Generator/bin/#{binary_name}"
# GitHub username
username_var_name = 'GITHUB_USERNAME'
username = ENV[username_var_name]
# Personal Access Token
token_var_name = 'RELEASE_ACCESS_TOKEN'
access_token = ENV[token_var_name]
# Error Raisins
unless access_token
access_token = UI.input "Please type in your GitHub access token or cancel the release and define enviroment variable \"#{token_var_name}\" with the personal access token to use."
end
unless username
username = UI.input "Please type in your GitHub username or cancel the release and define enviroment variable \"#{username_var_name}\" with your GitHub username."
end
# URL variables
repo_path = 'Brightify/Cuckoo'
base_url = "github.com/repos/#{repo_path}/releases"
api_url = "https://api.#{base_url}"
auth_string = "#{username}:#{access_token}"
changelog = create_changelog.gsub(/`/, '``').gsub(/'/, '&#39;').gsub(/"/, '&#34;').gsub(/\n/, '\\n')
version = version_bump_podspec(path: 'Cuckoo.podspec', bump_type: release_type)
# Make sure the changed podspec is valid.
pod_lib_lint(allow_warnings: true)
git_commit(path: './Cuckoo.podspec', message: "Bump version.")
add_git_tag(tag: version)
push_to_git_remote
# https://developer.github.com/v3/repos/releases/#create-a-release
release_title = "#{version}"
release_body = "#{changelog}"
creation_body = "'{\"tag_name\":\"#{version}\",\"target_commitish\":\"master\", \"name\":\"#{release_title}\", \"body\":\"#{release_body}\", \"draft\":false, \"prerelease\":false}'"
creation_response = JSON.parse(`curl -X POST -d #{creation_body} -u #{auth_string} #{api_url} -v`)
UI.crash! 'Release draft creation failed!' unless creation_response
upload_url = (creation_response['upload_url']).sub(/{.*name.*}/, '')
# https://developer.github.com/v3/repos/releases/#upload-a-release-asset
upload_response = JSON.parse(`curl -X POST --data-binary "@#{cuckoo_gen_path}" -u "#{auth_string}" "#{upload_url}?name=#{binary_name}" -H "Content-Type:application/octet-stream"`)
UI.crash! 'Release draft upload failed!' unless upload_response
pod_push(path: 'Cuckoo.podspec', allow_warnings: true)
UI.success "All done!\nYou can now visit #{creation_response['url']} (command+click) and release the thing."
end
def create_changelog
changelog = changelog_from_git_commits(pretty: "- %s", merge_commit_filtering: "exclude_merges")
if changelog
changelog.gsub(/.(?<=[^|\n]).*[B|b]ump.*\n?/, '')
else
'No new changes, sorry!'
end
end
after_all do
reset_git_repo(disregard_gitignore: false)
end
error do |_, exception|
reset_git_repo(disregard_gitignore: false)
UI.error "Release failed. This might help: #{exception}"
end
end

31
.gitignore vendored
View File

@ -1,5 +1,4 @@
# Xcode
#
.build/
build/
*.pbxuser
@ -19,25 +18,33 @@ DerivedData
*.xcuserstate
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
# Pods/
Pods
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
.DS_Store
default.profraw
Tests/Generated/*.swift
Tests/**/Generated/*.swift
Generator/*.app
# AppCode
.idea/
cuckoo_generator
.fastlane
Generator/CuckooGenerator.xcodeproj
Cuckoo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
Cuckoo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
Cuckoo.xcworkspace
Cuckoo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
Tuist/Dependencies/graph.json
Tuist/Dependencies/Carthage
Tuist/Dependencies/SwiftPackageManager
Tuist/Dependencies/Cocoapods
Generator/Generator.xcodeproj
Generator/GeneratedMocks.swift

104
.package.resolved Normal file
View File

@ -0,0 +1,104 @@
{
"pins" : [
{
"identity" : "commandant",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Carthage/Commandant.git",
"state" : {
"revision" : "07cad52573bad19d95844035bf0b25acddf6b0f6",
"version" : "0.15.0"
}
},
{
"identity" : "filekit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/nvzqz/FileKit.git",
"state" : {
"branch" : "develop",
"revision" : "6937ec38b0c383b0505caeea6603e62086bf5431"
}
},
{
"identity" : "nimble",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Quick/Nimble.git",
"state" : {
"revision" : "e9d769113660769a4d9dd3afb855562c0b7ae7b0",
"version" : "7.3.4"
}
},
{
"identity" : "pathkit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kylef/PathKit.git",
"state" : {
"revision" : "3bfd2737b700b9a36565a8c94f4ad2b050a5e574",
"version" : "1.0.1"
}
},
{
"identity" : "quick",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Quick/Quick.git",
"state" : {
"revision" : "f2b5a06440ea87eba1a167cab37bf6496646c52e",
"version" : "1.3.4"
}
},
{
"identity" : "result",
"kind" : "remoteSourceControl",
"location" : "https://github.com/antitypical/Result.git",
"state" : {
"revision" : "2ca499ba456795616fbc471561ff1d963e6ae160",
"version" : "4.1.0"
}
},
{
"identity" : "sourcekitten",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/SourceKitten.git",
"state" : {
"revision" : "79ca340f609adee48defa966e6a3dd0e0acbeb08",
"version" : "0.21.3"
}
},
{
"identity" : "spectre",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kylef/Spectre.git",
"state" : {
"revision" : "26cc5e9ae0947092c7139ef7ba612e34646086c7",
"version" : "0.10.1"
}
},
{
"identity" : "stencil",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kylef/Stencil.git",
"state" : {
"revision" : "ccd9402682f4c07dac9561befd207c8156e80e20",
"version" : "0.14.2"
}
},
{
"identity" : "swxmlhash",
"kind" : "remoteSourceControl",
"location" : "https://github.com/drmohundro/SWXMLHash.git",
"state" : {
"revision" : "f43166a8e18fdd0857f29e303b1bb79a5428bca0",
"version" : "4.9.0"
}
},
{
"identity" : "yams",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams.git",
"state" : {
"revision" : "b08dba4bcea978bf1ad37703a384097d3efce5af",
"version" : "1.0.2"
}
}
],
"version" : 2
}

View File

@ -1 +0,0 @@
3.0

View File

@ -1,19 +1,15 @@
language: objective-c
osx_image: xcode8.2
osx_image: xcode10.2
xcode_project: Cuckoo.xcodeproj
xcode_scheme: Cuckoo
xcode_sdk: macosx
before_script:
- gem install cucumber --no-rdoc --no-ri
- gem install aruba --no-rdoc --no-ri
- pod install --repo-update
script:
- cd Generator
- make test
- cd ..
- xcodebuild -workspace 'Cuckoo.xcworkspace' -scheme 'Cuckoo+Run' clean test
- pod lib lint
- xcodebuild -workspace 'Cuckoo.xcworkspace' -scheme 'Cuckoo+OCMock-macOS' clean test | xcpretty
- pod lib lint --allow-warnings
after_script:
- sleep 5

1
.tuist-version Normal file
View File

@ -0,0 +1 @@
3.11.0

View File

@ -1,50 +1,172 @@
# Changelog
## 0.8.4
## 1.4.1
- Sidestep `SourceKit`'s off-by-one bug when parsing generic parameter inheritance.
- Fix incorrect `where` clause parsing.
* Added support for inheritance mocking.
## 1.4.0
- Add tvOS targets and schemes.
- Integrate `tuist`, fixing Carthage issues.
- Fix type equality check to rule out whitespace inconsistencies.
## 1.3.2
- Fix `image not found` error for iOS 13 and beyond.
## 1.3.1
- **Swift Package Manager support**
- Added tvOS target (thanks @rodrigoff).
- Fixed accessibility to match enclosing container.
- Restructured README.
## 1.3.0
- Fix closure generation where explicit return type is required in `withoutActuallyEscaping` since swift 5.1 (XCode 11)
- Switch swift_version to 5.0 for Cocoapods
## 1.2.0
#### Features
- Objective-C mocking! Mock system classes/protocols as well as dynamic Swift classes. This is an optional subspec `Cuckoo/OCMock`.
- Convenience matchers for sequences and dictionaries. No need to use `equal(to:)` anymore, passing the `Array`/`Set`/`Dictionary` itself is enough from now on!
## 1.1.1
- Fix property, initializer, and function accessibility in public protocols.
## 1.1.0
#### Features:
- Add a simple type guesser based on assigned value.
#### Fixes:
- Fix accessibility problems.
## 1.0.6
- Fix a bug where adding a private name to a function made it generate twice and fail the compilation.
## 1.0.5
- Fix generic protocol generation and type erasure with multiple methods of same name.
- Fix a bug concerning empty public name methods with no private ones.
- Exit `run` script with error if it fails to get generator download URL.
## 1.0.4
- The `run` script doesn't use `realpath` command anymore because it's not available by default on Mac OS.
- Remove redundant stubbing of optional classes.
## 1.0.3
- Add support for optional read-only properties.
## 1.0.2
- Fix `where` clause that doesn't work in Swift 4.
- Fix some `run` script bugs.
## 1.0.1
- Fix `any()` not working anymore by itself with optional parameters in functions.
## 1.0.0
#### Features:
- **Generics** is now fully supported! This includes generic classes, protocols and methods.
- `Dictionary` matching out of the box.
- Better closure matching. Now allowing up to 7 parameter closures.
- `rethrows` functions now work properly.
- Allow non-optional values to be passed as matchers for `Optional`s just like in normal Swift code.
- Add support for inout method parameters.
#### Fixes:
- Update the `build_generator` script to work with Swift 5.
- Fix not being able to put `Optional` into functions accepting `Optional`s.
- Accessibility of variables and functions in `public` classes are now `public` as well.
## 0.13.0
- Updated for **Xcode 10.2** and **Swift 5**.
## 0.12.1
- Add class accessibility support.
- Add support for attributes (e.g. `@available`).
- Add support for subimport (e.g. `import struct UICat.Food`).
- Add `--clean` option to the run script to always build or download the generator (promptly forget to add its documentation to `README.md`).
- Ignore `final` classes (because we mock by inheritance).
- Smaller fixes and improvements in the whole project.
## 0.12.0
- Add first draft of a new Mock initialization DSL.
- Add `enableDefaultImplementation` to protocol `Mock`.
- Reintroduce support for pre-0.11.0 Cuckoo spies.
- Add **regular expression** `class` and `protocol` matching.
- Add **glob** switch that parses input paths as globs enabling for easier project scaling.
- Build generator by default. Download using `--download [VERSION]` option.
- Modify the `run` bash script to allow the user to build rather than download the `cuckoo_generator`.
- Add a debug flag that generates general info above methods when used.
- Fix escaping closure (crashing in Xcode 10).
## 0.11.0
- Added contribution guide.
- **BREAKING CHANGE**: Spies were reworked. They now use superclasses as their victims if enabled. Please see the Readme for more information.
- **BREAKING CHANGE**: Verification of properties' `get` is now a method you have to call, instead of a property. This change was made to remove the "unused result" warning. [bug #141](https://github.com/Brightify/Cuckoo/issues/141)
## 0.10.2
- Double the maximum parameters in `call` and `callThrows` methods. [bug #145](https://github.com/Brightify/Cuckoo/issues/145)
- Make the generator deterministic by sorting input files.
- [bug #157](https://github.com/Brightify/Cuckoo/issues/157)
- [PR #158 - kudos to IanKeen](https://github.com/Brightify/Cuckoo/pull/158)
- Add `equalTo` for `Array` and `Set` where `Element` is `Equatable`.
## 0.10.1
- Fixed some errors with getters [bug #151](https://github.com/Brightify/Cuckoo/issues/151)
## 0.10.0
- Updated for **Swift 4** (Xcode 9 GM)
## 0.9.2
- Fixed crash when source files were using non-ASCII characters - [bug #126](https://github.com/Brightify/Cuckoo/issues/126)
- Added `--exclude` parameter to explicitly exclude some types from mocking - [PR #112](https://github.com/Brightify/Cuckoo/pull/112) - (thanks to nxtstep for the feature)
- Fixed compile errors when generating stubs where inner types were returned - [bug #118](https://github.com/Brightify/Cuckoo/issues/118)
- Added possibility to reset multiple mocks with different types at once - [but #103](https://github.com/Brightify/Cuckoo/issues/103)
## 0.9.1
- Fixed "too complex to resolve in reasonable time" error in generator
- Fixed directory names for case sensitive file systems - [PR #114](https://github.com/Brightify/Cuckoo/pull/115) - (thanks to sundance2000 for the fix)
- Moved repository from `SwiftKit` to `Brightify` organization on GitHub.
## 0.9.0
- Rewritten Generator to use Stencil
- Use Swift PM for generator binary (results in faster builds)
- This release works with Swift 3.1
## 0.8.4
- Added support for inheritance mocking.
## 0.8.3
* Added support for `fileprivate` (thanks to lvdstam for implementation).
* Added support for default values (thanks to lvdstam for implementation).
* Fixed wrongly generated code where public class had internal members.
- Added support for `fileprivate` (thanks to lvdstam for implementation).
- Added support for default values (thanks to lvdstam for implementation).
- Fixed wrongly generated code where public class had internal members.
## 0.8.2
* Show error in generator in build log.
* Fixed crash of generator when instance variable type is not explicitly set.
* Fixed support of closures and unwrapped optionals.
- Show error in generator in build log.
- Fixed crash of generator when instance variable type is not explicitly set.
- Fixed support of closures and unwrapped optionals.
## 0.8.1
* Set "Reflection Metadata" to "None" to fix #72
- Set "Reflection Metadata" to "None" to fix #72
## 0.8.0
* Support for Swift 3
* Added --no-class-mocking parameter to generator
* Added Stub objects
- Support for **Swift 3**
- Added --no-class-mocking parameter to generator
- Added Stub objects
## 0.7.0
* Updated documentation
* Added more automated tests
* Added --file-prefix parameter to generator
* `and` and `or` methods can now be used with `Matchable` (literals)
* Using of custom `Matchable`, `ParameterMatcher` and `CallMatcher` is now easier
* Improved fail messages
* Merged generator and runtime repositories, making updating easier.
* Added support for named arguments in methods.
* Added support for classes with custom initializers.
* Changed usage of spies. Instead of `init(spyOn:)` use `init().spy(on:)`.
- Updated documentation
- Added more automated tests
- Added --file-prefix parameter to generator
- `and` and `or` methods can now be used with `Matchable` (literals)
- Using of custom `Matchable`, `ParameterMatcher` and `CallMatcher` is now easier
- Improved fail messages
- Merged generator and runtime repositories, making updating easier.
- Added support for named arguments in methods.
- Added support for classes with custom initializers.
- Changed usage of spies. Instead of `init(spyOn:)` use `init().spy(on:)`.
## 0.6.0
* Added release notes
* Added stub resetting
* Added `thenCallRealImplementation`
* Added argument capturing
* Added `verifyNoMoreInteractions`
* Added on going stubbing
* Added `thenDoNothing`
- Added release notes
- Added stub resetting
- Added `thenCallRealImplementation`
- Added argument capturing
- Added `verifyNoMoreInteractions`
- Added on going stubbing
- Added `thenDoNothing`

View File

@ -1,31 +1,54 @@
Pod::Spec.new do |s|
s.name = "Cuckoo"
s.version = "0.8.4"
s.version = "1.10.3"
s.summary = "Cuckoo - first boilerplate-free Swift mocking framework."
s.description = <<-DESC
Cuckoo is a mocking framework with an easy to use API (inspired by Mockito).
It generates mocks and some helper structures automatically to enable this functionality.
DESC
s.homepage = "https://github.com/SwiftKit/Cuckoo"
s.homepage = "https://github.com/Brightify/Cuckoo"
s.license = 'MIT'
s.author = { "Tadeas Kriz" => "tadeas@brightify.org", "Filip Dolnik" => "filip@brightify.org", "Adriaan (Arjan) Duijzer" => "arjan@nxtstep.nl" }
s.source = {
:git => "https://github.com/SwiftKit/Cuckoo.git",
:git => "https://github.com/Brightify/Cuckoo.git",
:tag => s.version.to_s
}
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.9'
s.ios.deployment_target = '9.0'
s.osx.deployment_target = '11.0'
#s.watchos.deployment_target = '2.0' # watchos does not include XCTest framework :(
s.tvos.deployment_target = '9.0'
s.source_files = ['Source/**/*.swift']
s.preserve_paths = ['Generator/**/*', 'run', 'build_generator']
generator_name = 'cuckoo_generator'
s.swift_version = '5.0'
s.preserve_paths = ['Generator/**/*', 'run', 'build_generator', generator_name]
s.prepare_command = <<-CMD
git submodule update --init --recursive
./build_generator
curl -Lo #{generator_name} https://github.com/Brightify/Cuckoo/releases/download/#{s.version}/#{generator_name}
chmod +x #{generator_name}
CMD
s.frameworks = 'XCTest', 'Foundation'
s.requires_arc = true
s.pod_target_xcconfig = { 'ENABLE_BITCODE' => 'NO', 'SWIFT_REFLECTION_METADATA_LEVEL' => 'none' }
s.pod_target_xcconfig = {
'ENABLE_BITCODE' => 'NO',
'SWIFT_REFLECTION_METADATA_LEVEL' => 'none',
'OTHER_LDFLAGS' => '$(inherited) -weak-lXCTestSwiftSupport',
}
s.default_subspec = 'Swift'
# When building for iOS versions 12 and lower in Xcode 11, a wild `image not found` appears.
# This is a workaround for that annoying error.
s.xcconfig = (8..12).map { |major| (0..5).map { |minor| [major, minor] } }.flatten(1).inject(Hash.new) do |hash, (major, minor)|
hash["LIBRARY_SEARCH_PATHS[sdk=iphoneos#{major}.#{minor}]"] = '$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift-$(SWIFT_VERSION)/$(PLATFORM_NAME)'
hash
end
s.subspec 'Swift' do |sub|
sub.source_files = 'Source/**/*.swift'
end
s.subspec 'OCMock' do |sub|
sub.source_files = 'OCMock/**/*.{h,m,swift}'
sub.dependency 'Cuckoo/Swift'
sub.dependency 'OCMock', '3.8.1'
end
end

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:/Users/TadeasKriz/Development/Sources/Mockery/Cuckoo.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,72 +0,0 @@
{
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "509FD5E949BB67AB92770169324D45AB1917F796",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"E111B14063EC98ABE518A93E1C4498F4167C2DEE" : 0,
"956D2B21DD155C49504BB67697A67F7C5351A353" : 0,
"D23C0CEAADB77074FDA4459000068A7940EB7AD0" : 0,
"64ACE19A884E8C30BC53E2E0CE86010ECED70B5A" : 0,
"FD7DA18210A2C280E9107E37D7344F243FEE5F75" : 0,
"EB2210CFD48672E403BED699D5D7F01B844069CF" : 0,
"E084C86B03F81D63323C9E7510697EA528A758C7" : 0,
"509FD5E949BB67AB92770169324D45AB1917F796" : 0
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "4F02CBB0-D238-438F-87C7-CFA61AC3F0B4",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"E111B14063EC98ABE518A93E1C4498F4167C2DEE" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/YamlSwift\/",
"956D2B21DD155C49504BB67697A67F7C5351A353" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/Commandant\/Carthage\/Checkouts\/Result\/",
"D23C0CEAADB77074FDA4459000068A7940EB7AD0" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/Commandant\/",
"64ACE19A884E8C30BC53E2E0CE86010ECED70B5A" : "Cuckoo\/Generator\/Dependencies\/FileKit\/",
"FD7DA18210A2C280E9107E37D7344F243FEE5F75" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/",
"EB2210CFD48672E403BED699D5D7F01B844069CF" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/SWXMLHash\/",
"E084C86B03F81D63323C9E7510697EA528A758C7" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/Commandant\/Carthage\/Checkouts\/xcconfigs\/",
"509FD5E949BB67AB92770169324D45AB1917F796" : "Cuckoo\/"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "Cuckoo",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Cuckoo.xcodeproj",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/SwiftKit\/Cuckoo.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "509FD5E949BB67AB92770169324D45AB1917F796"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/nvzqz\/FileKit",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "64ACE19A884E8C30BC53E2E0CE86010ECED70B5A"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/antitypical\/Result.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "956D2B21DD155C49504BB67697A67F7C5351A353"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Carthage\/Commandant.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "D23C0CEAADB77074FDA4459000068A7940EB7AD0"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/jspahrsummers\/xcconfigs.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "E084C86B03F81D63323C9E7510697EA528A758C7"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/behrang\/YamlSwift.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "E111B14063EC98ABE518A93E1C4498F4167C2DEE"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/drmohundro\/SWXMLHash.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "EB2210CFD48672E403BED699D5D7F01B844069CF"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/jpsim\/SourceKitten",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "FD7DA18210A2C280E9107E37D7344F243FEE5F75"
}
]
}

View File

@ -1,25 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
version = "1.7">
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "NO"
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1808B15F1C4575AA0036E924"
BuildableName = "cuckoo_generator.app"
BlueprintName = "CuckooGenerator"
ReferencedContainer = "container:Generator/CuckooGenerator.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
@ -28,47 +14,31 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "183D03FA1C4691C600EBAEF3"
BlueprintIdentifier = "6A8F12C3A778933132EBA10D"
BuildableName = "Cuckoo.framework"
BlueprintName = "Cuckoo"
BlueprintName = "Cuckoo-iOS"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "TestWithRun"
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "183D04041C4691C600EBAEF3"
BuildableName = "CuckooTests.xctest"
BlueprintName = "CuckooTests"
BlueprintIdentifier = "92C74015545203C1F4395DD4"
BuildableName = "Cuckoo_iOSTests.xctest"
BlueprintName = "Cuckoo-iOSTests"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
<LocationScenarioReference
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
referenceType = "1">
</LocationScenarioReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "183D03FA1C4691C600EBAEF3"
BuildableName = "Cuckoo.framework"
BlueprintName = "Cuckoo"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -83,14 +53,12 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "183D03FA1C4691C600EBAEF3"
BlueprintIdentifier = "6A8F12C3A778933132EBA10D"
BuildableName = "Cuckoo.framework"
BlueprintName = "Cuckoo"
BlueprintName = "Cuckoo-iOS"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@ -101,9 +69,9 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "183D03FA1C4691C600EBAEF3"
BlueprintIdentifier = "6A8F12C3A778933132EBA10D"
BuildableName = "Cuckoo.framework"
BlueprintName = "Cuckoo"
BlueprintName = "Cuckoo-iOS"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</MacroExpansion>

View File

@ -1,39 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
version = "1.7">
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "NO"
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OBJ_459"
BuildableName = "TemplateEncoder"
BlueprintName = "TemplateEncoder"
ReferencedContainer = "container:Generator/CuckooGenerator.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OBJ_427"
BuildableName = "cuckoo_generator"
BlueprintName = "cuckoo_generator"
ReferencedContainer = "container:Generator/CuckooGenerator.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
@ -42,9 +14,9 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "183D03FA1C4691C600EBAEF3"
BlueprintIdentifier = "1DC56D8212E4351521A57BD1"
BuildableName = "Cuckoo.framework"
BlueprintName = "Cuckoo"
BlueprintName = "Cuckoo-macOS"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@ -54,35 +26,19 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "183D04041C4691C600EBAEF3"
BuildableName = "CuckooTests.xctest"
BlueprintName = "CuckooTests"
BlueprintIdentifier = "DBDB2DD4E7BE487EEB257CC8"
BuildableName = "Cuckoo_macOSTests.xctest"
BlueprintName = "Cuckoo-macOSTests"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
<LocationScenarioReference
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
referenceType = "1">
</LocationScenarioReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "183D03FA1C4691C600EBAEF3"
BuildableName = "Cuckoo.framework"
BlueprintName = "Cuckoo"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -97,14 +53,12 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "183D03FA1C4691C600EBAEF3"
BlueprintIdentifier = "1DC56D8212E4351521A57BD1"
BuildableName = "Cuckoo.framework"
BlueprintName = "Cuckoo"
BlueprintName = "Cuckoo-macOS"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@ -115,9 +69,9 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "183D03FA1C4691C600EBAEF3"
BlueprintIdentifier = "1DC56D8212E4351521A57BD1"
BuildableName = "Cuckoo.framework"
BlueprintName = "Cuckoo"
BlueprintName = "Cuckoo-macOS"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</MacroExpansion>

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "AC1E5664C17BDCFB45CF1DF4"
BuildableName = "Cuckoo.framework"
BlueprintName = "Cuckoo-tvOS"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6AD4A9670FA783A1EC213000"
BuildableName = "Cuckoo_tvOSTests.xctest"
BlueprintName = "Cuckoo-tvOSTests"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "AC1E5664C17BDCFB45CF1DF4"
BuildableName = "Cuckoo.framework"
BlueprintName = "Cuckoo-tvOS"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "AC1E5664C17BDCFB45CF1DF4"
BuildableName = "Cuckoo.framework"
BlueprintName = "Cuckoo-tvOS"
ReferencedContainer = "container:Cuckoo.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Cuckoo.xcodeproj">
</FileRef>
<FileRef
location = "group:Generator/CuckooGenerator.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,100 +0,0 @@
{
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "509FD5E949BB67AB92770169324D45AB1917F796",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"1B9E61546D4F9511D800AE955CDC56CD3D276E5C" : 9223372036854775807,
"D23C0CEAADB77074FDA4459000068A7940EB7AD0" : 0,
"E084C86B03F81D63323C9E7510697EA528A758C7" : 0,
"E3472B155FC961329A2EA7BFAD3AFAE6EFBD63E5" : 9223372036854775807,
"E111B14063EC98ABE518A93E1C4498F4167C2DEE" : 0,
"64ACE19A884E8C30BC53E2E0CE86010ECED70B5A" : 0,
"95438028B10BBB846574013D29F154A00556A9D1" : 9223372036854775807,
"EB2210CFD48672E403BED699D5D7F01B844069CF" : 0,
"D0725CAC6FF2D66F2C83C2C48DC12106D42DAA64" : 9223372036854775807,
"FD7DA18210A2C280E9107E37D7344F243FEE5F75" : 0,
"956D2B21DD155C49504BB67697A67F7C5351A353" : 0,
"509FD5E949BB67AB92770169324D45AB1917F796" : 0
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "AA22B945-78BB-4BFD-8BCA-01658017BF31",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"1B9E61546D4F9511D800AE955CDC56CD3D276E5C" : "Cuckoo\/Generator\/Packages\/Yams-0.1.4\/",
"D23C0CEAADB77074FDA4459000068A7940EB7AD0" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/Commandant\/",
"E084C86B03F81D63323C9E7510697EA528A758C7" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/xcconfigs\/",
"E3472B155FC961329A2EA7BFAD3AFAE6EFBD63E5" : "Cuckoo\/Generator\/Packages\/PathKit-0.8.0\/",
"E111B14063EC98ABE518A93E1C4498F4167C2DEE" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/YamlSwift\/",
"64ACE19A884E8C30BC53E2E0CE86010ECED70B5A" : "Cuckoo\/Generator\/Dependencies\/FileKit\/",
"95438028B10BBB846574013D29F154A00556A9D1" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/Commandant\/Carthage\/Checkouts\/Quick\/Externals\/Nimble\/",
"EB2210CFD48672E403BED699D5D7F01B844069CF" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/SWXMLHash\/",
"D0725CAC6FF2D66F2C83C2C48DC12106D42DAA64" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/Commandant\/Carthage\/Checkouts\/Quick\/",
"FD7DA18210A2C280E9107E37D7344F243FEE5F75" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/",
"956D2B21DD155C49504BB67697A67F7C5351A353" : "Cuckoo\/Generator\/Dependencies\/SourceKitten\/Carthage\/Checkouts\/Commandant\/Carthage\/Checkouts\/Result\/",
"509FD5E949BB67AB92770169324D45AB1917F796" : "Cuckoo\/"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "Cuckoo",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Cuckoo.xcworkspace",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/jpsim\/Yams.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "1B9E61546D4F9511D800AE955CDC56CD3D276E5C"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/SwiftKit\/Cuckoo.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "509FD5E949BB67AB92770169324D45AB1917F796"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/nvzqz\/FileKit",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "64ACE19A884E8C30BC53E2E0CE86010ECED70B5A"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Quick\/Nimble.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "95438028B10BBB846574013D29F154A00556A9D1"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/antitypical\/Result.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "956D2B21DD155C49504BB67697A67F7C5351A353"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Quick\/Quick.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "D0725CAC6FF2D66F2C83C2C48DC12106D42DAA64"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Carthage\/Commandant.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "D23C0CEAADB77074FDA4459000068A7940EB7AD0"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/jspahrsummers\/xcconfigs.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "E084C86B03F81D63323C9E7510697EA528A758C7"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/behrang\/YamlSwift.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "E111B14063EC98ABE518A93E1C4498F4167C2DEE"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/kylef\/PathKit.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "E3472B155FC961329A2EA7BFAD3AFAE6EFBD63E5"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/drmohundro\/SWXMLHash.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "EB2210CFD48672E403BED699D5D7F01B844069CF"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/jpsim\/SourceKitten",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "FD7DA18210A2C280E9107E37D7344F243FEE5F75"
}
]
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@ -15,14 +15,10 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.8.4</string>
<key>CFBundleSignature</key>
<string>????</string>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<string>1</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Brightify. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
<string>Copyright ©. All rights reserved.</string>
</dict>
</plist>

View File

@ -3,11 +3,9 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
@ -15,18 +13,12 @@
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>0.8.4</string>
<key>CFBundleSignature</key>
<string>????</string>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Brightify. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<string>Copyright ©. All rights reserved.</string>
</dict>
</plist>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright ©. All rights reserved.</string>
</dict>
</plist>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright ©. All rights reserved.</string>
</dict>
</plist>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

6
Gemfile Normal file
View File

@ -0,0 +1,6 @@
# frozen_string_literal: true
source "https://rubygems.org"
gem 'json'
gem 'fastlane'
gem 'cocoapods'

285
Gemfile.lock Normal file
View File

@ -0,0 +1,285 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.5)
rexml
activesupport (6.1.4.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.600.0)
aws-sdk-core (3.131.2)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.57.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.114.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
cocoapods (1.11.2)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.11.2)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.4.0, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.4.0, < 2.0)
cocoapods-try (>= 1.1.0, < 2.0)
colored2 (~> 3.1)
escape (~> 0.0.4)
fourflusher (>= 2.3.0, < 3.0)
gh_inspector (~> 1.0)
molinillo (~> 0.8.0)
nap (~> 1.0)
ruby-macho (>= 1.0, < 3.0)
xcodeproj (>= 1.21.0, < 2.0)
cocoapods-core (1.11.2)
activesupport (>= 5.0, < 7)
addressable (~> 2.8)
algoliasearch (~> 1.0)
concurrent-ruby (~> 1.1)
fuzzy_match (~> 2.0.4)
nap (~> 1.0)
netrc (~> 0.11)
public_suffix (~> 4.0)
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5)
cocoapods-downloader (1.5.1)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.1)
cocoapods-trunk (1.6.0)
nap (>= 0.8, < 2.0)
netrc (~> 0.11)
cocoapods-try (1.2.0)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
concurrent-ruby (1.1.9)
declarative (0.0.20)
digest-crc (0.6.4)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
emoji_regex (3.2.3)
escape (0.0.4)
ethon (0.15.0)
ffi (>= 1.15.0)
excon (0.92.3)
faraday (1.10.0)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.206.2)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
colored
commander (~> 4.6)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
excon (>= 0.71.0, < 1.0.0)
faraday (~> 1.0)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 1.0)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (~> 2.0.0)
naturally (~> 2.2)
optparse (~> 0.1.1)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.3)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
ffi (1.15.4)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.22.0)
google-apis-core (>= 0.5, < 2.a)
google-apis-core (0.6.0)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.12.0)
google-apis-core (>= 0.6, < 2.a)
google-apis-playcustomapp_v1 (0.9.0)
google-apis-core (>= 0.6, < 2.a)
google-apis-storage_v1 (0.15.0)
google-apis-core (>= 0.5, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.2.0)
google-cloud-storage (1.36.2)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.1)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.1.3)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
i18n (1.8.11)
concurrent-ruby (~> 1.0)
jmespath (1.6.1)
json (2.6.2)
jwt (2.4.1)
memoist (0.16.2)
mini_magick (4.11.0)
mini_mime (1.1.2)
minitest (5.14.4)
molinillo (0.8.0)
multi_json (1.15.0)
multipart-post (2.0.0)
nanaimo (0.3.0)
nap (1.1.0)
naturally (2.2.1)
netrc (0.11.0)
optparse (0.1.1)
os (1.1.4)
plist (3.6.0)
public_suffix (4.0.7)
rake (13.0.6)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.2.5)
rouge (2.0.7)
ruby-macho (2.5.1)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.16.1)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.0)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.8)
CFPropertyList
naturally
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.1)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
webrick (1.7.0)
word_wrap (1.0.0)
xcodeproj (1.21.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
rexml (~> 3.2.4)
xcpretty (0.3.0)
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
zeitwerk (2.5.1)
PLATFORMS
arm64-darwin-21
DEPENDENCIES
cocoapods
fastlane
json
BUNDLED WITH
2.2.32

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright ©. All rights reserved.</string>
</dict>
</plist>

View File

@ -1,7 +0,0 @@
{
"autoPin": true,
"pins": [
],
"version": 1
}

View File

@ -1,22 +0,0 @@
import PackageDescription
let package = Package(
name: "CuckooGenerator",
targets: [
Target(name: "TemplateEncoder"),
Target(name: "CuckooGeneratorFramework", dependencies: [
.Target(name: "TemplateEncoder")]),
Target(name: "cuckoo_generator", dependencies: [
.Target(name: "CuckooGeneratorFramework")]),
],
dependencies: [
.Package(url: "https://github.com/jpsim/SourceKitten.git", versions: Version(0, 15, 0)..<Version(0, 17, .max)),
.Package(url: "https://github.com/TadeasKriz/FileKit.git", Version(4, 0, 2)),
.Package(url: "https://github.com/kylef/Stencil.git", majorVersion: 0, minor: 8),
],
exclude: [
"Tests"
]
)

56
Generator/Project.swift Normal file
View File

@ -0,0 +1,56 @@
import ProjectDescription
import ProjectDescriptionHelpers
// MARK: project definition
let project = Project(
name: "Generator",
options: .options(automaticSchemesOptions: .disabled, disableSynthesizedResourceAccessors: true),
packages: [
.package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.21.2")),
.package(url: "https://github.com/nvzqz/FileKit.git", .branch("develop")),
.package(url: "https://github.com/kylef/Stencil.git", .exact("0.14.2")),
.package(url: "https://github.com/Carthage/Commandant.git", .exact("0.15.0")),
],
targets: [
Target(
name: "CuckooGenerator",
platform: .macOS,
product: .commandLineTool,
productName: "cuckoo_generator",
bundleId: "CuckooGenerator",
deploymentTarget: DeploymentTarget.macOS(targetVersion: "10.13"),
sources: "Source/**",
dependencies: ["FileKit", "SourceKittenFramework", "Stencil", "Commandant"].map(TargetDependency.package(product:))
),
],
schemes: [
Scheme(
name: "Generator",
buildAction: BuildAction.buildAction(
targets: ["CuckooGenerator"],
postActions: [
ExecutionAction(
title: "Copy executable",
scriptText: #"\cp "$BUILT_PRODUCTS_DIR/$EXECUTABLE_NAME" "$PROJECT_DIR/bin/cuckoo_generator""#,
target: "CuckooGenerator"
)
],
runPostActionsOnFailure: false
),
runAction: RunAction.runAction(
executable: "CuckooGenerator",
arguments: Arguments(
launchArguments: [
// Any changes here should be reflected in `../Project.swift` as well.
LaunchArgument(name: "generate", isEnabled: true),
LaunchArgument(name: "--testable Cuckoo", isEnabled: true),
LaunchArgument(name: "--exclude ExcludedTestClass,ExcludedProtocol", isEnabled: true),
LaunchArgument(name: #"--output "$PROJECT_DIR"/GeneratedMocks.swift"#, isEnabled: true),
// This is the input file(s) glob.
LaunchArgument(name: #"--glob "$PROJECT_DIR"/../Tests/Swift/Source/*.swift"#, isEnabled: true),
]
)
)
),
]
)

View File

@ -1,11 +1,3 @@
//
// CuckooGeneratorError.swift
// CuckooGenerator
//
// Created by Tadeas Kriz on 13/01/16.
// Copyright © 2016 Brightify. All rights reserved.
//
import Foundation
import FileKit

View File

@ -0,0 +1,242 @@
import Foundation
import Commandant
import Result
import SourceKittenFramework
import FileKit
private func curry<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, R>
(_ f: @escaping (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) -> R)
-> (P1) -> (P2) -> (P3) -> (P4) -> (P5) -> (P6) -> (P7) -> (P8) -> (P9) -> (P10) -> (P11) -> (P12) -> R {
return { p1 in { p2 in { p3 in { p4 in { p5 in { p6 in { p7 in { p8 in { p9 in { p10 in { p11 in { p12 in
f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)
} } } } } } } } } } } }
}
public struct GenerateMocksCommand: CommandProtocol {
public let verb = "generate"
public let function = "Generates mock files"
public func run(_ options: Options) -> Result<Void, CuckooGeneratorError> {
let getFullPathSortedArray: ([String]) -> [String] = { stringArray in
Array(Set(stringArray.map { Path($0).standardRawValue })).sorted()
}
let inputPathValues: [String]
if options.globEnabled {
inputPathValues = getFullPathSortedArray(options.files.flatMap { Glob(pattern: $0).paths })
} else {
inputPathValues = getFullPathSortedArray(options.files)
}
let inputFiles = inputPathValues.map { File(path: $0) }.compactMap { $0 }
let tokens = inputFiles.map { Tokenizer(sourceFile: $0, debugMode: options.debugMode).tokenize() }
let tokensWithInheritance = options.noInheritance ? tokens : inheritNSObject(mergeInheritance(tokens))
// filter classes/protocols based on the settings passed to the generator
var typeFilters = [] as [(Token) -> Bool]
if options.noClassMocking {
typeFilters.append(ignoreClasses)
}
if !options.regex.isEmpty {
typeFilters.append(keepMatching(pattern: options.regex))
}
if !options.exclude.isEmpty {
typeFilters.append(ignoreIfExists(in: options.exclude))
}
let parsedFiles = removeTypes(from: tokensWithInheritance, using: typeFilters)
// generating headers and mocks
let headers = parsedFiles.map { options.noHeader ? "" : FileHeaderHandler.getHeader(of: $0, includeTimestamp: !options.noTimestamp) }
let imports = parsedFiles.map { FileHeaderHandler.getImports(of: $0, testableFrameworks: options.testableFrameworks) }
let mocks = parsedFiles.map { try! Generator(file: $0).generate(debug: options.debugMode) }
let mergedFiles = zip(zip(headers, imports), mocks).map { $0.0 + $0.1 + $1 }
let outputPath = Path(options.output)
do {
if outputPath.isDirectory {
let inputPaths = inputFiles.compactMap { $0.path }.map { Path($0) }
for (inputPath, outputText) in zip(inputPaths, mergedFiles) {
let fileName = options.filePrefix + inputPath.fileName
let outputFile = TextFile(path: outputPath + fileName)
try outputText |> outputFile
}
} else {
let outputFile = TextFile(path: outputPath)
try mergedFiles.joined(separator: "\n") |> outputFile
}
} catch let error as FileKitError {
return .failure(.ioError(error))
} catch let error {
return .failure(.unknownError(error))
}
return stderrUsed ? .failure(.stderrUsed) : .success(())
}
private func mergeInheritance(_ filesRepresentation: [FileRepresentation]) -> [FileRepresentation] {
return filesRepresentation.compactMap { $0.mergeInheritance(with: filesRepresentation) }
}
private func inheritNSObject(_ filesRepresentation: [FileRepresentation]) -> [FileRepresentation] {
func containsRecursively(name: String) -> Bool {
if let protocolDeclaration = protocolDeclarationDictionary[name] {
let collapsedInheritedTypesName = protocolDeclaration
.inheritedTypes
.map({ $0.name.components(separatedBy: "&") })
.joined()
.map({ $0.trimmingCharacters(in: .whitespaces) })
if collapsedInheritedTypesName.contains(where: { $0 == "NSObjectProtocol" }) {
return true
} else {
return protocolDeclaration.inheritedTypes.contains(where: { inheritanceType in
containsRecursively(name: inheritanceType.name)
})
}
} else {
return false
}
}
let protocolDeclarationDictionary: [String: ProtocolDeclaration] = Dictionary(
uniqueKeysWithValues: filesRepresentation.flatMap { file in
file.declarations.compactMap { token -> (name: String, protocolDeclaration: ProtocolDeclaration)? in
guard let protocolDeclaration = token as? ProtocolDeclaration else { return nil }
return (name: protocolDeclaration.name, protocolDeclaration: protocolDeclaration)
}
}
)
let nsObjectProtocols: [ProtocolDeclaration] = protocolDeclarationDictionary.values.reduce(into: []) { accumulator, protocolDeclaration in
guard containsRecursively(name: protocolDeclaration.name) else { return }
accumulator.append(protocolDeclaration)
}
return filesRepresentation.map { $0.inheritNSObject(subjects: nsObjectProtocols) }
}
private func removeTypes(from files: [FileRepresentation], using filters: [(Token) -> Bool]) -> [FileRepresentation] {
// Only keep those that pass all filters
let filter: (Token) -> Bool = { token in
!filters.contains { !$0(token) }
}
return files.compactMap { file in
let filteredDeclarations = file.declarations.filter(filter)
guard !filteredDeclarations.isEmpty else { return nil }
return FileRepresentation(sourceFile: file.sourceFile, declarations: filteredDeclarations)
}
}
// filter that keeps the protocols while removing all classes
private func ignoreClasses(token: Token) -> Bool {
return !(token is ClassDeclaration)
}
// filter that keeps the classes/protocols that match the passed regular expression
private func keepMatching(pattern: String) -> (Token) -> Bool {
do {
let regex = try NSRegularExpression(pattern: pattern, options: [])
return { token in
guard let containerToken = token as? ContainerToken else { return true }
return regex.firstMatch(in: containerToken.name, options: [], range: NSMakeRange(0, containerToken.name.count)) != nil
}
} catch {
fatalError("Invalid regular expression: " + (error as NSError).description)
}
}
// filter that keeps only the classes/protocols that are not supposed to be excluded
private func ignoreIfExists(in excluded: [String]) -> (Token) -> Bool {
let excludedSet = Set(excluded)
return { token in
guard let containerToken = token as? ContainerToken else { return true }
return !excludedSet.contains(containerToken.name)
}
}
public struct Options: OptionsProtocol {
let files: [String]
let output: String
let noHeader: Bool
let noTimestamp: Bool
let noInheritance: Bool
let testableFrameworks: [String]
let exclude: [String]
let filePrefix: String
let noClassMocking: Bool
let debugMode: Bool
let globEnabled: Bool
let regex: String
public init(
output: String,
testableFrameworks: String,
exclude: String,
noHeader: Bool,
noTimestamp: Bool,
noInheritance: Bool,
filePrefix: String,
noClassMocking: Bool,
debugMode: Bool,
globEnabled: Bool,
regex: String,
files: [String]
) {
self.output = output
self.testableFrameworks = testableFrameworks.components(separatedBy: ",").filter { !$0.isEmpty }
self.exclude = exclude.components(separatedBy: ",").filter { !$0.isEmpty }.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
self.noHeader = noHeader
self.noTimestamp = noTimestamp
self.noInheritance = noInheritance
self.filePrefix = filePrefix
self.noClassMocking = noClassMocking
self.debugMode = debugMode
self.globEnabled = globEnabled
self.regex = regex
self.files = files
}
// all options are declared here and then parsed by Commandant
public static func evaluate(_ m: CommandMode) -> Result<Options, CommandantError<CuckooGeneratorError>> {
let output: Result<String, CommandantError<ClientError>> = m <| Option(key: "output", defaultValue: "GeneratedMocks.swift", usage: "Where to put the generated mocks.\nIf a path to a directory is supplied, each input file will have a respective output file with mocks.\nIf a path to a Swift file is supplied, all mocks will be in a single file.\nDefault value is `GeneratedMocks.swift`.")
let testable: Result<String, CommandantError<ClientError>> = m <| Option(key: "testable", defaultValue: "", usage: "A comma separated list of frameworks that should be imported as @testable in the mock files.")
let exclude: Result<String, CommandantError<ClientError>> = m <| Option(key: "exclude", defaultValue: "", usage: "A comma separated list of classes and protocols that should be skipped during mock generation.")
let noHeader: Result<Bool, CommandantError<ClientError>> = m <| Option(key: "no-header", defaultValue: false, usage: "Do not generate file headers.")
let noTimestamp: Result<Bool, CommandantError<ClientError>> = m <| Option(key: "no-timestamp", defaultValue: false, usage: "Do not generate timestamp.")
let noInheritance: Result<Bool, CommandantError<ClientError>> = m <| Option(key: "no-inheritance", defaultValue: false, usage: "Do not generate stubs/mock for super class/protocol even if available.")
let filePrefix: Result<String, CommandantError<ClientError>> = m <| Option(key: "file-prefix", defaultValue: "", usage: "Names of generated files in directory will start with this prefix. Only works when output path is directory.")
let noClassMocking: Result<Bool, CommandantError<ClientError>> = m <| Option(key: "no-class-mocking", defaultValue: false, usage: "Do not generate mocks for classes.")
let debugMode: Result<Bool, CommandantError<ClientError>> = m <| Switch(flag: "d", key: "debug", usage: "Run generator in debug mode.")
let globEnabled: Result<Bool, CommandantError<ClientError>> = m <| Switch(flag: "g", key: "glob", usage: "Use glob for specifying input paths.")
let regex: Result<String, CommandantError<ClientError>> = m <| Option(key: "regex", defaultValue: "", usage: "A regular expression pattern that is used to match Classes and Protocols.\nAll that do not match are excluded.\nCan be used alongside `--exclude`.")
let input: Result<[String], CommandantError<ClientError>> = m <| Argument(usage: "Files to parse and generate mocks for.")
return curry(Options.init)
<*> output
<*> testable
<*> exclude
<*> noHeader
<*> noTimestamp
<*> noInheritance
<*> filePrefix
<*> noClassMocking
<*> debugMode
<*> globEnabled
<*> regex
<*> input
}
}
}

View File

@ -0,0 +1,178 @@
import Foundation
// Adapted from https://gist.github.com/blakemerryman/76312e1cbf8aec248167
/**
Finds files on the file system using pattern matching.
*/
class Glob: Collection {
/**
* Different glob implementations have different behaviors, so the behavior of this
* implementation is customizable.
*/
struct Behavior {
// If true then a globstar ("**") causes matching to be done recursively in subdirectories.
// If false then "**" is treated the same as "*"
let supportsGlobstar: Bool
// If true the results from the directory where the globstar is declared will be included as well.
// For example, with the pattern "dir/**/*.ext" the fie "dir/file.ext" would be included if this
// property is true, and would be omitted if it's false.
let includesFilesFromRootOfGlobstar: Bool
// If false then the results will not include directory entries. This does not affect recursion depth.
let includesDirectoriesInResults: Bool
// If false and the last characters of the pattern are "**/" then only directories are returned in the results.
let includesFilesInResultsIfTrailingSlash: Bool
}
static var defaultBehavior = Glob.Behavior(
supportsGlobstar: true,
includesFilesFromRootOfGlobstar: true,
includesDirectoriesInResults: false,
includesFilesInResultsIfTrailingSlash: false
)
private var isDirectoryCache = [String: Bool]()
let behavior: Behavior
var paths = [String]()
var startIndex: Int { return paths.startIndex }
var endIndex: Int { return paths.endIndex }
init(pattern: String, behavior: Behavior = Glob.defaultBehavior) {
self.behavior = behavior
var adjustedPattern = pattern
let hasTrailingGlobstarSlash = pattern.hasSuffix("**/")
var includeFiles = !hasTrailingGlobstarSlash
if behavior.includesFilesInResultsIfTrailingSlash {
includeFiles = true
if hasTrailingGlobstarSlash {
// Grab the files too.
adjustedPattern += "*"
}
}
let patterns = behavior.supportsGlobstar ? expandGlobstar(pattern: adjustedPattern) : [adjustedPattern]
for pattern in patterns {
var gt = glob_t()
if executeGlob(pattern: pattern, gt: &gt) {
populateFiles(gt: gt, includeFiles: includeFiles)
}
globfree(&gt)
}
paths = Array(Set(paths)).sorted { lhs, rhs in
lhs.compare(rhs) != ComparisonResult.orderedDescending
}
clearCaches()
}
// MARK: Private
private var globalFlags = GLOB_TILDE | GLOB_BRACE | GLOB_MARK
private func executeGlob(pattern: UnsafePointer<CChar>, gt: UnsafeMutablePointer<glob_t>) -> Bool {
return 0 == glob(pattern, globalFlags, nil, gt)
}
private func expandGlobstar(pattern: String) -> [String] {
guard pattern.contains("**") else {
return [pattern]
}
var results = [String]()
var parts = pattern.components(separatedBy: "**")
let firstPart = parts.removeFirst()
var lastPart = parts.joined(separator: "**")
let fileManager = FileManager.default
var directories: [String]
do {
directories = try fileManager.subpathsOfDirectory(atPath: firstPart).compactMap { subpath in
let fullPath = NSString(string: firstPart).appendingPathComponent(subpath)
var isDirectory = ObjCBool(false)
if fileManager.fileExists(atPath: fullPath, isDirectory: &isDirectory) && isDirectory.boolValue {
return fullPath
} else {
return nil
}
}
} catch {
directories = []
print("Error parsing file system item: \(error)")
}
if behavior.includesFilesFromRootOfGlobstar {
// Check the base directory for the glob star as well.
directories.insert(firstPart, at: 0)
// Include the globstar root directory ("dir/") in a pattern like "dir/**" or "dir/**/"
if lastPart.isEmpty {
results.append(firstPart)
}
}
if lastPart.isEmpty {
lastPart = "*"
}
for directory in directories {
let partiallyResolvedPattern = NSString(string: directory).appendingPathComponent(lastPart)
results.append(contentsOf: expandGlobstar(pattern: partiallyResolvedPattern))
}
return results
}
private func isDirectory(path: String) -> Bool {
var isDirectory = isDirectoryCache[path]
if let isDirectory = isDirectory {
return isDirectory
}
var isDirectoryBool = ObjCBool(false)
isDirectory = FileManager.default.fileExists(atPath: path, isDirectory: &isDirectoryBool) && isDirectoryBool.boolValue
isDirectoryCache[path] = isDirectory!
return isDirectory!
}
private func clearCaches() {
isDirectoryCache.removeAll()
}
private func populateFiles(gt: glob_t, includeFiles: Bool) {
let includeDirectories = behavior.includesDirectoriesInResults
for i in 0..<Int(gt.gl_matchc) {
if let path = String(validatingUTF8: gt.gl_pathv[i]!) {
if !includeFiles || !includeDirectories {
let isDirectory = self.isDirectory(path: path)
if (!includeFiles && !isDirectory) || (!includeDirectories && isDirectory) {
continue
}
}
paths.append(path)
}
}
}
// MARK: Subscript Support
subscript(i: Int) -> String {
return paths[i]
}
func index(after i: Int) -> Int {
return i + 1
}
}

View File

@ -1,11 +1,3 @@
//
// VersionCommand.swift
// CuckooGenerator
//
// Created by Tadeas Kriz on 17/01/16.
// Copyright © 2016 Brightify. All rights reserved.
//
import Foundation
import Commandant
import Result
@ -21,7 +13,7 @@ public struct VersionCommand: CommandProtocol {
public func run(_ options: Options) -> Result<Void, CuckooGeneratorError> {
print(VersionCommand.appVersion)
return .success()
return .success(())
}
public struct Options: OptionsProtocol {

View File

@ -1,12 +1,3 @@
//#!/usr/bin/swift -F Carthage/Build/Mac
//
// main.swift
// SwiftMockGenerator
//
// Created by Tadeas Kriz on 12/01/16.
// Copyright © 2016 Brightify. All rights reserved.
//
import Foundation
import Commandant

View File

@ -1,36 +0,0 @@
//
// CodeBuilder.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 06.07.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public class CodeBuilder {
fileprivate static let Tab = " "
public fileprivate(set) var code = ""
fileprivate var nesting = 0
public func clear() {
code = ""
}
public func nest(_ closure: () -> ()) {
nesting += 1
closure()
nesting -= 1
}
public func nest(_ line: String) {
nest { self += line }
}
}
public func +=(left: CodeBuilder, right: String) {
(0..<left.nesting).forEach { _ in left.code += CodeBuilder.Tab }
left.code += right
left.code += "\n"
}

View File

@ -1,90 +0,0 @@
//
// Generator.swift
// CuckooGenerator
//
// Created by Tadeas Kriz on 13/01/16.
// Copyright © 2016 Brightify. All rights reserved.
//
import Foundation
import Stencil
public struct Generator {
private let declarations: [Token]
private let code = CodeBuilder()
public init(file: FileRepresentation) {
declarations = file.declarations
}
public func generate() -> String {
code.clear()
let ext = Extension()
ext.registerFilter("genericSafe") { (value: Any?) in
guard let string = value as? String else { return value }
return self.genericSafeType(from: string)
}
ext.registerFilter("matchableGenericNames") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return self.matchableGenerics(with: parameters)
}
ext.registerFilter("matchableGenericWhere") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return self.matchableGenerics(where: parameters)
}
ext.registerFilter("matchableParameterSignature") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return self.matchableParameterSignature(with: parameters)
}
ext.registerFilter("parameterMatchers") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return self.parameterMatchers(for: parameters)
}
let environment = Environment(loader: InternalLoader(), extensions: [ext])
let containers = declarations.flatMap { $0 as? ContainerToken }
.filter { $0.accessibility.isAccessible }
.map { $0.serializeWithType() }
return try! environment.renderTemplate(name: "Mock.swift.stencil", context: ["containers": containers])
}
private func matchableGenerics(with parameters: [MethodParameter]) -> String {
guard parameters.isEmpty == false else { return "" }
let genericParameters = (1...parameters.count).map { "M\($0): Cuckoo.Matchable" }.joined(separator: ", ")
return "<\(genericParameters)>"
}
private func matchableGenerics(where parameters: [MethodParameter]) -> String {
guard parameters.isEmpty == false else { return "" }
let whereClause = parameters.enumerated().map { "M\($0 + 1).MatchedType == \(genericSafeType(from: $1.typeWithoutAttributes))" }.joined(separator: ", ")
return " where \(whereClause)"
}
private func matchableParameterSignature(with parameters: [MethodParameter]) -> String {
guard parameters.isEmpty == false else { return "" }
return parameters.enumerated().map { "\($1.labelAndName): M\($0 + 1)" }.joined(separator: ", ")
}
private func parameterMatchers(for parameters: [MethodParameter]) -> String {
guard parameters.isEmpty == false else { return "let matchers: [Cuckoo.ParameterMatcher<Void>] = []" }
let tupleType = parameters.map { $0.typeWithoutAttributes }.joined(separator: ", ")
let matchers = parameters.enumerated().map { "wrap(matchable: \($1.name)) { $0\(parameters.count > 1 ? ".\($0)" : "") }" }.joined(separator: ", ")
return "let matchers: [Cuckoo.ParameterMatcher<(\(genericSafeType(from: tupleType)))>] = [\(matchers)]"
}
private func genericSafeType(from type: String) -> String {
return type.replacingOccurrences(of: "!", with: "?")
}
}

View File

@ -1,69 +0,0 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
import Stencil
import Foundation
// A class for loading Stencil templates from compiled-in representations
public class InternalLoader: Loader {
private var templates: [String:String]
public init() {
self.templates = loadTemplates()
}
public func loadTemplate(name: String, environment: Environment) throws -> Template {
if let encoding = templates[name],
let data = Data(base64Encoded: encoding, options:[]),
let template = String(data:data, encoding:.utf8) {
return environment.templateClass.init(templateString: template,
environment: environment,
name: name)
} else {
throw TemplateDoesNotExist(templateNames: [name], loader: self)
}
}
public func loadTemplate(names: [String], environment: Environment) throws -> Template {
for name in names {
if let encoding = templates[name],
let data = Data(base64Encoded: encoding, options:[]),
let template = String(data:data, encoding:.utf8) {
return environment.templateClass.init(templateString: template,
environment: environment,
name: name)
}
}
throw TemplateDoesNotExist(templateNames: names, loader: self)
}
}

View File

@ -1,17 +0,0 @@
//
// CuckooGeneratorFramework.h
// CuckooGeneratorFramework
//
// Created by Tadeas Kriz on 13/01/16.
// Copyright © 2016 Brightify. All rights reserved.
//
#import <Foundation/Foundation.h>
//! Project version number for CuckooGeneratorFramework.
FOUNDATION_EXPORT double CuckooGeneratorFrameworkVersionNumber;
//! Project version string for CuckooGeneratorFramework.
FOUNDATION_EXPORT const unsigned char CuckooGeneratorFrameworkVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <CuckooGeneratorFramework/PublicHeader.h>

View File

@ -1,17 +0,0 @@
// GENERATED: DO NOT EDIT
//
// This file contains base64 encodings of templates used for Swift GRPC code generation.
//
func loadTemplates() -> [String:String] {
var templates : [String:String] = [:]
templates["Mock.swift.stencil"] = "eyUgZm9yIGNvbnRhaW5lciBpbiBjb250YWluZXJzICV9CmNsYXNzIE1vY2t7eyBjb250YWluZXIubmFtZSB9fToge3sgY29udGFpbmVyLm5hbWUgfX0sIEN1Y2tvby5Nb2NrIHsKICAgIHR5cGVhbGlhcyBNb2Nrc1R5cGUgPSB7eyBjb250YWluZXIubmFtZSB9fQogICAgdHlwZWFsaWFzIFN0dWJiaW5nID0gX19TdHViYmluZ1Byb3h5X3t7IGNvbnRhaW5lci5uYW1lIH19CiAgICB0eXBlYWxpYXMgVmVyaWZpY2F0aW9uID0gX19WZXJpZmljYXRpb25Qcm94eV97eyBjb250YWluZXIubmFtZSB9fQogICAgbGV0IGN1Y2tvb19tYW5hZ2VyID0gQ3Vja29vLk1vY2tNYW5hZ2VyKCkKCiAgICBwcml2YXRlIHZhciBvYnNlcnZlZDoge3sgY29udGFpbmVyLm5hbWUgfX0/CgogICAgZnVuYyBzcHkob24gdmljdGltOiB7eyBjb250YWluZXIubmFtZSB9fSkgLT4gU2VsZiB7CiAgICAgICAgb2JzZXJ2ZWQgPSB2aWN0aW0KICAgICAgICByZXR1cm4gc2VsZgogICAgfQoKICAgIHslIGZvciBwcm9wZXJ0eSBpbiBjb250YWluZXIucHJvcGVydGllcyAlfQogICAgLy8ge3twcm9wZXJ0eX19CiAgICB7eyBwcm9wZXJ0eS5hY2Nlc3NpYmlsaXR5IH19eyUgaWYgY29udGFpbmVyLkB0eXBlID09ICJDbGFzc0RlY2xhcmF0aW9uIiAlfSBvdmVycmlkZXslIGVuZGlmICV9IHZhciB7eyBwcm9wZXJ0eS5uYW1lIH19OiB7eyBwcm9wZXJ0eS50eXBlIH19IHsKICAgICAgICBnZXQgewogICAgICAgICAgICByZXR1cm4gY3Vja29vX21hbmFnZXIuZ2V0dGVyKCJ7eyBwcm9wZXJ0eS5uYW1lIH19Iiwgb3JpZ2luYWw6IG9ic2VydmVkLm1hcCB7IG8gaW4gcmV0dXJuIHsgKCkgLT4ge3sgcHJvcGVydHkudHlwZSB9fSBpbiBvLnt7IHByb3BlcnR5Lm5hbWUgfX0gfX0pCiAgICAgICAgfQogICAgICAgIHslIGlmbm90IHByb3BlcnR5LmlzUmVhZE9ubHkgJX0KICAgICAgICBzZXQgewogICAgICAgICAgICBjdWNrb29fbWFuYWdlci5zZXR0ZXIoInt7IHByb3BlcnR5Lm5hbWUgfX0iLCB2YWx1ZTogbmV3VmFsdWUsIG9yaWdpbmFsOiBvYnNlcnZlZCAhPSBuaWwgPyB7IHNlbGYub2JzZXJ2ZWQ/Lnt7IHByb3BlcnR5Lm5hbWUgfX0gPSAkMCB9IDogbmlsKQogICAgICAgIH0KICAgICAgICB7JSBlbmRpZiAlfQogICAgfQogICAgeyUgZW5kZm9yICV9CgogICAgeyUgZm9yIGluaXRpYWxpemVyIGluIGNvbnRhaW5lci5pbml0aWFsaXplcnMgJX0KICAgIHt7IGluaXRpYWxpemVyLmFjY2Vzc2liaWxpdHkgfX17JSBpZiBjb250YWluZXIuQHR5cGUgPT0gIkNsYXNzRGVjbGFyYXRpb24iICV9IG92ZXJyaWRleyUgZW5kaWYgJX17JSBpZiBpbml0aWFsaXplci5AdHlwZSA9PSAiUHJvdG9jb2xNZXRob2QiICV9IHJlcXVpcmVkeyVlbmRpZiV9IGluaXQoe3tpbml0aWFsaXplci5wYXJhbWV0ZXJTaWduYXR1cmV9fSkgewogICAgICAgIHslIGlmIGNvbnRhaW5lci5AdHlwZSA9PSAiQ2xhc3NEZWNsYXJhdGlvbiIgJX0KICAgICAgICBzdXBlci5pbml0KHt7aW5pdGlhbGl6ZXIuY2FsbH19KQogICAgICAgIHslIGVuZGlmICV9CiAgICB9CiAgICB7JSBlbmRmb3IgJX0KCiAgICB7JSBmb3IgbWV0aG9kIGluIGNvbnRhaW5lci5tZXRob2RzICV9CiAgICB7eyBtZXRob2QuYWNjZXNzaWJpbGl0eSB9fXslIGlmIGNvbnRhaW5lci5AdHlwZSA9PSAiQ2xhc3NEZWNsYXJhdGlvbiIgJX0gb3ZlcnJpZGV7JSBlbmRpZiAlfSBmdW5jIHt7IG1ldGhvZC5uYW1lIH19KHt7IG1ldGhvZC5wYXJhbWV0ZXJTaWduYXR1cmUgfX0pIHt7IG1ldGhvZC5yZXR1cm5TaWduYXR1cmUgfX0gewogICAgICAgIHslIGlmIG1ldGhvZC5pc1Rocm93aW5nICV9CiAgICAgICAgcmV0dXJuIHRyeSBjdWNrb29fbWFuYWdlci5jYWxsVGhyb3dzKCJ7e21ldGhvZC5mdWxseVF1YWxpZmllZE5hbWV9fSIsCiAgICAgICAgICAgIHBhcmFtZXRlcnM6ICh7e21ldGhvZC5wYXJhbWV0ZXJOYW1lc319KSwKICAgICAgICAgICAgb3JpZ2luYWw6IG9ic2VydmVkLm1hcCB7IG8gaW4gcmV0dXJuIHsgKHt7IG1ldGhvZC5wYXJhbWV0ZXJTaWduYXR1cmVXaXRob3V0TmFtZXMgfX0pe3ttZXRob2QucmV0dXJuU2lnbmF0dXJlfX0gaW4gdHJ5IG8ue3ttZXRob2QubmFtZX19eyVpZiBtZXRob2QuaXNPcHRpb25hbCAlfT97JWVuZGlmJX0oe3ttZXRob2QuY2FsbH19KSB9IH0pCiAgICAgICAgeyUgZWxzZSAlfQogICAgICAgIHJldHVybiBjdWNrb29fbWFuYWdlci5jYWxsKCJ7e21ldGhvZC5mdWxseVF1YWxpZmllZE5hbWV9fSIsCiAgICAgICAgICAgIHBhcmFtZXRlcnM6ICh7e21ldGhvZC5wYXJhbWV0ZXJOYW1lc319KSwKICAgICAgICAgICAgb3JpZ2luYWw6IG9ic2VydmVkLm1hcCB7IG8gaW4gcmV0dXJuIHsgKHt7IG1ldGhvZC5wYXJhbWV0ZXJTaWduYXR1cmVXaXRob3V0TmFtZXMgfX0pe3ttZXRob2QucmV0dXJuU2lnbmF0dXJlfX0gaW4gby57e21ldGhvZC5uYW1lfX17JWlmIG1ldGhvZC5pc09wdGlvbmFsICV9P3slZW5kaWYlfSh7e21ldGhvZC5jYWxsfX0pIH0gfSkKICAgICAgICB7JSBlbmRpZiAlfQogICAgfQogICAgeyUgZW5kZm9yICV9Cgp7JSBpbmNsdWRlICJTdHViYmluZ1Byb3h5LnN3aWZ0LnN0ZW5jaWwiICV9Cgp7JSBpbmNsdWRlICJWZXJpZmljYXRpb25Qcm94eS5zd2lmdC5zdGVuY2lsIiAlfQoKfQoKeyUgaW5jbHVkZSAiTm9wSW1wbFN0dWIuc3dpZnQuc3RlbmNpbCIgJX0KCnslIGVuZGZvciAlfQo="
templates["NopImplStub.swift.stencil"] = "e3tjb250YWluZXIuYWNjZXNzaWJpbGl0eX19IGNsYXNzIHt7IGNvbnRhaW5lci5uYW1lIH19U3R1Yjoge3sgY29udGFpbmVyLm5hbWUgfX0gewogICAgeyUgZm9yIHByb3BlcnR5IGluIGNvbnRhaW5lci5wcm9wZXJ0aWVzICV9CiAgICB7eyBwcm9wZXJ0eS5hY2Nlc3NpYmlsaXR5IH19eyUgaWYgY29udGFpbmVyLkB0eXBlID09ICJDbGFzc0RlY2xhcmF0aW9uIiAlfSBvdmVycmlkZXslIGVuZGlmICV9IHZhciB7eyBwcm9wZXJ0eS5uYW1lIH19OiB7eyBwcm9wZXJ0eS50eXBlIH19IHsKICAgICAgICBnZXQgewogICAgICAgICAgICByZXR1cm4gRGVmYXVsdFZhbHVlUmVnaXN0cnkuZGVmYXVsdFZhbHVlKGZvcjogKHt7cHJvcGVydHkudHlwZX19KS5zZWxmKQogICAgICAgIH0KICAgICAgICB7JSBpZm5vdCBwcm9wZXJ0eS5pc1JlYWRPbmx5ICV9CiAgICAgICAgc2V0IHsgfQogICAgICAgIHslIGVuZGlmICV9CiAgICB9CiAgICB7JSBlbmRmb3IgJX0KCiAgICB7JSBmb3IgaW5pdGlhbGl6ZXIgaW4gY29udGFpbmVyLmluaXRpYWxpemVycyAlfQogICAge3sgaW5pdGlhbGl6ZXIuYWNjZXNzaWJpbGl0eSB9fXslIGlmIGNvbnRhaW5lci5AdHlwZSA9PSAiQ2xhc3NEZWNsYXJhdGlvbiIgJX0gb3ZlcnJpZGV7JSBlbmRpZiAlfXslIGlmIGluaXRpYWxpemVyLkB0eXBlID09ICJQcm90b2NvbE1ldGhvZCIgJX0gcmVxdWlyZWR7JWVuZGlmJX0gaW5pdCh7e2luaXRpYWxpemVyLnBhcmFtZXRlclNpZ25hdHVyZX19KSB7CiAgICAgICAgeyUgaWYgY29udGFpbmVyLkB0eXBlID09ICJDbGFzc0RlY2xhcmF0aW9uIiAlfQogICAgICAgIHN1cGVyLmluaXQoe3tpbml0aWFsaXplci5jYWxsfX0pCiAgICAgICAgeyUgZW5kaWYgJX0KICAgIH0KICAgIHslIGVuZGZvciAlfQoKICAgIHslIGZvciBtZXRob2QgaW4gY29udGFpbmVyLm1ldGhvZHMgJX0KICAgIHt7IG1ldGhvZC5hY2Nlc3NpYmlsaXR5IH19eyUgaWYgY29udGFpbmVyLkB0eXBlID09ICJDbGFzc0RlY2xhcmF0aW9uIiAlfSBvdmVycmlkZXslIGVuZGlmICV9IGZ1bmMge3sgbWV0aG9kLm5hbWUgfX0oe3sgbWV0aG9kLnBhcmFtZXRlclNpZ25hdHVyZSB9fSkge3sgbWV0aG9kLnJldHVyblNpZ25hdHVyZSB9fSB7CiAgICAgICAgcmV0dXJuIERlZmF1bHRWYWx1ZVJlZ2lzdHJ5LmRlZmF1bHRWYWx1ZShmb3I6ICh7e21ldGhvZC5yZXR1cm5UeXBlfX0pLnNlbGYpCiAgICB9CiAgICB7JSBlbmRmb3IgJX0KfQo="
templates["StubbingProxy.swift.stencil"] = "ICAgIHN0cnVjdCBfX1N0dWJiaW5nUHJveHlfe3sgY29udGFpbmVyLm5hbWUgfX06IEN1Y2tvby5TdHViYmluZ1Byb3h5IHsKICAgICAgICBwcml2YXRlIGxldCBjdWNrb29fbWFuYWdlcjogQ3Vja29vLk1vY2tNYW5hZ2VyCgogICAgICAgIGluaXQobWFuYWdlcjogQ3Vja29vLk1vY2tNYW5hZ2VyKSB7CiAgICAgICAgICAgIHNlbGYuY3Vja29vX21hbmFnZXIgPSBtYW5hZ2VyCiAgICAgICAgfQogICAgICAgIHslIGZvciBwcm9wZXJ0eSBpbiBjb250YWluZXIucHJvcGVydGllcyAlfQogICAgICAgIHZhciB7e3Byb3BlcnR5Lm5hbWV9fTogQ3Vja29vLlRvQmVTdHViYmVkeyUgaWYgcHJvcGVydHkuaXNSZWFkT25seSAlfVJlYWRPbmx5eyVlbmRpZiV9UHJvcGVydHk8e3twcm9wZXJ0eS50eXBlfGdlbmVyaWNTYWZlfX0+IHsKICAgICAgICAgICAgcmV0dXJuIC5pbml0KG1hbmFnZXI6IGN1Y2tvb19tYW5hZ2VyLCBuYW1lOiAie3twcm9wZXJ0eS5uYW1lfX0iKQogICAgICAgIH0KICAgICAgICB7JSBlbmRmb3IgJX0KICAgICAgICB7JSBmb3IgbWV0aG9kIGluIGNvbnRhaW5lci5tZXRob2RzICV9CiAgICAgICAgZnVuYyB7e21ldGhvZC5uYW1lfX17e21ldGhvZC5wYXJhbWV0ZXJzfG1hdGNoYWJsZUdlbmVyaWNOYW1lc319KHt7bWV0aG9kLnBhcmFtZXRlcnN8bWF0Y2hhYmxlUGFyYW1ldGVyU2lnbmF0dXJlfX0pIC0+IHt7bWV0aG9kLnN0dWJGdW5jdGlvbn19PCh7e21ldGhvZC5pbnB1dFR5cGVzfGdlbmVyaWNTYWZlfX0peyVpZiBtZXRob2QucmV0dXJuVHlwZSAhPSAiVm9pZCIgJX0sIHt7bWV0aG9kLnJldHVyblR5cGV8Z2VuZXJpY1NhZmV9fXslZW5kaWYlfT57e21ldGhvZC5wYXJhbWV0ZXJzfG1hdGNoYWJsZUdlbmVyaWNXaGVyZX19IHsKICAgICAgICAgICAge3ttZXRob2QucGFyYW1ldGVyc3xwYXJhbWV0ZXJNYXRjaGVyc319CiAgICAgICAgICAgIHJldHVybiAuaW5pdChzdHViOiBjdWNrb29fbWFuYWdlci5jcmVhdGVTdHViKCJ7e21ldGhvZC5mdWxseVF1YWxpZmllZE5hbWV9fSIsIHBhcmFtZXRlck1hdGNoZXJzOiBtYXRjaGVycykpCiAgICAgICAgfQogICAgICAgIHslIGVuZGZvciAlfQogICAgfQo="
templates["VerificationProxy.swift.stencil"] = "ICAgIHN0cnVjdCBfX1ZlcmlmaWNhdGlvblByb3h5X3t7IGNvbnRhaW5lci5uYW1lIH19OiBDdWNrb28uVmVyaWZpY2F0aW9uUHJveHkgewogICAgICAgIHByaXZhdGUgbGV0IGN1Y2tvb19tYW5hZ2VyOiBDdWNrb28uTW9ja01hbmFnZXIKICAgICAgICBwcml2YXRlIGxldCBjYWxsTWF0Y2hlcjogQ3Vja29vLkNhbGxNYXRjaGVyCiAgICAgICAgcHJpdmF0ZSBsZXQgc291cmNlTG9jYXRpb246IEN1Y2tvby5Tb3VyY2VMb2NhdGlvbgoKICAgICAgICBpbml0KG1hbmFnZXI6IEN1Y2tvby5Nb2NrTWFuYWdlciwgY2FsbE1hdGNoZXI6IEN1Y2tvby5DYWxsTWF0Y2hlciwgc291cmNlTG9jYXRpb246IEN1Y2tvby5Tb3VyY2VMb2NhdGlvbikgewogICAgICAgICAgICBzZWxmLmN1Y2tvb19tYW5hZ2VyID0gbWFuYWdlcgogICAgICAgICAgICBzZWxmLmNhbGxNYXRjaGVyID0gY2FsbE1hdGNoZXIKICAgICAgICAgICAgc2VsZi5zb3VyY2VMb2NhdGlvbiA9IHNvdXJjZUxvY2F0aW9uCiAgICAgICAgfQoKICAgICAgICB7JSBmb3IgcHJvcGVydHkgaW4gY29udGFpbmVyLnByb3BlcnRpZXMgJX0KICAgICAgICB2YXIge3twcm9wZXJ0eS5uYW1lfX06IEN1Y2tvby5WZXJpZnl7JSBpZiBwcm9wZXJ0eS5pc1JlYWRPbmx5ICV9UmVhZE9ubHl7JWVuZGlmJX1Qcm9wZXJ0eTx7e3Byb3BlcnR5LnR5cGV8Z2VuZXJpY1NhZmV9fT4gewogICAgICAgICAgICByZXR1cm4gLmluaXQobWFuYWdlcjogY3Vja29vX21hbmFnZXIsIG5hbWU6ICJ7e3Byb3BlcnR5Lm5hbWV9fSIsIGNhbGxNYXRjaGVyOiBjYWxsTWF0Y2hlciwgc291cmNlTG9jYXRpb246IHNvdXJjZUxvY2F0aW9uKQogICAgICAgIH0KICAgICAgICB7JSBlbmRmb3IgJX0KCiAgICAgICAgeyUgZm9yIG1ldGhvZCBpbiBjb250YWluZXIubWV0aG9kcyAlfQogICAgICAgIEBkaXNjYXJkYWJsZVJlc3VsdAogICAgICAgIGZ1bmMge3ttZXRob2QubmFtZX19e3ttZXRob2QucGFyYW1ldGVyc3xtYXRjaGFibGVHZW5lcmljTmFtZXN9fSh7e21ldGhvZC5wYXJhbWV0ZXJzfG1hdGNoYWJsZVBhcmFtZXRlclNpZ25hdHVyZX19KSAtPiBDdWNrb28uX19Eb05vdFVzZTx7e21ldGhvZC5yZXR1cm5UeXBlfGdlbmVyaWNTYWZlfX0+e3ttZXRob2QucGFyYW1ldGVyc3xtYXRjaGFibGVHZW5lcmljV2hlcmV9fSB7CiAgICAgICAgICAgIHt7bWV0aG9kLnBhcmFtZXRlcnN8cGFyYW1ldGVyTWF0Y2hlcnN9fQogICAgICAgICAgICByZXR1cm4gY3Vja29vX21hbmFnZXIudmVyaWZ5KCJ7e21ldGhvZC5mdWxseVF1YWxpZmllZE5hbWV9fSIsIGNhbGxNYXRjaGVyOiBjYWxsTWF0Y2hlciwgcGFyYW1ldGVyTWF0Y2hlcnM6IG1hdGNoZXJzLCBzb3VyY2VMb2NhdGlvbjogc291cmNlTG9jYXRpb24pCiAgICAgICAgfQogICAgICAgIHslIGVuZGZvciAlfQogICAgfQo="
return templates
}

View File

@ -1,241 +0,0 @@
//
// Tokenizer.swift
// CuckooGenerator
//
// Created by Tadeas Kriz on 12/01/16.
// Copyright © 2016 Brightify. All rights reserved.
//
import Foundation
import SourceKittenFramework
public struct Tokenizer {
private let file: File
private let source: String
public init(sourceFile: File) {
self.file = sourceFile
source = sourceFile.contents
}
public func tokenize() -> FileRepresentation {
let structure = Structure(file: file)
let declarations = tokenize(structure.dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
let imports = tokenize(imports: declarations)
return FileRepresentation(sourceFile: file, declarations: declarations + imports)
}
private func tokenize(_ representables: [SourceKitRepresentable]) -> [Token] {
return representables.flatMap(tokenize)
}
internal static let nameNotSet = "name not set"
internal static let unknownType = "unknown type"
private func tokenize(_ representable: SourceKitRepresentable) -> Token? {
guard let dictionary = representable as? [String: SourceKitRepresentable] else { return nil }
// Common fields
let name = dictionary[Key.Name.rawValue] as? String ?? Tokenizer.nameNotSet
let kind = dictionary[Key.Kind.rawValue] as? String ?? Tokenizer.unknownType
// Inheritance
let inheritedTypes = dictionary[Key.InheritedTypes.rawValue] as? [SourceKitRepresentable] ?? []
let tokenizedInheritedTypes = inheritedTypes.flatMap { type -> InheritanceDeclaration in
guard let typeDict = type as? [String: SourceKitRepresentable] else {
return InheritanceDeclaration.empty
}
let name = typeDict[Key.Name.rawValue] as? String ?? Tokenizer.nameNotSet
return InheritanceDeclaration(name: name)
}
// Optional fields
let range = extractRange(from: dictionary, offset: .Offset, length: .Length)
let nameRange = extractRange(from: dictionary, offset: .NameOffset, length: .NameLength)
let bodyRange = extractRange(from: dictionary, offset: .BodyOffset, length: .BodyLength)
let attributes = dictionary[Key.Attributes.rawValue]
print(attributes)
let attributeOptional = (dictionary[Key.Attributes.rawValue] as? [Any])?.first(where: {($0 as? [String : String])?[Key.Attribute.rawValue] == Kinds.Optional.rawValue}) != nil
let accessibility = (dictionary[Key.Accessibility.rawValue] as? String).flatMap { Accessibility(rawValue: $0) }
let type = dictionary[Key.TypeName.rawValue] as? String
switch kind {
case Kinds.ProtocolDeclaration.rawValue:
let subtokens = tokenize(dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
let initializers = subtokens.only(Initializer.self)
let children = subtokens.noneOf(Initializer.self)
return ProtocolDeclaration(
name: name,
accessibility: accessibility!,
range: range!,
nameRange: nameRange!,
bodyRange: bodyRange!,
initializers: initializers,
children: children,
inheritedTypes: tokenizedInheritedTypes)
case Kinds.ClassDeclaration.rawValue:
let subtokens = tokenize(dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
let initializers = subtokens.only(Initializer.self)
let children = subtokens.noneOf(Initializer.self).map { child -> Token in
if var property = child as? InstanceVariable {
property.overriding = true
return property
} else {
return child
}
}
return ClassDeclaration(
name: name,
accessibility: accessibility!,
range: range!,
nameRange: nameRange!,
bodyRange: bodyRange!,
initializers: initializers,
children: children,
inheritedTypes: tokenizedInheritedTypes)
case Kinds.ExtensionDeclaration.rawValue:
return ExtensionDeclaration(range: range!)
case Kinds.InstanceVariable.rawValue:
let setterAccessibility = (dictionary[Key.SetterAccessibility.rawValue] as? String).flatMap(Accessibility.init)
if String(describing: source.utf8.dropFirst(range!.startIndex)).takeUntil(occurence: name)?.trimmed.hasPrefix("let") == true {
return nil
}
if type == nil {
stderrPrint("Type of instance variable \(name) could not be inferred. Please specify it explicitly. (\(file.path ?? ""))")
}
return InstanceVariable(
name: name,
type: type ?? "__UnknownType",
accessibility: accessibility!,
setterAccessibility: setterAccessibility,
range: range!,
nameRange: nameRange!,
overriding: false)
case Kinds.InstanceMethod.rawValue:
let parameters = tokenize(methodName: name, parameters: dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
var returnSignature: String
if let bodyRange = bodyRange {
returnSignature = source[nameRange!.endIndex..<bodyRange.startIndex].takeUntil(occurence: "{")?.trimmed ?? ""
} else {
returnSignature = source[nameRange!.endIndex..<range!.endIndex].trimmed
if returnSignature.isEmpty {
let untilThrows = String(source.utf8.dropFirst(nameRange!.endIndex))?
.takeUntil(occurence: "throws").map { $0 + "throws" }?
.trimmed
if let untilThrows = untilThrows, untilThrows == "throws" || untilThrows == "rethrows" {
returnSignature = "\(untilThrows)"
}
}
}
if returnSignature.isEmpty == false {
returnSignature = " " + returnSignature
}
// When bodyRange != nil, we need to create .ClassMethod instead of .ProtocolMethod
if let bodyRange = bodyRange {
return ClassMethod(
name: name,
accessibility: accessibility!,
returnSignature: returnSignature,
range: range!,
nameRange: nameRange!,
parameters: parameters,
bodyRange: bodyRange)
} else {
return ProtocolMethod(
name: name,
accessibility: accessibility!,
returnSignature: returnSignature,
isOptional: attributeOptional,
range: range!,
nameRange: nameRange!,
parameters: parameters)
}
default:
// Do not log anything, until the parser contains all known cases.
// stderrPrint("Unknown kind. Dictionary: \(dictionary) \(file.path ?? "")")
return nil
}
}
private func tokenize(methodName: String, parameters: [SourceKitRepresentable]) -> [MethodParameter] {
// Takes the string between `(` and `)`
let parameterNames = methodName.components(separatedBy: "(").last?.characters.dropLast(1).map { "\($0)" }.joined(separator: "")
var parameterLabels: [String?] = parameterNames?.components(separatedBy: ":").map { $0 != "_" ? $0 : nil } ?? []
// Last element is not type.
parameterLabels = Array(parameterLabels.dropLast())
// Substructure can contain some other informations after the parameters.
let filteredParameters = parameters.filter({
let dictionary = $0 as? [String: SourceKitRepresentable]
let kind = dictionary?[Key.Kind.rawValue] as? String ?? ""
return kind == Kinds.MethodParameter.rawValue
})
return zip(parameterLabels, filteredParameters).flatMap(tokenize)
}
private func tokenize(parameterLabel: String?, parameter: SourceKitRepresentable) -> MethodParameter? {
guard let dictionary = parameter as? [String: SourceKitRepresentable] else { return nil }
let name = dictionary[Key.Name.rawValue] as? String ?? "name not set"
let kind = dictionary[Key.Kind.rawValue] as? String ?? "unknown type"
let range = extractRange(from: dictionary, offset: .Offset, length: .Length)
let nameRange = extractRange(from: dictionary, offset: .NameOffset, length: .NameLength)
let type = dictionary[Key.TypeName.rawValue] as? String
switch kind {
case Kinds.MethodParameter.rawValue:
return MethodParameter(label: parameterLabel, name: name, type: type!, range: range!, nameRange: nameRange!)
default:
stderrPrint("Unknown method parameter. Dictionary: \(dictionary) \(file.path ?? "")")
return nil
}
}
private func tokenize(imports otherTokens: [Token]) -> [Token] {
let rangesToIgnore: [CountableRange<Int>] = otherTokens.flatMap { token in
switch token {
case let container as ContainerToken:
return container.range
case let extensionToken as ExtensionDeclaration:
return extensionToken.range
default:
return nil
}
}
do {
let regex = try NSRegularExpression(pattern: "(?:\\b|;)import(?:\\s|(?:\\/\\/.*\\n)|(?:\\/\\*.*\\*\\/))+([^\\s;\\/]+)", options: [])
let results = regex.matches(in: source, options: [], range: NSMakeRange(0, source.characters.count))
return results.filter { result in
rangesToIgnore.filter { $0 ~= result.range.location }.isEmpty
}.map {
let libraryRange = $0.rangeAt(1)
let fromIndex = source.index(source.startIndex, offsetBy: libraryRange.location)
let toIndex = source.index(fromIndex, offsetBy: libraryRange.length)
let library = source.substring(with: fromIndex..<toIndex)
let range = $0.range.location..<($0.range.location + $0.range.length)
return Import(range: range, library: library)
}
} catch let error as NSError {
fatalError("Invalid regex:" + error.description)
}
}
}

View File

@ -1,20 +0,0 @@
//
// Attribute.swift
// CuckooGenerator
//
// Created by Tadeas Kriz on 2/25/17.
//
//
public enum Attribute: String {
case objc = "source.decl.attribute.objc"
case optional = "source.decl.attribute.optional"
case lazy = "source.decl.attribute.lazy"
case required = "source.decl.attribute.required"
case override = "source.decl.attribute.override"
case convenience = "source.decl.attribute.convenience"
case weak = "source.decl.attribute.weak"
case ibAction = "source.decl.attribute.ibaction"
case ibOutlet = "source.decl.attribute.iboutlet"
}

View File

@ -1,40 +0,0 @@
//
// ClassDeclaration.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public struct ClassDeclaration: ContainerToken {
public let name: String
public let accessibility: Accessibility
public let range: CountableRange<Int>
public let nameRange: CountableRange<Int>
public let bodyRange: CountableRange<Int>
public let initializers: [Initializer]
public let children: [Token]
public let implementation: Bool = true
public let inheritedTypes: [InheritanceDeclaration]
public let attributes: [Attribute] = []
public var hasNoArgInit: Bool {
return initializers.filter { $0.parameters.isEmpty }.isEmpty
}
public func replace(children tokens: [Token]) -> ClassDeclaration {
return ClassDeclaration(name: self.name,
accessibility: self.accessibility,
range: self.range,
nameRange: self.nameRange,
bodyRange: self.bodyRange,
initializers: self.initializers,
children: tokens,
inheritedTypes: self.inheritedTypes)
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? ClassDeclaration else { return false }
return self.name == other.name
}
}

View File

@ -1,22 +0,0 @@
//
// ClassMethod.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public struct ClassMethod: Method {
public let name: String
public let accessibility: Accessibility
public let returnSignature: String
public let range: CountableRange<Int>
public let nameRange: CountableRange<Int>
public let parameters: [MethodParameter]
public let bodyRange: CountableRange<Int>
public var isOptional: Bool {
return false
}
}

View File

@ -1,46 +0,0 @@
//
// ContainerToken.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public protocol ContainerToken: Token {
var name: String { get }
var accessibility: Accessibility { get }
var range: CountableRange<Int> { get }
var nameRange: CountableRange<Int> { get }
var bodyRange: CountableRange<Int> { get }
var initializers: [Initializer] { get }
var children: [Token] { get }
var implementation: Bool { get }
var inheritedTypes: [InheritanceDeclaration] { get }
var attributes: [Attribute] { get }
}
extension ContainerToken {
public func serialize() -> [String : Any] {
let properties = children.flatMap { $0 as? InstanceVariable }
.filter { $0.accessibility.isAccessible }
.map { $0.serializeWithType() }
let methods = children.flatMap { $0 as? Method }
.filter { $0.accessibility.isAccessible && !$0.isInit && !$0.isDeinit }
.map { $0.serializeWithType() }
let initializers = children.flatMap { $0 as? Method }
.filter { $0.accessibility.isAccessible && $0.isInit && !$0.isDeinit }
.map { $0.serializeWithType() }
return [
"name": name,
"accessibility": accessibility,
"isAccessible": accessibility.isAccessible,
"children": children.map { $0.serializeWithType() },
"properties": properties,
"methods": methods,
"initializers": implementation ? [] : initializers
]
}
}

View File

@ -1,17 +0,0 @@
//
// ExtensionDeclaration.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 17.06.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public struct ExtensionDeclaration: Token {
// TODO Implement support for extensions
public let range: CountableRange<Int>
public func isEqual(to other: Token) -> Bool {
guard let other = other as? ExtensionDeclaration else { return false }
return self.range == other.range
}
}

View File

@ -1,67 +0,0 @@
//
// FileRepresentation.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
import SourceKittenFramework
public struct FileRepresentation {
public let sourceFile: File
public let declarations: [Token]
public init(sourceFile: File, declarations: [Token]) {
self.sourceFile = sourceFile
self.declarations = declarations
}
}
public extension FileRepresentation {
public func mergeInheritance(with files: [FileRepresentation]) -> FileRepresentation {
let tokens = self.declarations.reduce([Token]()) { list, token in
let mergeToken = token.mergeInheritance(with: files)
return list + [mergeToken]
}
return FileRepresentation(sourceFile: self.sourceFile, declarations: tokens)
}
}
internal extension Token {
internal func mergeInheritance(with files: [FileRepresentation]) -> Token {
guard let typeToken = self as? ContainerToken else {
return self
}
let inheritedRepresentations: [Token] = typeToken.inheritedTypes
.flatMap { Self.findToken(forClassOrProtocol: $0.name, in: files) }
.flatMap { $0.mergeInheritance(with: files) }
// Merge super declarations
let mergedTokens = inheritedRepresentations.filter { $0.isClassOrProtocolDefinition }
.map { $0 as! ContainerToken }
.flatMap { $0.children }
.reduce(typeToken.children) { tokens, inheritedToken in
if (tokens.contains { $0 == inheritedToken }) {
return tokens
}
return tokens + [inheritedToken]
}
switch typeToken {
case let classToken as ClassDeclaration:
return classToken.replace(children: mergedTokens)
case let protocolToken as ProtocolDeclaration:
return protocolToken.replace(children: mergedTokens)
default:
return typeToken
}
}
internal static func findToken(forClassOrProtocol name: String, in files: [FileRepresentation]) -> Token? {
return files.flatMap { $0.declarations }
.filter { $0.isClassOrProtocolDefinition }
.map { $0 as! ContainerToken }
.first { $0.name == name }
}
}

View File

@ -1,17 +0,0 @@
//
// Import.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 17.06.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public struct Import: Token {
public let range: CountableRange<Int>
public let library: String
public func isEqual(to other: Token) -> Bool {
guard let other = other as? Import else { return false }
return self.range == other.range && self.library == other.library
}
}

View File

@ -1,22 +0,0 @@
//
// Initializer.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public struct Initializer: Method {
public let name: String
public let accessibility: Accessibility
public let returnSignature: String
public let range: CountableRange<Int>
public let nameRange: CountableRange<Int>
public let parameters: [MethodParameter]
public let required: Bool
public var isOptional: Bool {
return false
}
}

View File

@ -1,39 +0,0 @@
//
// InstanceVariable.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public struct InstanceVariable: Token {
public var name: String
public var type: String
public var accessibility: Accessibility
public var setterAccessibility: Accessibility?
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var overriding: Bool
public var readOnly: Bool {
if let setterAccessibility = setterAccessibility {
return !setterAccessibility.isAccessible
} else {
return true
}
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? InstanceVariable else { return false }
return self.name == other.name
}
public func serialize() -> [String : Any] {
return [
"name": name,
"type": type,
"accesibility": accessibility.sourceName,
"isReadOnly": readOnly,
]
}
}

View File

@ -1,101 +0,0 @@
//
// .swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public protocol Method: Token {
var name: String { get }
var accessibility: Accessibility { get }
var returnSignature: String { get }
var range: CountableRange<Int> { get }
var nameRange: CountableRange<Int> { get }
var parameters: [MethodParameter] { get }
var isOptional: Bool { get }
}
public extension Method {
var rawName: String {
return name.takeUntil(occurence: "(") ?? ""
}
var isInit: Bool {
return rawName == "init"
}
var isDeinit: Bool {
return rawName == "deinit"
}
var fullyQualifiedName: String {
let parameterTypes = parameters.map { $0.type }
let nameParts = name.components(separatedBy: ":")
let lastNamePart = nameParts.last ?? ""
return zip(nameParts.dropLast(), parameterTypes)
.map { $0 + ": " + $1 }
.joined(separator: ", ") + lastNamePart + returnSignature
}
var isThrowing: Bool {
return returnSignature.trimmed.hasPrefix("throws")
}
var returnType: String {
if let range = returnSignature.range(of: "->") {
return returnSignature.substring(from: range.upperBound).trimmed
} else {
return "Void"
}
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? Method else { return false }
return self.name == other.name
}
public func serialize() -> [String : Any] {
let call = parameters.map {
if let label = $0.label {
return "\(label): \($0.name)"
} else {
return $0.name
}
}.joined(separator: ", ")
let stubFunction: String
if isThrowing {
if returnType == "Void" {
stubFunction = "Cuckoo.StubNoReturnThrowingFunction"
} else {
stubFunction = "Cuckoo.StubThrowingFunction"
}
} else {
if returnType == "Void" {
stubFunction = "Cuckoo.StubNoReturnFunction"
} else {
stubFunction = "Cuckoo.StubFunction"
}
}
return [
"name": rawName,
"accessibility": accessibility.sourceName,
"returnSignature": returnSignature,
"parameters": parameters,
"parameterNames": parameters.map { $0.name }.joined(separator: ", "),
"isInit": isInit,
"returnType": returnType,
"isThrowing": isThrowing,
"fullyQualifiedName": fullyQualifiedName,
"call": call,
"parameterSignature": parameters.map { "\($0.labelAndName): \($0.type)" }.joined(separator: ", "),
"parameterSignatureWithoutNames": parameters.map { "\($0.name): \($0.type)" }.joined(separator: ", "),
"stubFunction": stubFunction,
"inputTypes": parameters.map { $0.typeWithoutAttributes }.joined(separator: ", "),
"isOptional": isOptional
]
}
}

View File

@ -1,42 +0,0 @@
//
// MethodParameter.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public struct MethodParameter: Token {
public let label: String?
public let name: String
public let type: String
public let range: CountableRange<Int>
public let nameRange: CountableRange<Int>
public var labelAndName: String {
if let label = label {
return label != name ? "\(label) \(name)" : name
} else {
return "_ \(name)"
}
}
public var typeWithoutAttributes: String {
return type.replacingOccurrences(of: "@escaping", with: "").replacingOccurrences(of: "@autoclosure", with: "").trimmed
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? MethodParameter else { return false }
return self.name == other.name
}
public func serialize() -> [String : Any] {
return [
"label": label,
"name": name,
"type": type,
"labelAndName": labelAndName,
"typeWithoutAttributes": typeWithoutAttributes
]
}
}

View File

@ -1,36 +0,0 @@
//
// ProtocolDeclaration.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public struct ProtocolDeclaration: ContainerToken {
public let name: String
public let accessibility: Accessibility
public let range: CountableRange<Int>
public let nameRange: CountableRange<Int>
public let bodyRange: CountableRange<Int>
public let initializers: [Initializer]
public let children: [Token]
public let implementation: Bool = false
public let inheritedTypes: [InheritanceDeclaration]
public let attributes: [Attribute] = []
public func replace(children tokens: [Token]) -> ProtocolDeclaration {
return ProtocolDeclaration(name: self.name,
accessibility: self.accessibility,
range: self.range,
nameRange: self.nameRange,
bodyRange: self.bodyRange,
initializers: self.initializers,
children: tokens,
inheritedTypes: self.inheritedTypes)
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? ProtocolDeclaration else { return false }
return self.name == other.name
}
}

View File

@ -1,17 +0,0 @@
//
// ProtocolMethod.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public struct ProtocolMethod: Method {
public let name: String
public let accessibility: Accessibility
public let returnSignature: String
public let isOptional: Bool
public let range: CountableRange<Int>
public let nameRange: CountableRange<Int>
public let parameters: [MethodParameter]
}

View File

@ -1,49 +0,0 @@
//
// Token.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public protocol Token {
func isEqual(to other: Token) -> Bool
func serialize() -> [String: Any]
}
public func ==(rhs: Token, lhs: Token) -> Bool {
return rhs.isEqual(to: lhs)
}
public extension Token {
func serialize() -> [String: Any] {
return [:]
}
func serializeWithType() -> [String: Any] {
var serialized = serialize()
serialized["@type"] = "\(type(of: self))"
return serialized
}
public var isClassOrProtocolDefinition: Bool {
switch self {
case _ as ProtocolDeclaration:
fallthrough
case _ as ClassDeclaration:
return true
default:
return false
}
}
public var isInheritanceDefinition: Bool {
switch self {
case _ as InheritanceDeclaration:
return true
default:
return false
}
}
}

View File

@ -1,45 +0,0 @@
//
// String+Utility.swift
// CuckooGenerator
//
// Created by Tadeas Kriz on 12/01/16.
// Copyright © 2016 Brightify. All rights reserved.
//
import Foundation
import SourceKittenFramework
extension String {
var trimmed: String {
return trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
func takeUntil(occurence: String) -> String? {
return components(separatedBy: occurence).first
}
subscript(range: Range<Int>) -> String {
let stringRange = characters.index(startIndex, offsetBy: range.lowerBound)..<characters.index(startIndex, offsetBy: range.upperBound)
return self[stringRange]
}
}
extension Sequence {
func only<T>(_ type: T.Type) -> [T] {
return flatMap { $0 as? T }
}
func noneOf<T>(_ type: T.Type) -> [Iterator.Element] {
return filter { !($0 is T) }
}
}
internal func extractRange(from dictionary: [String: SourceKitRepresentable], offset: Key, length: Key) -> CountableRange<Int>? {
guard let
offset = (dictionary[offset.rawValue] as? Int64).map({ Int($0) }),
let length = (dictionary[length.rawValue] as? Int64).map({ Int($0) })
else { return nil }
return offset..<offset.advanced(by: length)
}

View File

@ -1,11 +1,3 @@
//
// FileHeaderHandler.swift
// CuckooGenerator
//
// Created by Tadeas Kriz on 12/01/16.
// Copyright © 2016 Brightify. All rights reserved.
//
import Foundation
import FileKit
@ -24,9 +16,9 @@ public struct FileHeaderHandler {
}
public static func getImports(of file: FileRepresentation, testableFrameworks: [String]) -> String {
var imports = Array(Set(file.declarations.only(Import.self).map { "import " + $0.library + "\n" })).sorted().joined(separator: "")
var imports = Array(Set(file.declarations.only(Import.self).map { "import \($0.importee)\n" })).sorted().joined(separator: "")
if imports.isEmpty == false {
imports = "\n" + imports
imports = "\n\(imports)"
}
return "import Cuckoo\n" + getTestableImports(testableFrameworks: testableFrameworks) + imports
}
@ -45,7 +37,7 @@ public struct FileHeaderHandler {
let possibleHeader = String(file.sourceFile.contents.utf8.prefix(possibleHeaderEnd)) ?? ""
let singleLine = getPrefixToLastSingleLineComment(text: possibleHeader)
let multiLine = getPrefixToLastMultiLineComment(text: possibleHeader)
return singleLine.characters.count > multiLine.characters.count ? singleLine : multiLine
return singleLine.count > multiLine.count ? singleLine : multiLine
}
private static func getPossibleHeaderEnd(current: Int, declarations: [Token]) -> Int {
@ -68,7 +60,7 @@ public struct FileHeaderHandler {
private static func getPrefixToLastSingleLineComment(text: String) -> String {
if let range = text.range(of: "//", options: .backwards) {
let lastLine = text.lineRange(for: range)
return text.substring(to: lastLine.upperBound)
return String(text[..<lastLine.upperBound])
} else {
return ""
}
@ -76,7 +68,7 @@ public struct FileHeaderHandler {
private static func getPrefixToLastMultiLineComment(text: String) -> String {
if let range = text.range(of: "*/", options: .backwards) {
return text.substring(to: range.upperBound) + "\n"
return String(text[..<range.upperBound]) + "\n"
} else {
return ""
}

View File

@ -0,0 +1,156 @@
import Foundation
import Stencil
public struct Generator {
private let declarations: [Token]
public init(file: FileRepresentation) {
declarations = file.declarations
}
public func generate(debug: Bool = false) throws -> String {
let ext = Extension()
ext.registerFilter("genericSafe") { (value: Any?) in
guard let string = value as? String else { return value }
return self.genericSafeType(from: string)
}
ext.registerFilter("matchableGenericNames") { (value: Any?) in
guard let method = value as? Method else { return value }
return self.matchableGenericTypes(from: method)
}
ext.registerFilter("matchableGenericWhereClause") { (value: Any?) in
guard let method = value as? Method else { return value }
return self.matchableGenericsWhereClause(from: method)
}
ext.registerFilter("matchableParameterSignature") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return self.matchableParameterSignature(with: parameters)
}
ext.registerFilter("parameterMatchers") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return self.parameterMatchers(for: parameters)
}
ext.registerFilter("openNestedClosure") { (value: Any?) in
guard let method = value as? Method else { return value }
return self.openNestedClosure(for: method)
}
ext.registerFilter("closeNestedClosure") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return self.closeNestedClosure(for: parameters)
}
ext.registerFilter("escapeReservedKeywords") { (value: Any?) in
guard let name = value as? String else { return value }
return escapeReservedKeywords(for: name)
}
ext.registerFilter("removeClosureArgumentNames") { (value: Any?) in
guard let type = value as? String else { return value }
return self.removeClosureArgumentNames(for: type)
}
let environment = Environment(extensions: [ext])
let containers = declarations.compactMap { $0 as? ContainerToken }
.filter {
$0.parent?.areAllHierarchiesAccessible ?? true && $0.accessibility.isAccessible
}
.map { $0.serializeWithType() }
return try environment.renderTemplate(string: Templates.mock, context: ["containers": containers, "debug": debug])
}
private func matchableGenericTypes(from method: Method) -> String {
guard !method.parameters.isEmpty || !method.genericParameters.isEmpty else { return "" }
let matchableGenericParameters = method.parameters.enumerated().map { index, parameter -> String in
let type = parameter.isOptional ? "OptionalMatchable" : "Matchable"
return "M\(index + 1): Cuckoo.\(type)"
}
let methodGenericParameters = method.genericParameters.map { $0.description }
return "<\((matchableGenericParameters + methodGenericParameters).joined(separator: ", "))>"
}
private func matchableGenericsWhereClause(from method: Method) -> String {
guard method.parameters.isEmpty == false else { return "" }
let matchableWhereConstraints = method.parameters.enumerated().map { index, parameter -> String in
let type = parameter.isOptional ? "OptionalMatchedType" : "MatchedType"
return "M\(index + 1).\(type) == \(genericSafeType(from: parameter.type.withoutAttributes.unoptionaled.sugarized))"
}
let methodWhereConstraints = method.returnSignature.whereConstraints
return " where \((matchableWhereConstraints + methodWhereConstraints).joined(separator: ", "))"
}
private func matchableParameterSignature(with parameters: [MethodParameter]) -> String {
guard parameters.isEmpty == false else { return "" }
return parameters.enumerated().map { "\($1.labelAndName): M\($0 + 1)" }.joined(separator: ", ")
}
private func parameterMatchers(for parameters: [MethodParameter]) -> String {
guard parameters.isEmpty == false else { return "let matchers: [Cuckoo.ParameterMatcher<Void>] = []" }
let tupleType = parameters.map { $0.typeWithoutAttributes }.joined(separator: ", ")
let matchers = parameters.enumerated().map { index, parameter in
let name = escapeReservedKeywords(for: parameter.name)
return "wrap(matchable: \(name)) { $0\(parameters.count > 1 ? ".\(index)" : "") }"
}
.joined(separator: ", ")
return "let matchers: [Cuckoo.ParameterMatcher<(\(genericSafeType(from: tupleType)))>] = [\(matchers)]"
}
private func genericSafeType(from type: String) -> String {
return type.replacingOccurrences(of: "!", with: "?")
}
private func openNestedClosure(for method: Method) -> String {
var fullString = ""
for (index, parameter) in method.parameters.enumerated() {
if parameter.isClosure && !parameter.isEscaping {
let indents = String(repeating: "\t", count: index)
let tries = method.isThrowing ? "try " : ""
let awaits = method.isAsync ? "await " : ""
let sugarizedReturnType = method.returnType.sugarized
let returnSignature: String
if sugarizedReturnType.isEmpty {
returnSignature = sugarizedReturnType
} else {
returnSignature = " -> \(sugarizedReturnType)"
}
fullString += "\(indents)return \(tries)\(awaits)withoutActuallyEscaping(\(parameter.name), do: { (\(parameter.name): @escaping \(parameter.type))\(returnSignature) in\n"
}
}
return fullString
}
private func closeNestedClosure(for parameters: [MethodParameter]) -> String {
var fullString = ""
for (index, parameter) in parameters.enumerated() {
if parameter.isClosure && !parameter.isEscaping {
let indents = String(repeating: "\t", count: index)
fullString += "\(indents)})\n"
}
}
return fullString
}
private func removeClosureArgumentNames(for type: String) -> String {
type.replacingOccurrences(
of: "_\\s+?[_a-zA-Z]\\w*?\\s*?:",
with: "",
options: .regularExpression
)
}
}

View File

@ -0,0 +1,19 @@
import Foundation
@dynamicMemberLookup
public final class Reference<Value> {
private(set) var value: Value
public init(value: Value) {
self.value = value
}
public subscript<T>(dynamicMember keyPath: KeyPath<Value, T>) -> T {
value[keyPath: keyPath]
}
public subscript<T>(dynamicMember keyPath: WritableKeyPath<Value, T>) -> T {
get { value[keyPath: keyPath] }
set { value[keyPath: keyPath] = newValue }
}
}

View File

@ -1,11 +1,3 @@
//
// StderrPrint.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 18.12.16.
// Copyright © 2016 Brightify. All rights reserved.
//
import Foundation
public private(set) var stderrUsed = false

View File

@ -0,0 +1,153 @@
import Foundation
extension Templates {
static let staticGenericParameter = "_CUCKOO$$GENERIC"
static let typeErasureClassName = "DefaultImplCaller"
static let mock = """
{% for container in containers %}
{% if debug %}
// {{ container }}
{% endif %}
{{ container.unavailablePlatformsCheck }}
{% for attribute in container.attributes %}
{{ attribute.text }}
{% endfor %}
{% if container.hasParent %}
extension {{ container.parentFullyQualifiedName }} {
{% endif %}
{{ container.accessibility }} class {{ container.mockName }}{{ container.genericParameters }}: {% if container.isNSObjectProtocol %}NSObject, {% endif %}{{ container.name }}{% if container.isImplementation %}{{ container.genericArguments }}{% endif %}, {% if container.isImplementation %}Cuckoo.ClassMock{% else %}Cuckoo.ProtocolMock{% endif %} {
{% if container.isGeneric and not container.isImplementation %}
{{ container.accessibility }} typealias MocksType = \(typeErasureClassName){{ container.genericArguments }}
{% else %}
{{ container.accessibility }} typealias MocksType = {{ container.name }}{{ container.genericArguments }}
{% endif %}
{{ container.accessibility }} typealias Stubbing = __StubbingProxy_{{ container.name }}
{{ container.accessibility }} typealias Verification = __VerificationProxy_{{ container.name }}
{{ container.accessibility }} let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: {{ container.isImplementation }})
{% if container.isGeneric and not container.isImplementation %}
\(Templates.typeErasure.indented())
private var __defaultImplStub: \(typeErasureClassName){{ container.genericArguments }}?
{{ container.accessibility }} func enableDefaultImplementation<\(staticGenericParameter): {{ container.name }}>(_ stub: \(staticGenericParameter)) where {{ container.genericProtocolIdentity }} {
var mutableStub = stub
__defaultImplStub = \(typeErasureClassName)(from: &mutableStub, keeping: mutableStub)
cuckoo_manager.enableDefaultStubImplementation()
}
{{ container.accessibility }} func enableDefaultImplementation<\(staticGenericParameter): {{ container.name }}>(mutating stub: UnsafeMutablePointer<\(staticGenericParameter)>) where {{ container.genericProtocolIdentity }} {
__defaultImplStub = \(typeErasureClassName)(from: stub, keeping: nil)
cuckoo_manager.enableDefaultStubImplementation()
}
{% else %}
private var __defaultImplStub: {{ container.name }}{{ container.genericArguments }}?
{{ container.accessibility }} func enableDefaultImplementation(_ stub: {{ container.name }}{{ container.genericArguments }}) {
__defaultImplStub = stub
cuckoo_manager.enableDefaultStubImplementation()
}
{% endif %}
{% for property in container.properties %}
{{ property.unavailablePlatformsCheck }}
{% if debug %}
// {{property}}
{% endif %}
{% for attribute in property.attributes %}
{{ attribute.text }}
{% endfor %}
{{ property.accessibility }}{% if container.isImplementation %} override{% endif %} var {{ property.name }}: {{ property.type }} {
get{% if property.isAsync %} async{% endif %}{% if property.isThrowing %} throws{% endif %} {
return {% if property.isThrowing %}try {% endif %}{% if property.isAsync %}await {% endif %}cuckoo_manager.getter{% if property.isThrowing %}Throws{% endif %}("{{ property.name }}",
superclassCall:
{% if container.isImplementation %}
{% if property.isThrowing %}try {% endif %}{% if property.isAsync %}await {% endif %}super.{{ property.name }}
{% else %}
Cuckoo.MockManager.crashOnProtocolSuperclassCall()
{% endif %},
defaultCall: {% if property.isThrowing %}try {% endif %}{% if property.isAsync %}await {% endif %} __defaultImplStub!.{{property.name}})
}
{% ifnot property.isReadOnly %}
set {
cuckoo_manager.setter("{{ property.name }}",
value: newValue,
superclassCall:
{% if container.isImplementation %}
super.{{ property.name }} = newValue
{% else %}
Cuckoo.MockManager.crashOnProtocolSuperclassCall()
{% endif %},
defaultCall: __defaultImplStub!.{{property.name}} = newValue)
}
{% endif %}
}
{% if property.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
{% for initializer in container.initializers %}
{{ initializer.unavailablePlatformsCheck }}
{% if debug %}
// {{initializer}}
{% endif %}
{{ initializer.accessibility }}{% if container.isImplementation %} override{% endif %}{% if initializer.@type == "ProtocolMethod" %} required{% endif %} init({{initializer.parameterSignature}}) {
{% if container.isImplementation %}
super.init({{initializer.call}})
{% endif %}
}
{% if initializer.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
{% for method in container.methods %}
{{ method.unavailablePlatformsCheck }}
{% if debug %}
// {{method}}
{% endif %}
{% for attribute in method.attributes %}
{{ attribute.text }}
{% endfor %}
{{ method.accessibility }}{% if container.isImplementation and method.isOverriding %} override{% endif %} func {{ method.name|escapeReservedKeywords }}{{ method.genericParameters }}({{ method.parameterSignature }}) {{ method.returnSignature }} {
{{ method.self|openNestedClosure }}
return{% if method.isThrowing %} try{% endif %}{% if method.isAsync %} await{% endif %} cuckoo_manager.call{% if method.isThrowing %}{{ method.throwType|capitalize }}{% endif %}(
\"\"\"
{{method.fullyQualifiedName}}
\"\"\",
parameters: ({{method.parameterNames}}),
escapingParameters: ({{method.escapingParameterNames}}),
superclassCall:
{% if container.isImplementation %}
{% if method.isAsync %}await {% endif %}super.{{method.name}}({{method.call}})
{% else %}
Cuckoo.MockManager.crashOnProtocolSuperclassCall()
{% endif %},
defaultCall: {% if method.isAsync %}await {% endif %}__defaultImplStub!.{{method.name}}{%if method.isOptional %}!{%endif%}({{method.call}}))
{{ method.parameters|closeNestedClosure }}
}
{% if method.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
\(Templates.stubbingProxy.indented())
\(Templates.verificationProxy.indented())
}
\(Templates.noImplStub)
{% if container.hasParent %}
}
{% endif %}
{% if container.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
"""
}

View File

@ -0,0 +1,57 @@
extension Templates {
static let noImplStub = """
{% for attribute in container.attributes %}
{{ attribute.text }}
{% endfor %}
{{container.accessibility}} class {{ container.name }}Stub{{ container.genericParameters }}: {% if container.isNSObjectProtocol %}NSObject, {% endif %}{{ container.name }}{% if container.isImplementation %}{{ container.genericArguments }}{% endif %} {
{% for property in container.properties %}
{{ property.unavailablePlatformsCheck }}
{% if debug %}
// {{property}}
{% endif %}
{% for attribute in property.attributes %}
{{ attribute.text }}
{% endfor %}
{{ property.accessibility }}{% if container.@type == "ClassDeclaration" %} override{% endif %} var {{ property.name }}: {{ property.type }} {
get {
return DefaultValueRegistry.defaultValue(for: ({{property.type|genericSafe|removeClosureArgumentNames}}).self)
}
{% ifnot property.isReadOnly %}
set { }
{% endif %}
}
{% if property.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
{% for initializer in container.initializers %}
{{ initializer.unavailablePlatformsCheck }}
{{ initializer.accessibility }}{% if container.@type == "ClassDeclaration" %} override{% endif %}{% if initializer.@type == "ProtocolMethod" %} required{%endif%} init({{initializer.parameterSignature}}) {
{% if container.@type == "ClassDeclaration" %}
super.init({{initializer.call}})
{% endif %}
}
{% if initializer.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
{% for method in container.methods %}
{{ method.unavailablePlatformsCheck }}
{% if debug %}
// {{method}}
{% endif %}
{% for attribute in method.attributes %}
{{ attribute.text }}
{% endfor %}
{{ method.accessibility }}{% if container.@type == "ClassDeclaration" and method.isOverriding %} override{% endif %} func {{ method.name|escapeReservedKeywords }}{{ method.genericParameters }}({{ method.parameterSignature }}) {{ method.returnSignature }} {{ method.whereClause }} {
return DefaultValueRegistry.defaultValue(for: ({{method.returnType|genericSafe}}).self)
}
{% if method.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
}
"""
}

View File

@ -0,0 +1,41 @@
import Foundation
extension Templates {
static let stubbingProxy = """
{{ container.accessibility }} struct __StubbingProxy_{{ container.name }}: Cuckoo.StubbingProxy {
private let cuckoo_manager: Cuckoo.MockManager
{{ container.accessibility }} init(manager: Cuckoo.MockManager) {
self.cuckoo_manager = manager
}
{% for property in container.properties %}
{{ property.unavailablePlatformsCheck }}
{% for attribute in property.attributes %}
{{ attribute.text }}
{% endfor %}
var {{property.name}}: Cuckoo.{{ property.stubType }}<{{ container.mockName }}, {% if property.isReadOnly %}{{property.type|genericSafe}}{% else %}{{property.nonOptionalType|genericSafe}}{% endif %}> {
return .init(manager: cuckoo_manager, name: "{{property.name}}")
}
{% if property.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
{% for method in container.methods %}
{{ method.unavailablePlatformsCheck }}
{% for attribute in method.attributes %}
{{ attribute.text }}
{% endfor %}
func {{method.name|escapeReservedKeywords}}{{method.self|matchableGenericNames}}({{method.parameters|matchableParameterSignature}}) -> {{method.stubFunction}}<({{method.inputTypes|genericSafe}}){%if method.returnType != "Void" %}, {{method.returnType|genericSafe}}{%endif%}>{{method.self|matchableGenericWhereClause}} {
{{method.parameters|parameterMatchers}}
return .init(stub: cuckoo_manager.createStub(for: {{ container.mockName }}.self, method:
\"\"\"
{{method.fullyQualifiedName}}
\"\"\", parameterMatchers: matchers))
}
{% if method.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
}
"""
}

View File

@ -0,0 +1,13 @@
import Foundation
struct Templates { }
extension String {
func indented(times: Int = 1) -> String {
let indentation = String(repeating: " ", count: times)
return self.components(separatedBy: CharacterSet.newlines).map {
indentation + $0
}.joined(separator: "\n")
}
}

View File

@ -0,0 +1,42 @@
import Foundation
extension Templates {
static let typeErasure = """
{{ container.accessibility }} class \(typeErasureClassName){{ container.genericParameters }}: {{ container.name }} {
private let reference: Any
{% for property in container.properties %}private let _getter_storage$${{ property.name }}: () -> {{ property.type }}{% if not property.isReadOnly %}
private let _setter_storage$${{ property.name }}: ({{ property.type }}) -> Void{% endif %}
{{ container.accessibility }} var {{ property.name }}: {{ property.type }} {
get { return _getter_storage$${{ property.name }}() }{% if not property.isReadOnly %}
set { _setter_storage$${{ property.name }}(newValue) }{% endif %}
}
{% endfor %}
{# For developers: The `keeping reference: Any?` is necessary because when called from the `enableDefaultImplementation(stub:)` method
instead of `enableDefaultImplementation(mutating:)`, we need to prevent the struct getting deallocated. #}
init<\(staticGenericParameter): {{ container.name }}>(from defaultImpl: UnsafeMutablePointer<\(staticGenericParameter)>, keeping reference: @escaping @autoclosure () -> Any?) where {{ container.genericProtocolIdentity }} {
self.reference = reference
{% for property in container.properties %}_getter_storage$${{ property.name }} = { defaultImpl.pointee.{{ property.name }} }
{% if not property.isReadOnly %}_setter_storage$${{ property.name }} = { defaultImpl.pointee.{{ property.name }} = $0 }{% endif %}
{% endfor %}
{% for method in container.methods %}_storage${{ forloop.counter }}${{ method.name }} = defaultImpl.pointee.{{ method.name }}
{% endfor %}
}
{% if container.initializers %}
/// MARK:- ignored required initializers{% endif %}
{% for initializer in container.initializers %}{{ container.accessibility }} required init({{ initializer.parameterSignature }}) {
fatalError("`DefaultImplCaller` class is only used for calling default implementation and can't be initialized on its own.")
}
{% endfor %}
{% for method in container.methods %}
private let _storage${{ forloop.counter }}${{ method.name }}: ({{ method.inputTypes }}) {% if method.isAsync %} async{% endif %} -> {{ method.returnType }}
{{ container.accessibility }} func {{ method.name|escapeReservedKeywords }}({{ method.parameterSignature }}) {{ method.returnSignature }} {
return {% if method.isAsync %} await{% endif %} _storage${{ forloop.counter }}${{ method.name }}({{ method.parameterNames }})
}
{% endfor %}
}
"""
}

View File

@ -0,0 +1,48 @@
import Foundation
extension Templates {
static let verificationProxy = """
{{ container.accessibility }} struct __VerificationProxy_{{ container.name }}: Cuckoo.VerificationProxy {
private let cuckoo_manager: Cuckoo.MockManager
private let callMatcher: Cuckoo.CallMatcher
private let sourceLocation: Cuckoo.SourceLocation
{{ container.accessibility }} init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) {
self.cuckoo_manager = manager
self.callMatcher = callMatcher
self.sourceLocation = sourceLocation
}
{% for property in container.properties %}
{{ property.unavailablePlatformsCheck }}
{% for attribute in property.attributes %}
{{ attribute.text }}
{% endfor %}
var {{property.name}}: Cuckoo.{{property.verifyType}}<{% if property.isReadOnly %}{{property.type|genericSafe}}{% else %}{{property.nonOptionalType|genericSafe}}{% endif %}> {
return .init(manager: cuckoo_manager, name: "{{property.name}}", callMatcher: callMatcher, sourceLocation: sourceLocation)
}
{% if property.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
{% for method in container.methods %}
{{ method.unavailablePlatformsCheck }}
{% for attribute in method.attributes %}
{{ attribute.text }}
{% endfor %}
@discardableResult
func {{method.name|escapeReservedKeywords}}{{method.self|matchableGenericNames}}({{method.parameters|matchableParameterSignature}}) -> Cuckoo.__DoNotUse<({{method.inputTypes|genericSafe}}), {{method.returnType|genericSafe}}>{{method.self|matchableGenericWhereClause}} {
{{method.parameters|parameterMatchers}}
return cuckoo_manager.verify(
\"\"\"
{{method.fullyQualifiedName}}
\"\"\", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation)
}
{% if method.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
}
"""
}

View File

@ -0,0 +1,603 @@
import Foundation
import SourceKittenFramework
public struct Tokenizer {
private let file: File
private let source: String
private let debugMode: Bool
public init(sourceFile: File, debugMode: Bool) {
self.file = sourceFile
self.debugMode = debugMode
source = sourceFile.contents
}
public func tokenize() -> FileRepresentation {
do {
let structure = try Structure(file: file)
let declarations = tokenize(structure.dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
.flatMap { declaration -> [Token] in
guard let parent = declaration as? ParentToken else { return [declaration] }
return [parent] + parent.adoptAllYoungerGenerations()
}
let imports = tokenize(imports: declarations)
return FileRepresentation(sourceFile: file, declarations: declarations + imports)
} catch {
print("Error")
}
return FileRepresentation(sourceFile: file, declarations: [])
}
private func tokenize(_ representables: [SourceKitRepresentable]) -> [Token] {
return representables.compactMap(tokenize)
}
internal static let nameNotSet = "name not set"
internal static let unknownType = "unknown type"
private func tokenize(_ representable: SourceKitRepresentable) -> Token? {
guard let dictionary = representable as? [String: SourceKitRepresentable] else { return nil }
// Common fields
let name = dictionary[Key.Name.rawValue] as? String ?? Tokenizer.nameNotSet
let kind = dictionary[Key.Kind.rawValue] as? String ?? Tokenizer.unknownType
// Inheritance
let inheritedTypes = dictionary[Key.InheritedTypes.rawValue] as? [SourceKitRepresentable] ?? []
let tokenizedInheritedTypes = inheritedTypes.compactMap { type -> InheritanceDeclaration in
guard let typeDict = type as? [String: SourceKitRepresentable] else {
return InheritanceDeclaration.empty
}
let name = typeDict[Key.Name.rawValue] as? String ?? Tokenizer.nameNotSet
return InheritanceDeclaration(name: name)
}
// Optional fields
let range = extractRange(from: dictionary, offset: .Offset, length: .Length)
let nameRange = extractRange(from: dictionary, offset: .NameOffset, length: .NameLength)
let bodyRange = extractRange(from: dictionary, offset: .BodyOffset, length: .BodyLength)
// Attributes
let attributes = (NSOrderedSet(array: (dictionary[Key.Attributes.rawValue] as? [SourceKitRepresentable] ?? [])
.compactMap { attribute -> Attribute? in
guard let attribute = attribute as? [String: SourceKitRepresentable],
let stringKind = attribute[Key.Attribute.rawValue] as? String,
let kind = Attribute.Kind(rawValue: stringKind),
let attributeRange = extractRange(from: attribute, offset: .Offset, length: .Length) else { return nil }
let startIndex = source.utf8.index(source.utf8.startIndex, offsetBy: attributeRange.lowerBound)
let endIndex = source.utf8.index(source.utf8.startIndex, offsetBy: attributeRange.upperBound)
guard let text = String(source.utf8[startIndex..<endIndex]) else { return nil }
return Attribute(kind: kind, text: text)
}
).array as? [Attribute]) ?? []
guard !attributes.map({ $0.kind }).contains(.final) else {
if debugMode {
fputs("Cuckoo: Ignoring mocking of '\(name)' because it's marked `final`.\n", stdout)
}
return nil
}
let accessibility = (dictionary[Key.Accessibility.rawValue] as? String).flatMap { Accessibility(rawValue: $0) } ?? .Internal
let type: WrappableType?
if let stringType = dictionary[Key.TypeName.rawValue] as? String {
type = WrappableType(parsing: stringType)
} else {
type = nil
}
switch kind {
case Kinds.ProtocolDeclaration.rawValue:
let subtokens = tokenize(dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
let initializers = subtokens.only(Initializer.self)
let children = subtokens.noneOf(Initializer.self)
let genericParameters = subtokens.only(GenericParameter.self)
// FIXME: Remove when SourceKitten fixes the off-by-one error that includes the ending `>` in the last inherited type.
let fixedGenericParameters = fixSourceKittenLastGenericParameterBug(genericParameters)
return ProtocolDeclaration(
name: name,
accessibility: accessibility,
range: range!,
nameRange: nameRange!,
bodyRange: bodyRange!,
initializers: initializers,
children: children,
inheritedTypes: tokenizedInheritedTypes,
attributes: attributes,
genericParameters: fixedGenericParameters,
isNSObjectProtocol: false
)
case Kinds.ClassDeclaration.rawValue:
let subtokens = tokenize(dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
let initializers = subtokens.only(Initializer.self)
let children = subtokens.noneOf(Initializer.self).map { child -> Token in
if var property = child as? InstanceVariable {
property.overriding = true
return property
} else {
return child
}
}
let genericParameters = subtokens.only(GenericParameter.self)
// FIXME: Remove when SourceKitten fixes the off-by-one error that includes the ending `>` in the last inherited type.
let fixedGenericParameters = fixSourceKittenLastGenericParameterBug(genericParameters)
return ClassDeclaration(
name: name,
accessibility: accessibility,
range: range!,
nameRange: nameRange!,
bodyRange: bodyRange!,
initializers: initializers,
children: children,
inheritedTypes: tokenizedInheritedTypes,
attributes: attributes,
genericParameters: fixedGenericParameters
)
case Kinds.StructDeclaration.rawValue:
let subtokens = tokenize(dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
let children = subtokens.only(ContainerToken.self)
return StructDeclaration(
name: name,
accessibility: accessibility,
range: range!,
nameRange: nameRange!,
bodyRange: bodyRange!,
attributes: attributes,
children: children
)
case Kinds.ExtensionDeclaration.rawValue:
let subtokens = tokenize(dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
let children = subtokens.only(ContainerToken.self)
return ExtensionDeclaration(
name: name,
accessibility: accessibility,
range: range!,
nameRange: nameRange!,
bodyRange: bodyRange!,
attributes: attributes,
children: children
)
case Kinds.InstanceVariable.rawValue:
let setterAccessibility = (dictionary[Key.SetterAccessibility.rawValue] as? String).flatMap(Accessibility.init)
if String(source.utf8.dropFirst(range!.startIndex))?.takeUntil(occurence: name)?.trimmed.hasPrefix("let") == true {
return nil
}
let guessedType: WrappableType?
if type == nil {
guessedType = TypeGuesser.guessType(from: String(source.utf8[range!.startIndex..<range!.endIndex].drop(while: { $0 != "=" }).dropFirst()).trimmed).map { .type($0) }
} else {
guessedType = type
}
let effects: InstanceVariable.Effects
if let bodyRange = bodyRange {
effects = parseEffects(source: source.utf8[bodyRange])
} else {
effects = .init()
}
return InstanceVariable(
name: name,
type: guessedType ?? .type("__UnknownType"),
accessibility: accessibility,
setterAccessibility: setterAccessibility,
effects: effects,
range: range!,
nameRange: nameRange!,
overriding: false,
attributes: attributes
)
case Kinds.InstanceMethod.rawValue:
let genericParameters = tokenize(dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? []).only(GenericParameter.self)
let parameters = tokenize(methodName: name, parameters: dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
let returnSignature: ReturnSignature
if let bodyRange = bodyRange {
returnSignature = parseReturnSignature(source: source.utf8[nameRange!.endIndex..<bodyRange.startIndex].takeUntil(occurence: "{")?.trimmed ?? "")
} else {
returnSignature = parseReturnSignature(source: source.utf8[nameRange!.endIndex..<range!.endIndex].trimmed)
}
// methods can specify an empty public name of a parameter without any private name - `fun(_: String)`
let namedParameters = parameters.enumerated().map { index, parameter -> MethodParameter in
if parameter.name == Tokenizer.nameNotSet {
var mutableParameter = parameter
mutableParameter.name = "parameter\(index)"
return mutableParameter
} else {
return parameter
}
}
// FIXME: Remove when SourceKit fixes the off-by-one error that includes the ending `>` in the last inherited type.
let fixedGenericParameters = fixSourceKittenLastGenericParameterBug(genericParameters)
// When bodyRange != nil, we need to create `ClassMethod` instead of `ProtocolMethod`
if let bodyRange = bodyRange {
return ClassMethod(
name: name,
accessibility: accessibility,
returnSignature: returnSignature,
range: range!,
nameRange: nameRange!,
parameters: namedParameters,
bodyRange: bodyRange,
attributes: attributes,
genericParameters: fixedGenericParameters
)
} else {
return ProtocolMethod(
name: name,
accessibility: accessibility,
returnSignature: returnSignature,
range: range!,
nameRange: nameRange!,
parameters: namedParameters,
attributes: attributes,
genericParameters: fixedGenericParameters
)
}
case Kinds.GenericParameter.rawValue:
return tokenize(parameterLabel: nil, parameter: representable)
case Kinds.AssociatedType.rawValue:
let regex = try! NSRegularExpression(pattern: "\\s*:\\s*([^\\s;\\/]+)")
guard let range = range else { return nil }
guard let inheritanceMatch = regex.firstMatch(
in: source,
range: NSMakeRange(range.startIndex, range.endIndex - range.startIndex)) else {
return GenericParameter(name: name, range: range, inheritedType: nil)
}
let inheritanceRange = inheritanceMatch.range(at: 1)
let fromIndex = source.index(source.startIndex, offsetBy: inheritanceRange.location)
let toIndex = source.index(fromIndex, offsetBy: inheritanceRange.length)
let inheritance = String(source[fromIndex..<toIndex])
let fullRange = range.lowerBound..<(range.upperBound + inheritanceMatch.range.length)
return GenericParameter(
name: name,
range: fullRange,
inheritedType: InheritanceDeclaration(name: inheritance)
)
default:
// Do not log anything, until the parser contains all known cases.
// stderrPrint("Unknown kind. Dictionary: \(dictionary) \(file.path ?? "")")
return nil
}
}
private func tokenize(methodName: String, parameters: [SourceKitRepresentable]) -> [MethodParameter] {
// Takes the string between `(` and `)`
let parameterNames = methodName.components(separatedBy: "(").last?.dropLast(1).map { "\($0)" }.joined(separator: "")
var parameterLabels: [String?] = parameterNames?.components(separatedBy: ":").map { $0 != "_" ? $0 : nil } ?? []
// Last element is not type.
parameterLabels = Array(parameterLabels.dropLast())
// Substructure can contain some other information after the parameters.
let filteredParameters = parameters.filter {
let dictionary = $0 as? [String: SourceKitRepresentable]
let kind = dictionary?[Key.Kind.rawValue] as? String ?? ""
return kind == Kinds.MethodParameter.rawValue
}
return zip(parameterLabels, filteredParameters).compactMap { tokenize(parameterLabel: $0, parameter: $1) as? MethodParameter }
}
private func tokenize(parameterLabel: String?, parameter: SourceKitRepresentable) -> Token? {
guard let dictionary = parameter as? [String: SourceKitRepresentable] else { return nil }
let name = dictionary[Key.Name.rawValue] as? String ?? Tokenizer.nameNotSet
let kind = dictionary[Key.Kind.rawValue] as? String ?? Tokenizer.unknownType
let range = extractRange(from: dictionary, offset: .Offset, length: .Length)
let nameRange = extractRange(from: dictionary, offset: .NameOffset, length: .NameLength)
let type = dictionary[Key.TypeName.rawValue] as? String
switch kind {
case Kinds.MethodParameter.rawValue:
// separate `inout` from the type and remember that the parameter is inout
let type = type!
// we want to remove `inout` and remember it, but we don't want to affect a potential `inout` closure parameter
let inoutSeparatedType: String
let isInout: Bool
if let inoutRange = type.range(of: "inout ") {
if let closureParenIndex = type.firstIndex(of: "("), closureParenIndex < inoutRange.upperBound {
inoutSeparatedType = type
isInout = false
} else {
var mutableString = type
mutableString.removeSubrange(inoutRange)
inoutSeparatedType = mutableString
isInout = true
}
} else {
inoutSeparatedType = type
isInout = false
}
let wrappableType = WrappableType(parsing: inoutSeparatedType)
return MethodParameter(label: parameterLabel, name: name, type: wrappableType, range: range!, nameRange: nameRange, isInout: isInout)
case Kinds.GenericParameter.rawValue:
let inheritedTypeElement = (dictionary[Key.InheritedTypes.rawValue] as? [SourceKitRepresentable] ?? []).first
let inheritedType = (inheritedTypeElement as? [String: SourceKitRepresentable] ?? [:])[Key.Name.rawValue] as? String
let inheritanceDeclaration: InheritanceDeclaration?
if let inheritedType = inheritedType {
inheritanceDeclaration = .init(name: inheritedType)
} else {
inheritanceDeclaration = nil
}
return GenericParameter(name: name, range: range!, inheritedType: inheritanceDeclaration)
default:
stderrPrint("Unknown method parameter. Dictionary: \(dictionary) \(file.path ?? "")")
return nil
}
}
private func tokenize(imports otherTokens: [Token]) -> [Token] {
let rangesToIgnore: [CountableRange<Int>] = otherTokens.compactMap { token in
switch token {
case let container as ContainerToken:
return container.range
case let extensionToken as ExtensionDeclaration:
return extensionToken.range
default:
return nil
}
}
do {
let baseRegex = "(?:\\b|;)import(?:\\s|(?:\\/\\/.*\\n)|(?:\\/\\*.*\\*\\/))+"
let identifierRegex = "[^\\s;\\/]+"
let libraryImportRegex = baseRegex + "(\(identifierRegex))(?:\\n|(?:\\s)*;)"
let componentImportRegex = baseRegex + "(\(identifierRegex))\\s+(\(identifierRegex))\\.(\(identifierRegex))"
let libraryRegex = try NSRegularExpression(pattern: libraryImportRegex)
let componentRegex = try NSRegularExpression(pattern: componentImportRegex)
let librariesRange = NSRange(location: 0, length: source.count)
let libraries = libraryRegex.matches(in: source, range: librariesRange)
.filter { result in
rangesToIgnore.filter { $0 ~= result.range.location }.isEmpty
}
.map { result -> Import in
let range = result.range.location..<(result.range.location + result.range.length)
let library = source.stringMatch(from: result, at: 1)
return Import(range: range, importee: .library(name: library))
}
let components = componentRegex.matches(in: source, range: NSRange(location: 0, length: source.count))
.filter { result in
rangesToIgnore.filter { $0 ~= result.range.location }.isEmpty
}
.map { result -> Import in
let componentRange = result.range(at: 1)
let componentType = componentRange.location == NSNotFound ? nil : source[componentRange]
let library = source[result.range(at: 2)]
let component = source[result.range(at: 3)]
let range = result.range.location..<(result.range.location + result.range.length)
return Import(range: range, importee: .component(componentType: componentType, library: library, name: component))
}
return libraries + components
} catch let error as NSError {
fatalError("Invalid regex:" + error.description)
}
}
private func getReturnType(source: String, index: inout String.Index) -> String {
var returnType = ""
var afterArrow = true
var parenLevel = 0
while index != source.endIndex {
let character = source[index]
switch character {
case "(", "<", "[":
parenLevel += 1
returnType.append(character)
index = source.index(after: index)
case ")", ">", "]":
parenLevel -= 1
returnType.append(character)
index = source.index(after: index)
case "-":
index = source.index(after: index)
// just a little sanity check
guard source[index] == ">" else { fatalError("Uhh, what.") }
index = source.index(after: index)
returnType.append(" -> ")
afterArrow = true
case " ":
index = source.index(after: index)
returnType.append(character)
case "w":
let previousCharacter = source[source.index(before: index)]
guard parenLevel == 0 && !afterArrow && previousCharacter == " " else {
returnType.append(character)
index = source.index(after: index)
continue
}
// we reached the "where" clause
return returnType
default:
afterArrow = false
returnType.append(character)
index = source.index(after: index)
}
}
return returnType
}
/// - returns: the where constraints parsed from the where clause
private func parseWhereClause(source: String, index: inout String.Index) -> [String] {
var whereConstraints = [] as [String]
var currentConstraint = ""
var parenLevel = 0
while index != source.endIndex {
let character = source[index]
switch character {
case "(", "<", "[":
parenLevel += 1
currentConstraint.append(character)
case ")", ">", "]":
parenLevel -= 1
currentConstraint.append(character)
case "," where parenLevel == 0:
currentConstraint = currentConstraint.trimmed
whereConstraints.append(currentConstraint)
currentConstraint = ""
default:
currentConstraint.append(character)
}
index = source.index(after: index)
}
if !currentConstraint.isEmpty {
currentConstraint = currentConstraint.trimmed
whereConstraints.append(currentConstraint)
}
return whereConstraints
}
/// - parameter source: A trimmed string containing only the method return signature excluding the trailing brace
/// - returns: ReturnSignature structure containing the parsed throwString, return type, and where constraints
private func parseReturnSignature(source: String) -> ReturnSignature {
var isAsync = false
var throwString = nil as String?
var returnType: WrappableType?
var whereConstraints = [] as [String]
var index = source.startIndex
parseLoop: while index != source.endIndex {
let character = source[index]
switch character {
case "a":
isAsync = true
let asyncString = "async"
index = source.index(index, offsetBy: asyncString.count)
continue
case "r" where returnType == nil:
throwString = "rethrows"
index = source.index(index, offsetBy: throwString!.count)
continue
case "t" where returnType == nil:
throwString = "throws"
index = source.index(index, offsetBy: throwString!.count)
continue
case "w":
index = source.index(index, offsetBy: "where".count)
whereConstraints = parseWhereClause(source: source, index: &index)
// the where clause is the last thing in method signature, so we'll just stop the parsing
break parseLoop
case "-":
index = source.index(after: index)
guard source[index] == ">" else { fatalError("Uhh, what.") }
index = source.index(after: index)
returnType = WrappableType(parsing: getReturnType(source: source, index: &index).trimmed)
continue
default:
break
}
index = source.index(after: index)
}
return ReturnSignature(isAsync: isAsync, throwString: throwString, returnType: returnType ?? WrappableType.type("Void"), whereConstraints: whereConstraints)
}
private func parseEffects(source: String) -> InstanceVariable.Effects {
var effects = InstanceVariable.Effects()
let trimmed = source.drop(while: { $0.isWhitespace })
guard trimmed.hasPrefix("get") else { return effects }
let afterGet = trimmed.dropFirst("get".count).drop(while: { $0.isWhitespace })
var index = afterGet.startIndex
parseLoop: while index != afterGet.endIndex {
let character = afterGet[index]
switch character {
case "a":
effects.isAsync = true
index = source.index(index, offsetBy: "async".count)
case "t":
effects.isThrowing = true
index = source.index(index, offsetBy: "throws".count)
case let c where c.isWhitespace:
break
default:
break parseLoop
}
index = source.index(after: index)
}
return effects
}
// FIXME: Remove when SourceKitten fixes the off-by-one error that includes the ending `>` in the last inherited type.
private func fixSourceKittenLastGenericParameterBug(_ genericParameters: [GenericParameter]) -> [GenericParameter] {
let fixedGenericParameters: [GenericParameter]
if let lastGenericParameter = genericParameters.last,
let inheritedType = lastGenericParameter.inheritedType,
inheritedType.name.hasSuffix(">>") == true {
fixedGenericParameters = genericParameters.dropLast() + [
GenericParameter(
name: lastGenericParameter.name,
range: lastGenericParameter.range.lowerBound..<lastGenericParameter.range.upperBound - 1,
inheritedType: InheritanceDeclaration(name: String(inheritedType.name.dropLast()))
)
]
} else {
fixedGenericParameters = genericParameters
}
return fixedGenericParameters
}
}
extension String {
subscript(range: NSRange) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: range.location)
let toIndex = self.index(fromIndex, offsetBy: range.length)
return String(self[fromIndex..<toIndex])
}
}
extension String {
func stringMatch(from match: NSTextCheckingResult, at range: Int = 0) -> String {
let matchRange = match.range(at: range)
let fromIndex = index(startIndex, offsetBy: matchRange.location)
let toIndex = index(fromIndex, offsetBy: matchRange.length)
return String(self[fromIndex..<toIndex])
}
func removing(match: NSTextCheckingResult, at range: Int = 0) -> String {
let matchRange = match.range(at: range)
let fromIndex = index(startIndex, offsetBy: matchRange.location)
let toIndex = index(fromIndex, offsetBy: matchRange.length)
var mutableString = self
mutableString.removeSubrange(fromIndex..<toIndex)
return mutableString
}
}

View File

@ -1,11 +1,3 @@
//
// Accessibility.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public enum Accessibility: String {
case Open = "source.lang.swift.accessibility.open"
case Public = "source.lang.swift.accessibility.public"
@ -32,3 +24,25 @@ public enum Accessibility: String {
return self != .Private && self != .FilePrivate
}
}
extension Accessibility: Comparable {
/// How open is this accessibility. The higher number the more accessible.
private var openness: Int {
switch self {
case .Open:
return 4
case .Public:
return 3
case .Internal:
return 2
case .FilePrivate:
return 1
case .Private:
return 0
}
}
public static func < (lhs: Accessibility, rhs: Accessibility) -> Bool {
return lhs.openness < rhs.openness
}
}

View File

@ -0,0 +1,60 @@
import Foundation
public struct Attribute: Hashable {
public enum Kind: String, Hashable {
case objc = "source.decl.attribute.objc"
case optional = "source.decl.attribute.optional"
case lazy = "source.decl.attribute.lazy"
case required = "source.decl.attribute.required"
case override = "source.decl.attribute.override"
case convenience = "source.decl.attribute.convenience"
case weak = "source.decl.attribute.weak"
case ibAction = "source.decl.attribute.ibaction"
case ibOutlet = "source.decl.attribute.iboutlet"
case available = "source.decl.attribute.available"
case final = "source.decl.attribute.final"
}
public var kind: Kind
public var text: String
public var isSupported: Bool {
switch (kind) {
case .objc, .optional, .lazy, .required, .override, .convenience, .weak, .ibAction, .ibOutlet, .final:
return false
case .available:
return true
}
}
public var unavailablePlatform: String? {
guard kind == .available,
text.hasPrefix("@available(") else {
return nil
}
let parameters = text
.dropFirst("@available(".count)
.dropLast()
.split(separator: ",")
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
guard parameters.count >= 2,
parameters[1] == "unavailable" else {
return nil
}
return String(parameters[0])
}
}
extension Attribute: Token {
public func isEqual(to other: Token) -> Bool {
guard let otherAttribute = other as? Attribute else { return false }
return self.kind == otherAttribute.kind && self.text == otherAttribute.text
}
public func serialize() -> [String : Any] {
return ["text": text]
}
}

View File

@ -0,0 +1,5 @@
import Foundation
public protocol ChildToken: Token {
var parent: Reference<ParentToken>? { get set }
}

View File

@ -0,0 +1,37 @@
public struct ClassDeclaration: ContainerToken, HasAccessibility {
public let implementation: Bool = true
public var name: String
public var parent: Reference<ParentToken>?
public var accessibility: Accessibility
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var bodyRange: CountableRange<Int>
public var initializers: [Initializer]
public var children: [Token]
public var inheritedTypes: [InheritanceDeclaration]
public var attributes: [Attribute]
public var genericParameters: [GenericParameter]
public var hasNoArgInit: Bool {
return initializers.filter { $0.parameters.isEmpty }.isEmpty
}
public func replace(children tokens: [Token]) -> ClassDeclaration {
return ClassDeclaration(
name: self.name,
parent: self.parent,
accessibility: self.accessibility,
range: self.range,
nameRange: self.nameRange,
bodyRange: self.bodyRange,
initializers: self.initializers,
children: tokens,
inheritedTypes: self.inheritedTypes,
attributes: self.attributes,
genericParameters: self.genericParameters)
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? ClassDeclaration else { return false }
return self.name == other.name
}
}

View File

@ -0,0 +1,17 @@
public struct ClassMethod: Method {
public var name: String
public var accessibility: Accessibility
public var returnSignature: ReturnSignature
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var parameters: [MethodParameter]
public var bodyRange: CountableRange<Int>
public var attributes: [Attribute]
public var genericParameters: [GenericParameter]
public var isOptional: Bool {
return false
}
public var isOverriding: Bool {
return true
}
}

View File

@ -0,0 +1,63 @@
public protocol ContainerToken: ParentToken, ChildToken {
var initializers: [Initializer] { get }
var implementation: Bool { get }
var inheritedTypes: [InheritanceDeclaration] { get }
var genericParameters: [GenericParameter] { get }
}
extension ContainerToken {
public func serialize() -> [String : Any] {
func withAdjustedAccessibility(token: Token & HasAccessibility) -> Token & HasAccessibility {
// We only want to adjust tokens that are accessible and lower than the enclosing type
guard token.accessibility.isAccessible && token.accessibility < accessibility else { return token }
var mutableToken = token
mutableToken.accessibility = accessibility
return mutableToken
}
let accessibilityAdjustedChildren = children.map { child -> Token in
guard let childWithAccessibility = child as? HasAccessibility & Token else { return child }
return withAdjustedAccessibility(token: childWithAccessibility)
}
let properties = accessibilityAdjustedChildren.compactMap { $0 as? InstanceVariable }
.filter { $0.accessibility.isAccessible }
.map { $0.serializeWithType() }
let methods = accessibilityAdjustedChildren.compactMap { $0 as? Method }
.filter { $0.accessibility.isAccessible && !$0.isInit && !$0.isDeinit }
.map { $0.serializeWithType() }
let initializers = accessibilityAdjustedChildren.compactMap { $0 as? Method }
.filter { $0.accessibility.isAccessible && $0.isInit && !$0.isDeinit }
.map { $0.serializeWithType() }
let genericParametersString = genericParameters.map { $0.description }.joined(separator: ", ")
let genericArgumentsString = genericParameters.map { $0.name }.joined(separator: ", ")
let genericProtocolIdentity = genericParameters.map { "\(Templates.staticGenericParameter).\($0.name) == \($0.name)" }.joined(separator: ", ")
let isGeneric = !genericParameters.isEmpty
return [
"name": name,
"accessibility": accessibility.sourceName,
"isAccessible": accessibility.isAccessible,
"hasParent": parent != nil,
"parentFullyQualifiedName": parent?.fullyQualifiedName ?? "",
"children": accessibilityAdjustedChildren.map { $0.serializeWithType() },
"properties": properties,
"methods": methods,
"initializers": implementation ? [] : initializers,
"isImplementation": implementation,
"mockName": "Mock\(name)",
"inheritedTypes": inheritedTypes,
"attributes": attributes.filter { $0.isSupported },
"hasUnavailablePlatforms": hasUnavailablePlatforms,
"unavailablePlatformsCheck": unavailablePlatformsCheck,
"isGeneric": isGeneric,
"genericParameters": isGeneric ? "<\(genericParametersString)>" : "",
"genericArguments": isGeneric ? "<\(genericArgumentsString)>" : "",
"genericProtocolIdentity": genericProtocolIdentity,
"isNSObjectProtocol": (self as? ProtocolDeclaration)?.isNSObjectProtocol ?? false
]
}
}

View File

@ -0,0 +1,15 @@
public struct ExtensionDeclaration: ParentToken {
// TODO Implement support for extensions
public let name: String
public var accessibility: Accessibility
public let range: CountableRange<Int>
public let nameRange: CountableRange<Int>
public let bodyRange: CountableRange<Int>
public var attributes: [Attribute]
public let children: [Token]
public func isEqual(to other: Token) -> Bool {
guard let other = other as? ExtensionDeclaration else { return false }
return self.range == other.range
}
}

View File

@ -0,0 +1,71 @@
import SourceKittenFramework
public struct FileRepresentation {
public let sourceFile: File
public let declarations: [Token]
public init(sourceFile: File, declarations: [Token]) {
self.sourceFile = sourceFile
self.declarations = declarations
}
}
public extension FileRepresentation {
func mergeInheritance(with files: [FileRepresentation]) -> FileRepresentation {
let tokens = self.declarations.reduce([Token]()) { list, token in
let mergeToken = token.mergeInheritance(with: files)
return list + [mergeToken]
}
return FileRepresentation(sourceFile: self.sourceFile, declarations: tokens)
}
func inheritNSObject(subjects: [ProtocolDeclaration]) -> FileRepresentation {
FileRepresentation(sourceFile: self.sourceFile, declarations: self.declarations.map { $0.inheritNSObject(subjects: subjects) })
}
}
extension Token {
func mergeInheritance(with files: [FileRepresentation]) -> Token {
guard let typeToken = self as? ContainerToken else {
return self
}
let inheritedRepresentations: [Token] = typeToken.inheritedTypes
.compactMap { Self.findToken(forClassOrProtocol: $0.name, in: files) }
.compactMap { $0.mergeInheritance(with: files) }
// Merge super declarations
let mergedTokens = inheritedRepresentations.filter { $0.isClassOrProtocolDeclaration }
.map { $0 as! ContainerToken }
.flatMap { $0.children }
.reduce(typeToken.children) { tokens, inheritedToken in
if tokens.contains(where: { $0 == inheritedToken }) {
return tokens
}
return tokens + [inheritedToken]
}
switch typeToken {
case let classToken as ClassDeclaration:
return classToken.replace(children: mergedTokens)
case let protocolToken as ProtocolDeclaration:
return protocolToken.replace(children: mergedTokens)
default:
return typeToken
}
}
func inheritNSObject(subjects: [ProtocolDeclaration]) -> Token {
guard let protocolToken = self as? ProtocolDeclaration else {
return self
}
return subjects.contains { $0.name == protocolToken.name } ? protocolToken.replace(isNSObjectProtocol: true) : self
}
static func findToken(forClassOrProtocol name: String, in files: [FileRepresentation]) -> Token? {
return files.flatMap { $0.declarations }
.filter { $0.isClassOrProtocolDeclaration }
.map { $0 as! ContainerToken }
.first { $0.name == name }
}
}

View File

@ -0,0 +1,24 @@
import Foundation
public struct GenericParameter: Token {
public let name: String
public let range: CountableRange<Int>
public let inheritedType: InheritanceDeclaration?
public var description: String {
let hasInheritedType = inheritedType != nil
return "\(name)\(hasInheritedType ? ": " : "")\(inheritedType?.name ?? "")"
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? GenericParameter else { return false }
return self.name == other.name && self.range == other.range && self.inheritedType?.name == other.inheritedType?.name
}
public func serialize() -> [String : Any] {
return [
"name": name,
"inheritedType": inheritedType,
]
}
}

View File

@ -0,0 +1,5 @@
import Foundation
public protocol HasAccessibility {
var accessibility: Accessibility { get set }
}

View File

@ -0,0 +1,19 @@
import Foundation
public protocol HasAttributes {
var attributes: [Attribute] { get }
}
extension HasAttributes {
private var unavailablePlatforms: [String] {
return attributes.lazy.compactMap { $0.unavailablePlatform }
}
var hasUnavailablePlatforms: Bool {
return !unavailablePlatforms.isEmpty
}
var unavailablePlatformsCheck: String {
return hasUnavailablePlatforms ? "#if !os(\(unavailablePlatforms.joined(separator: ") && !os(")))" : ""
}
}

View File

@ -0,0 +1,30 @@
public struct Import: Token {
public enum Importee: CustomStringConvertible {
case library(name: String)
case component(componentType: String?, library: String, name: String)
public var description: String {
switch self {
case .library(let name):
return name
case .component(let componentType, let library, let name):
return [componentType, "\(library).\(name)"].compactMap { $0 }.joined(separator: " ")
}
}
}
public let range: CountableRange<Int>
public let importee: Importee
public func isEqual(to other: Token) -> Bool {
guard let other = other as? Import, self.range == other.range else { return false }
switch (self.importee, other.importee) {
case (.library(let lhsName), .library(let rhsName)):
return lhsName == rhsName
case (.component(let lhsImportType, let lhsLibrary, let lhsName), .component(let rhsImportType, let rhsLibrary, let rhsName)):
return lhsImportType == rhsImportType && lhsLibrary == rhsLibrary && lhsName == rhsName
default:
return false
}
}
}

View File

@ -1,11 +1,3 @@
//
// InheritanceDeclaration.swift
// CuckooGenerator
//
// Created by Arjan Duijzer on 22/02/2017.
// Copyright (c) 2017 Brightify. All rights reserved.
//
public struct InheritanceDeclaration: Token {
public static let empty = InheritanceDeclaration(name: Tokenizer.nameNotSet)
public let name: String
@ -14,4 +6,4 @@ public struct InheritanceDeclaration: Token {
guard let other = other as? InheritanceDeclaration else { return false }
return self.name == other.name
}
}
}

View File

@ -0,0 +1,17 @@
public struct Initializer: Method, HasAccessibility {
public var name: String
public var accessibility: Accessibility
public var returnType: WrappableType
public var returnSignature: ReturnSignature
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var parameters: [MethodParameter]
public var isOverriding: Bool
public var required: Bool
public var attributes: [Attribute]
public var genericParameters: [GenericParameter]
public var isOptional: Bool {
return false
}
}

View File

@ -0,0 +1,51 @@
public struct InstanceVariable: Token, HasAccessibility, HasAttributes {
public struct Effects {
public var isThrowing = false
public var isAsync = false
}
public var name: String
public var type: WrappableType
public var accessibility: Accessibility
public var setterAccessibility: Accessibility?
public var effects: Effects
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var overriding: Bool
public var attributes: [Attribute]
public var readOnly: Bool {
if let setterAccessibility = setterAccessibility {
return !setterAccessibility.isAccessible
} else {
return true
}
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? InstanceVariable else { return false }
return self.name == other.name
}
public func serialize() -> [String : Any] {
let readOnlyVerifyString = readOnly ? "ReadOnly" : ""
let readOnlyStubString = effects.isThrowing ? "" : readOnlyVerifyString
let optionalString = type.isOptional && !readOnly ? "Optional" : ""
let throwingString = effects.isThrowing ? "Throwing" : ""
return [
"name": name,
"type": type.sugarized,
"nonOptionalType": type.unoptionaled.sugarized,
"accessibility": accessibility.sourceName,
"isReadOnly": readOnly,
"isAsync": effects.isAsync,
"isThrowing": effects.isThrowing,
"stubType": (overriding ? "Class" : "Protocol") + "ToBeStubbed\(readOnlyStubString)\(optionalString)\(throwingString)Property",
"verifyType": "Verify\(readOnlyVerifyString)\(optionalString)Property",
"attributes": attributes.filter { $0.isSupported },
"hasUnavailablePlatforms": hasUnavailablePlatforms,
"unavailablePlatformsCheck": unavailablePlatformsCheck,
]
}
}

View File

@ -1,11 +1,3 @@
//
// Key.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public enum Key: String {
case Substructure = "key.substructure"
case Kind = "key.kind"

View File

@ -1,17 +1,12 @@
//
// Kinds.swift
// CuckooGenerator
//
// Created by Filip Dolnik on 30.05.16.
// Copyright © 2016 Brightify. All rights reserved.
//
public enum Kinds: String {
case ProtocolDeclaration = "source.lang.swift.decl.protocol"
case InstanceMethod = "source.lang.swift.decl.function.method.instance"
case MethodParameter = "source.lang.swift.decl.var.parameter"
case ClassDeclaration = "source.lang.swift.decl.class"
case StructDeclaration = "source.lang.swift.decl.struct"
case ExtensionDeclaration = "source.lang.swift.decl.extension"
case InstanceVariable = "source.lang.swift.decl.var.instance"
case GenericParameter = "source.lang.swift.decl.generic_type_param"
case AssociatedType = "source.lang.swift.decl.associatedtype"
case Optional = "source.decl.attribute.optional"
}

View File

@ -0,0 +1,158 @@
import Foundation
public protocol Method: Token, HasAccessibility, HasAttributes {
var name: String { get }
var returnSignature: ReturnSignature { get }
var range: CountableRange<Int> { get }
var nameRange: CountableRange<Int> { get }
var parameters: [MethodParameter] { get }
var isOptional: Bool { get }
var isOverriding: Bool { get }
var hasClosureParams: Bool { get }
var hasOptionalParams: Bool { get }
var genericParameters: [GenericParameter] { get }
}
public extension Method {
var rawName: String {
return name.takeUntil(occurence: "(") ?? ""
}
var isInit: Bool {
return rawName == "init"
}
var isDeinit: Bool {
return rawName == "deinit"
}
var fullyQualifiedName: String {
let parameterTypes = parameters.map { ($0.isInout ? "inout " : "") + $0.type.sugarized }
let nameParts = name.components(separatedBy: ":")
let lastNamePart = nameParts.last ?? ""
let returnSignatureDescription = returnSignature.description
let returnSignatureString = returnSignatureDescription.isEmpty ? "" : " \(returnSignatureDescription)"
return zip(nameParts.dropLast(), parameterTypes)
.map { $0 + ": " + $1 }
.joined(separator: ", ") + lastNamePart + returnSignatureString
}
var isAsync: Bool {
return returnSignature.isAsync
}
var isThrowing: Bool {
guard let throwType = returnSignature.throwType else { return false }
return throwType.isThrowing || throwType.isRethrowing
}
var returnType: WrappableType {
return returnSignature.returnType
}
var hasClosureParams: Bool {
return parameters.contains { $0.isClosure }
}
var hasOptionalParams: Bool {
return parameters.contains { $0.isOptional }
}
func isEqual(to other: Token) -> Bool {
guard let other = other as? Method else { return false }
return self.name == other.name && self.parameters == other.parameters && self.returnType == other.returnType
}
func serialize() -> [String : Any] {
let call = parameters.map {
let name = escapeReservedKeywords(for: $0.name)
let referencedName = "\($0.isInout ? "&" : "")\(name)\($0.isAutoClosure ? "()" : "")"
if let label = $0.label {
return "\(label): \(referencedName)"
} else {
return referencedName
}
}.joined(separator: ", ")
let stubFunctionPrefix = isOverriding ? "Class" : "Protocol"
let returnString = returnType.sugarized == "Void" ? "NoReturn" : ""
let throwingString = isThrowing ? "Throwing" : ""
let stubFunction = "Cuckoo.\(stubFunctionPrefix)Stub\(returnString)\(throwingString)Function"
let escapingParameterNames = parameters.map { parameter in
if parameter.isClosure && !parameter.isEscaping {
let parameterCount = parameter.closureParamCount
let parameterSignature = parameterCount > 0 ? (1...parameterCount).map { _ in "_" }.joined(separator: ", ") : "()"
// FIXME: Instead of parsing the closure return type here, Tokenizer should do it and pass the information in a data structure
let returnSignature: String
let closureReturnType = extractClosureReturnType(parameter: parameter.type.sugarized)
if let closureReturnType = closureReturnType, !closureReturnType.isEmpty && closureReturnType != "Void" {
returnSignature = " -> " + closureReturnType
} else {
returnSignature = ""
}
return "{ \(parameterSignature)\(returnSignature) in fatalError(\"This is a stub! It's not supposed to be called!\") }"
} else {
return escapeReservedKeywords(for: parameter.name)
}
}.joined(separator: ", ")
let genericParametersString = genericParameters.map { $0.description }.joined(separator: ", ")
let isGeneric = !genericParameters.isEmpty
return [
"self": self,
"name": rawName,
"accessibility": accessibility.sourceName,
"returnSignature": returnSignature.description,
"parameters": parameters,
"parameterNames": parameters.map { escapeReservedKeywords(for: $0.name) }.joined(separator: ", "),
"escapingParameterNames": escapingParameterNames,
"isInit": isInit,
"returnType": returnType.explicitOptionalOnly.sugarized,
"isAsync": isAsync,
"isThrowing": isThrowing,
"throwType": returnSignature.throwType?.description ?? "",
"fullyQualifiedName": fullyQualifiedName,
"call": call,
"isOverriding": isOverriding,
"parameterSignature": parameters.map { "\($0.labelAndName): \($0.isInout ? "inout " : "")\($0.type)" }.joined(separator: ", "),
"parameterSignatureWithoutNames": parameters.map { "\($0.name): \($0.type)" }.joined(separator: ", "),
"argumentSignature": parameters.map { $0.type.description }.joined(separator: ", "),
"stubFunction": stubFunction,
"inputTypes": parameters.map { $0.typeWithoutAttributes }.joined(separator: ", "),
"isOptional": isOptional,
"hasClosureParams": hasClosureParams,
"hasOptionalParams": hasOptionalParams,
"attributes": attributes.filter { $0.isSupported },
"hasUnavailablePlatforms": hasUnavailablePlatforms,
"unavailablePlatformsCheck": unavailablePlatformsCheck,
"genericParameters": isGeneric ? "<\(genericParametersString)>" : "",
]
}
private func extractClosureReturnType(parameter: String) -> String? {
var parenLevel = 0
for i in 0..<parameter.count {
let index = parameter.index(parameter.startIndex, offsetBy: i)
let character = parameter[index]
if character == "(" {
parenLevel += 1
} else if character == ")" {
parenLevel -= 1
if parenLevel == 0 {
let returnSignature = String(parameter[parameter.index(after: index)..<parameter.endIndex])
let regex = try! NSRegularExpression(pattern: "\\s*->\\s*(.*)\\s*")
guard let result = regex.matches(in: returnSignature, range: NSRange(location: 0, length: returnSignature.count)).first else { return nil }
return returnSignature[result.range(at: 1)]
}
}
}
return nil
}
}

View File

@ -0,0 +1,83 @@
public struct MethodParameter: Token, Equatable {
public var label: String?
public var name: String
public var type: WrappableType
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>?
public var isInout: Bool
public var labelAndName: String {
if let label = label {
return label != name ? "\(label) \(name)" : name
} else {
return "_ \(name)"
}
}
public var typeWithoutAttributes: String {
return type.withoutAttributes.sugarized.trimmed
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? MethodParameter else { return false }
return label == other.label && type == other.type
}
public var isClosure: Bool {
return typeWithoutAttributes.hasPrefix("(") && typeWithoutAttributes.range(of: "->") != nil
}
public var isAutoClosure: Bool {
type.containsAttribute(named: "@autoclosure")
}
public var isOptional: Bool {
return type.isOptional
}
public var closureParamCount: Int {
// make sure that the parameter is a closure and that it's not just an empty `() -> ...` closure
guard isClosure && !"^\\s*\\(\\s*\\)".regexMatches(typeWithoutAttributes) else { return 0 }
var parenLevel = 0
var parameterCount = 1
for character in typeWithoutAttributes {
switch character {
case "(", "<":
parenLevel += 1
case ")", ">":
parenLevel -= 1
case ",":
parameterCount += parenLevel == 1 ? 1 : 0
default:
break
}
if parenLevel == 0 {
break
}
}
return parameterCount
}
public var isEscaping: Bool {
return isClosure && (type.containsAttribute(named: "@escaping") || type.isOptional)
}
public func serialize() -> [String : Any] {
return [
"label": label ?? "",
"name": name,
"type": type,
"labelAndName": labelAndName,
"typeWithoutAttributes": typeWithoutAttributes,
"isClosure": isClosure,
"isOptional": isOptional,
"isEscaping": isEscaping
]
}
}
public func ==(lhs: MethodParameter, rhs: MethodParameter) -> Bool {
return lhs.isEqual(to: rhs)
}

View File

@ -0,0 +1,43 @@
import Foundation
public protocol ParentToken: Token, HasAccessibility, HasAttributes {
var name: String { get }
var range: CountableRange<Int> { get }
var nameRange: CountableRange<Int> { get }
var bodyRange: CountableRange<Int> { get }
var children: [Token] { get }
}
extension ParentToken {
var fullyQualifiedName: String {
var names = [name]
var parent: ParentToken? = (self as? ChildToken)?.parent?.value
while let p = parent {
names.insert(p.name, at: 0)
parent = (p as? ChildToken)?.parent?.value
}
return names.joined(separator: ".")
}
var areAllHierarchiesAccessible: Bool {
guard accessibility.isAccessible else { return false }
var parent: ParentToken? = (self as? ChildToken)?.parent?.value
while let p = parent {
guard p.accessibility.isAccessible else { return false }
parent = (p as? ChildToken)?.parent?.value
}
return true
}
func adoptAllYoungerGenerations() -> [ParentToken] {
let parentReference: Reference<ParentToken> = Reference(value: self)
return children
.compactMap { child -> ParentToken? in
guard var c = child as? ContainerToken else { return nil }
c.parent = parentReference
return c
}
.flatMap { [$0] + $0.adoptAllYoungerGenerations() }
}
}

View File

@ -0,0 +1,54 @@
public struct ProtocolDeclaration: ContainerToken, HasAccessibility {
public let implementation: Bool = false
public var name: String
public var parent: Reference<ParentToken>?
public var accessibility: Accessibility
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var bodyRange: CountableRange<Int>
public var initializers: [Initializer]
public var children: [Token]
public var inheritedTypes: [InheritanceDeclaration]
public var attributes: [Attribute]
public var genericParameters: [GenericParameter]
public var isNSObjectProtocol: Bool
public func replace(children tokens: [Token]) -> ProtocolDeclaration {
return ProtocolDeclaration(
name: self.name,
parent: self.parent,
accessibility: self.accessibility,
range: self.range,
nameRange: self.nameRange,
bodyRange: self.bodyRange,
initializers: self.initializers,
children: tokens,
inheritedTypes: self.inheritedTypes,
attributes: self.attributes,
genericParameters: self.genericParameters,
isNSObjectProtocol: self.isNSObjectProtocol
)
}
public func replace(isNSObjectProtocol: Bool) -> ProtocolDeclaration {
ProtocolDeclaration(
name: self.name,
parent: self.parent,
accessibility: self.accessibility,
range: self.range,
nameRange: self.nameRange,
bodyRange: self.bodyRange,
initializers: self.initializers,
children: self.children,
inheritedTypes: self.inheritedTypes,
attributes: self.attributes,
genericParameters: self.genericParameters,
isNSObjectProtocol: isNSObjectProtocol
)
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? ProtocolDeclaration else { return false }
return self.name == other.name
}
}

View File

@ -0,0 +1,17 @@
public struct ProtocolMethod: Method {
public var name: String
public var accessibility: Accessibility
public var returnSignature: ReturnSignature
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var parameters: [MethodParameter]
public var attributes: [Attribute]
public var genericParameters: [GenericParameter]
public var isOptional: Bool {
return attributes.map { $0.kind }.contains(.optional)
}
public var isOverriding: Bool {
return false
}
}

View File

@ -0,0 +1,29 @@
import Foundation
public struct ReturnSignature {
public var isAsync: Bool
public var throwType: ThrowType?
public var returnType: WrappableType
public var whereConstraints: [String]
public init(isAsync: Bool, throwString: String?, returnType: WrappableType, whereConstraints: [String]) {
self.isAsync = isAsync
if let throwString = throwString {
throwType = ThrowType(string: throwString)
} else {
throwType = nil
}
self.returnType = returnType
self.whereConstraints = whereConstraints
}
}
extension ReturnSignature: CustomStringConvertible {
public var description: String {
let asyncString = isAsync ? "async" : nil
let trimmedReturnType = returnType.explicitOptionalOnly.sugarized.trimmed
let returnString = trimmedReturnType.isEmpty || trimmedReturnType == "Void" ? nil : "-> \(returnType)"
let whereString = whereConstraints.isEmpty ? nil : "where \(whereConstraints.joined(separator: ", "))"
return [asyncString, throwType?.description, returnString, whereString].compactMap { $0 }.joined(separator: " ")
}
}

View File

@ -0,0 +1,17 @@
import Foundation
public struct StructDeclaration: ParentToken {
// NOTE: Purely for supporting nested classes, could be any generic parent (like extensions)
public let name: String
public var accessibility: Accessibility
public let range: CountableRange<Int>
public let nameRange: CountableRange<Int>
public let bodyRange: CountableRange<Int>
public var attributes: [Attribute]
public let children: [Token]
public func isEqual(to other: Token) -> Bool {
guard let other = other as? StructDeclaration else { return false }
return self.name == other.name
}
}

View File

@ -0,0 +1,31 @@
public enum ThrowType: CustomStringConvertible {
case throwing
case rethrowing
public init?(string: String) {
if string.trimmed.hasPrefix("throws") {
self = .throwing
} else if string.trimmed.hasPrefix("rethrows") {
self = .rethrowing
} else {
return nil
}
}
public var isThrowing: Bool {
return self == .throwing
}
public var isRethrowing: Bool {
return self == .rethrowing
}
public var description: String {
switch self {
case .throwing:
return "throws"
case .rethrowing:
return "rethrows"
}
}
}

View File

@ -0,0 +1,29 @@
public protocol Token {
func isEqual(to other: Token) -> Bool
func serialize() -> [String: Any]
}
public func ==(rhs: Token, lhs: Token) -> Bool {
return rhs.isEqual(to: lhs)
}
public extension Token {
func serialize() -> [String: Any] {
return [:]
}
func serializeWithType() -> [String: Any] {
var serialized = serialize()
serialized["@type"] = "\(type(of: self))"
return serialized
}
var isClassOrProtocolDeclaration: Bool {
return self is ProtocolDeclaration || self is ClassDeclaration
}
var isInheritanceDeclaration: Bool {
return self is InheritanceDeclaration
}
}

View File

@ -0,0 +1,148 @@
public enum WrappableType {
indirect case optional(WrappableType)
indirect case implicitlyUnwrappedOptional(WrappableType)
indirect case attributed(WrappableType, attributes: [String])
case type(String)
public var sugarized: String {
switch self {
case .optional(let wrapped):
return "\(wrapped.sugarized)?"
case .implicitlyUnwrappedOptional(let wrapped):
return "\(wrapped.sugarized)!"
case .attributed(let wrapped, let attributes):
return "\(attributes.joined(separator: " ")) \(wrapped.sugarized)"
case .type(let type):
return type
}
}
public var desugarized: String {
switch self {
case .optional(let wrapped), .implicitlyUnwrappedOptional(let wrapped):
return "Optional<\(wrapped.desugarized)>"
case .attributed(let wrapped, let attributes):
return "\(attributes.joined(separator: " ")) \(wrapped.desugarized)"
case .type(let type):
return type
}
}
public var explicitOptionalOnly: WrappableType {
switch self {
case .optional(let wrapped), .implicitlyUnwrappedOptional(let wrapped):
return .optional(wrapped.explicitOptionalOnly)
case .attributed(let wrapped, let attributes):
return .attributed(wrapped.explicitOptionalOnly, attributes: attributes)
case .type:
return self
}
}
public var unoptionaled: WrappableType {
switch self {
case .optional(let wrapped), .implicitlyUnwrappedOptional(let wrapped):
return wrapped.unoptionaled
case .attributed(let wrapped, let attributes):
return .attributed(wrapped.unoptionaled, attributes: attributes)
case .type:
return self
}
}
public var unwrapped: WrappableType {
switch self {
case .optional(let wrapped), .implicitlyUnwrappedOptional(let wrapped):
return wrapped
case .attributed(let wrapped, let attributes):
return .attributed(wrapped.unwrapped, attributes: attributes)
case .type:
return self
}
}
public var withoutAttributes: WrappableType {
switch self {
case .optional(let wrapped):
return .optional(wrapped.withoutAttributes)
case .implicitlyUnwrappedOptional(let wrapped):
return .implicitlyUnwrappedOptional(wrapped.withoutAttributes)
case .attributed(let wrapped, _):
return wrapped
case .type:
return self
}
}
public var isOptional: Bool {
switch self {
case .optional, .implicitlyUnwrappedOptional:
return true
case .attributed(let wrapped, _):
return wrapped.isOptional
case .type:
return false
}
}
public init(parsing value: String) {
let trimmedValue = value.trimmed
let optionalPrefix = "Optional<"
if trimmedValue.hasPrefix("@") {
let (attributes, resultString) = ["@autoclosure", "@escaping", "@noescape"]
.reduce(([], trimmedValue)) { acc, next -> ([String], String) in
var (attributes, resultString) = acc
guard let range = resultString.range(of: next) else { return acc }
resultString.removeSubrange(range)
attributes.append(next)
return (attributes, resultString)
}
self = .attributed(WrappableType(parsing: resultString), attributes: attributes)
} else if trimmedValue.hasSuffix("?") {
if trimmedValue.contains("->") && !trimmedValue.hasSuffix(")?") {
self = .type(trimmedValue)
} else {
self = .optional(WrappableType(parsing: String(trimmedValue.dropLast())))
}
} else if trimmedValue.hasPrefix(optionalPrefix) {
self = .optional(WrappableType(parsing: String(trimmedValue.dropFirst(optionalPrefix.count).dropLast())))
} else if trimmedValue.hasSuffix("!") {
self = .implicitlyUnwrappedOptional(WrappableType(parsing: String(trimmedValue.dropLast())))
} else {
self = .type(trimmedValue)
}
}
public func containsAttribute(named attribute: String) -> Bool {
switch self {
case .optional(let wrapped), .implicitlyUnwrappedOptional(let wrapped):
return wrapped.containsAttribute(named: attribute)
case .attributed(_, let attributes):
return attributes.contains(attribute.trimmed)
case .type:
return false
}
}
}
extension WrappableType: CustomStringConvertible {
public var description: String {
return sugarized
}
}
extension WrappableType: Equatable {
public static func ==(lhs: WrappableType, rhs: WrappableType) -> Bool {
switch (lhs, rhs) {
case (.optional(let lhsWrapped), .optional(let rhsWrapped)),
(.implicitlyUnwrappedOptional(let lhsWrapped), .implicitlyUnwrappedOptional(let rhsWrapped)):
return lhsWrapped == rhsWrapped
case (.attributed(let lhsWrapped, let lhsAttributes), .attributed(let rhsWrapped, let rhsAttributes)):
return lhsWrapped == rhsWrapped && lhsAttributes == rhsAttributes
case (.type(let lhsType), .type(let rhsType)):
return lhsType.components(separatedBy: .whitespacesAndNewlines).joined() == rhsType.components(separatedBy: .whitespacesAndNewlines).joined()
default:
return false
}
}
}

View File

@ -0,0 +1,53 @@
import Foundation
struct TypeGuesser {
static func guessType(from value: String) -> String? {
let value = value.trimmed
guard !value.isEmpty else { return nil }
let casting = checkCasting(from: value)
guard casting == nil else { return casting }
let character = value[value.startIndex]
switch character {
case "-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9":
return guessNumberType(from: value)
case "_":
return guessIdentifier(from: value)
case "\"":
return "String"
default:
let identifier = guessIdentifier(from: value)
return identifier == "true" || identifier == "false" ? "Bool" : identifier
}
}
private static func guessNumberType(from value: String) -> String {
var iterator = value.makeIterator()
while let character = iterator.next() {
if character == "." || character == "e" {
return "Double"
}
}
return "Int"
}
private static func guessIdentifier(from value: String) -> String? {
var identifier = ""
var iterator = value.makeIterator()
while let character = iterator.next() {
guard character != "(" else { break }
identifier.append(character)
}
return identifier
}
private static func checkCasting(from value: String) -> String? {
let regex = try! NSRegularExpression(pattern: " as (.*)$")
let range = NSRange(location: 0, length: value.count)
guard let casting = regex.firstMatch(in: value, range: range) else { return nil }
let foundRange = casting.range(at: 1)
guard foundRange.location != NSNotFound else { return nil }
return value[foundRange]
}
}

View File

@ -0,0 +1,76 @@
import Foundation
import SourceKittenFramework
extension String {
var trimmed: String {
return trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
func takeUntil(occurence: String) -> String? {
return components(separatedBy: occurence).first
}
subscript(range: Range<Int>) -> String {
let stringRange = index(startIndex, offsetBy: range.lowerBound)..<index(startIndex, offsetBy: range.upperBound)
return String(self[stringRange])
}
}
extension String.UTF8View {
subscript(range: Range<Int>) -> String {
let stringRange = index(startIndex, offsetBy: range.lowerBound)..<index(startIndex, offsetBy: range.upperBound)
let subsequence: String.UTF8View.SubSequence = self[stringRange]
return String(subsequence) ?? ""
}
}
extension String {
func regexMatches(_ source: String) -> Bool {
let regex = try! NSRegularExpression(pattern: self)
return regex.firstMatch(in: source, range: NSRange(location: 0, length: source.count)) != nil
}
}
extension Sequence {
#if !swift(>=4.1)
public func compactMap<O>(_ transform: (Element) -> O?) -> [O] {
return self.flatMap(transform)
}
#endif
func only<T>(_ type: T.Type) -> [T] {
return compactMap { $0 as? T }
}
func noneOf<T>(_ type: T.Type) -> [Iterator.Element] {
return filter { !($0 is T) }
}
}
/// Reserved keywords that are not allowed as function names, function parameters, or local variables, etc.
fileprivate let reservedKeywordsNotAllowed: Set = [
// Keywords used in declarations:
"associatedtype", "class", "deinit", "enum", "extension", "fileprivate", "func", "import", "init", "inout",
"internal", "let", "operator", "private", "precedencegroup", "protocol", "public", "rethrows", "static",
"struct", "subscript", "typealias", "var",
// Keywords used in statements:
"break", "case", "catch", "continue", "default", "defer", "do", "else", "fallthrough", "for", "guard", "if", "in",
"repeat", "return", "throw", "switch", "where", "while",
// Keywords used in expressions and types:
"Any", "as", "catch", "false", "is", "nil", "rethrows", "self", "super", "throw", "throws", "true", "try",
// Keywords used in patterns:
"_",
]
/// Utility function for escaping reserved keywords for a symbol name.
internal func escapeReservedKeywords(for name: String) -> String {
reservedKeywordsNotAllowed.contains(name) ? "`\(name)`" : name
}
internal func extractRange(from dictionary: [String: SourceKitRepresentable], offset: Key, length: Key) -> CountableRange<Int>? {
guard let offset = (dictionary[offset.rawValue] as? Int64).map(Int.init),
let length = (dictionary[length.rawValue] as? Int64).map(Int.init) else { return nil }
return offset..<offset.advanced(by: length)
}

Some files were not shown because too many files have changed in this diff Show More