danger-localizationlinter 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +12 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +167 -0
  6. data/Guardfile +21 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +62 -0
  9. data/Rakefile +25 -0
  10. data/danger-localizationlinter.gemspec +60 -0
  11. data/ext/localizationlinter/helper/validate_wording_cli.rb +21 -0
  12. data/ext/localizationlinter/localizationlinter.rb +331 -0
  13. data/ext/localizationlinter/swiftgen_localizables_check.stencil +36 -0
  14. data/lib/danger_localizationlinter.rb +3 -0
  15. data/lib/danger_plugin.rb +3 -0
  16. data/lib/localizationlinter/gem_version.rb +5 -0
  17. data/lib/localizationlinter/plugin.rb +96 -0
  18. data/spec/Test/Podfile +6 -0
  19. data/spec/Test/Podfile.lock +16 -0
  20. data/spec/Test/Pods/SwiftGen/CHANGELOG.md +1357 -0
  21. data/spec/Test/Pods/SwiftGen/LICENCE +21 -0
  22. data/spec/Test/Pods/SwiftGen/README.md +892 -0
  23. data/spec/Test/Pods/SwiftGen/bin/swiftgen +0 -0
  24. data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Commander +0 -0
  25. data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Resources/Info.plist +48 -0
  26. data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/A/Commander +0 -0
  27. data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/A/Resources/Info.plist +48 -0
  28. data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/A/_CodeSignature/CodeResources +132 -0
  29. data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/Current/Commander +0 -0
  30. data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/Current/Resources/Info.plist +48 -0
  31. data/spec/Test/Pods/SwiftGen/lib/Commander.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
  32. data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Kanna +0 -0
  33. data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Resources/Info.plist +48 -0
  34. data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/A/Kanna +0 -0
  35. data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/A/Resources/Info.plist +48 -0
  36. data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/A/_CodeSignature/CodeResources +132 -0
  37. data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/Current/Kanna +0 -0
  38. data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/Current/Resources/Info.plist +48 -0
  39. data/spec/Test/Pods/SwiftGen/lib/Kanna.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
  40. data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/PathKit +0 -0
  41. data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Resources/Info.plist +48 -0
  42. data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/A/PathKit +0 -0
  43. data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/A/Resources/Info.plist +48 -0
  44. data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/A/_CodeSignature/CodeResources +132 -0
  45. data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/Current/PathKit +0 -0
  46. data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/Current/Resources/Info.plist +48 -0
  47. data/spec/Test/Pods/SwiftGen/lib/PathKit.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
  48. data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Resources/Info.plist +48 -0
  49. data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Stencil +0 -0
  50. data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/A/Resources/Info.plist +48 -0
  51. data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/A/Stencil +0 -0
  52. data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/A/_CodeSignature/CodeResources +132 -0
  53. data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/Current/Resources/Info.plist +48 -0
  54. data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/Current/Stencil +0 -0
  55. data/spec/Test/Pods/SwiftGen/lib/Stencil.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
  56. data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Resources/Info.plist +48 -0
  57. data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/StencilSwiftKit +0 -0
  58. data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/A/Resources/Info.plist +48 -0
  59. data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/A/StencilSwiftKit +0 -0
  60. data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/A/_CodeSignature/CodeResources +132 -0
  61. data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/Current/Resources/Info.plist +48 -0
  62. data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/Current/StencilSwiftKit +0 -0
  63. data/spec/Test/Pods/SwiftGen/lib/StencilSwiftKit.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
  64. data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Resources/Info.plist +48 -0
  65. data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/SwiftGenKit +0 -0
  66. data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/A/Resources/Info.plist +48 -0
  67. data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/A/SwiftGenKit +0 -0
  68. data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/A/_CodeSignature/CodeResources +132 -0
  69. data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/Current/Resources/Info.plist +48 -0
  70. data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/Current/SwiftGenKit +0 -0
  71. data/spec/Test/Pods/SwiftGen/lib/SwiftGenKit.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
  72. data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Resources/Info.plist +48 -0
  73. data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/A/Resources/Info.plist +48 -0
  74. data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/A/Yams +0 -0
  75. data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/A/_CodeSignature/CodeResources +132 -0
  76. data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/Current/Resources/Info.plist +48 -0
  77. data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/Current/Yams +0 -0
  78. data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Versions/Current/_CodeSignature/CodeResources +132 -0
  79. data/spec/Test/Pods/SwiftGen/lib/Yams.framework/Yams +0 -0
  80. data/spec/Test/Pods/SwiftGen/templates/colors/literals-swift4.stencil +43 -0
  81. data/spec/Test/Pods/SwiftGen/templates/colors/literals-swift5.stencil +43 -0
  82. data/spec/Test/Pods/SwiftGen/templates/colors/swift4.stencil +84 -0
  83. data/spec/Test/Pods/SwiftGen/templates/colors/swift5.stencil +84 -0
  84. data/spec/Test/Pods/SwiftGen/templates/coredata/swift4.stencil +211 -0
  85. data/spec/Test/Pods/SwiftGen/templates/coredata/swift5.stencil +211 -0
  86. data/spec/Test/Pods/SwiftGen/templates/fonts/swift4.stencil +110 -0
  87. data/spec/Test/Pods/SwiftGen/templates/fonts/swift5.stencil +113 -0
  88. data/spec/Test/Pods/SwiftGen/templates/ib/scenes-swift4.stencil +157 -0
  89. data/spec/Test/Pods/SwiftGen/templates/ib/scenes-swift5.stencil +159 -0
  90. data/spec/Test/Pods/SwiftGen/templates/ib/segues-swift4.stencil +60 -0
  91. data/spec/Test/Pods/SwiftGen/templates/ib/segues-swift5.stencil +60 -0
  92. data/spec/Test/Pods/SwiftGen/templates/json/inline-swift4.stencil +82 -0
  93. data/spec/Test/Pods/SwiftGen/templates/json/inline-swift5.stencil +82 -0
  94. data/spec/Test/Pods/SwiftGen/templates/json/runtime-swift4.stencil +112 -0
  95. data/spec/Test/Pods/SwiftGen/templates/json/runtime-swift5.stencil +112 -0
  96. data/spec/Test/Pods/SwiftGen/templates/plist/inline-swift4.stencil +82 -0
  97. data/spec/Test/Pods/SwiftGen/templates/plist/inline-swift5.stencil +82 -0
  98. data/spec/Test/Pods/SwiftGen/templates/plist/runtime-swift4.stencil +117 -0
  99. data/spec/Test/Pods/SwiftGen/templates/plist/runtime-swift5.stencil +117 -0
  100. data/spec/Test/Pods/SwiftGen/templates/strings/flat-swift4.stencil +97 -0
  101. data/spec/Test/Pods/SwiftGen/templates/strings/flat-swift5.stencil +97 -0
  102. data/spec/Test/Pods/SwiftGen/templates/strings/objc-h.stencil +66 -0
  103. data/spec/Test/Pods/SwiftGen/templates/strings/objc-m.stencil +90 -0
  104. data/spec/Test/Pods/SwiftGen/templates/strings/structured-swift4.stencil +102 -0
  105. data/spec/Test/Pods/SwiftGen/templates/strings/structured-swift5.stencil +102 -0
  106. data/spec/Test/Pods/SwiftGen/templates/xcassets/swift4.stencil +266 -0
  107. data/spec/Test/Pods/SwiftGen/templates/xcassets/swift5.stencil +274 -0
  108. data/spec/Test/Pods/SwiftGen/templates/yaml/inline-swift4.stencil +92 -0
  109. data/spec/Test/Pods/SwiftGen/templates/yaml/inline-swift5.stencil +92 -0
  110. data/spec/Test/Test.xcodeproj/project.pbxproj +406 -0
  111. data/spec/Test/Test.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  112. data/spec/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  113. data/spec/Test/Test.xcworkspace/contents.xcworkspacedata +10 -0
  114. data/spec/Test/Test.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  115. data/spec/Test/Test/AppDelegate.swift +36 -0
  116. data/spec/Test/Test/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  117. data/spec/Test/Test/Assets.xcassets/AppIcon.appiconset/Contents.json +98 -0
  118. data/spec/Test/Test/Assets.xcassets/Contents.json +6 -0
  119. data/spec/Test/Test/ContentView.swift +21 -0
  120. data/spec/Test/Test/Info.plist +62 -0
  121. data/spec/Test/Test/SceneDelegate.swift +63 -0
  122. data/spec/Test/Test/all_target_main_language.yml +1 -0
  123. data/spec/Test/Test/en.lproj/LaunchScreen.storyboard +25 -0
  124. data/spec/Test/Test/en.lproj/localizable.strings +3 -0
  125. data/spec/Test/Test/fr.lproj/LaunchScreen.storyboard +25 -0
  126. data/spec/Test/Test/fr.lproj/localizable.strings +3 -0
  127. data/spec/localizationofficer_spec.rb +116 -0
  128. data/spec/spec_helper.rb +67 -0
  129. data/spec/support/fixtures/all_target_main_language.yml +1 -0
  130. data/spec/support/fixtures/resources/TEST/en.lproj/Localizable.strings +8 -0
  131. data/spec/support/fixtures/resources/TEST/en.lproj/Localizable.stringsdict +30 -0
  132. data/spec/support/fixtures/resources/TEST_KO/en.lproj/Localizable.strings +11 -0
  133. data/spec/support/fixtures/resources/TEST_KO/en.lproj/Localizable.stringsdict +30 -0
  134. data/spec/support/fixtures/resources/TEST_KO/fr.lproj/Localizable.strings +11 -0
  135. data/spec/support/fixtures/resources/TEST_KO/fr.lproj/Localizable.stringsdict +30 -0
  136. metadata +491 -0
@@ -0,0 +1,21 @@
1
+ MIT Licence
2
+
3
+ Copyright (c) 2020 SwiftGen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,892 @@
1
+ # SwiftGen
2
+
3
+ [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/SwiftGen.svg)](https://img.shields.io/cocoapods/v/SwiftGen.svg)
4
+ [![Platform](https://img.shields.io/cocoapods/p/SwiftGen.svg?style=flat)](http://cocoadocs.org/docsets/SwiftGen)
5
+ ![Swift 4.x](https://img.shields.io/badge/Swift-4.x-orange) ![Swift 5.x](https://img.shields.io/badge/Swift-5.x-orange)
6
+
7
+ SwiftGen is a tool to automatically generate Swift code for resources of your projects (like images, localised strings, etc), to make them type-safe to use.
8
+
9
+ <table border="0"><tr>
10
+ <td>
11
+ <img alt="SwiftGen Logo" src="https://github.com/SwiftGen/Eve/raw/master/logo/logo-256.png" />
12
+ </td><td>
13
+ <ul>
14
+ <li><a href="#installation">Installation</a>
15
+ <li><a href="#configuration-file">Configuration File</a>
16
+ <li><a href="#choosing-your-template">Choosing your template</a>
17
+ <li><a href="#additional-documentation">Additional documentation</a>
18
+ </ul>
19
+ Then generate constants for:
20
+ <ul>
21
+ <li><a href="#asset-catalog">Assets Catalogs</a>
22
+ <li><a href="#colors">Colors</a>
23
+ <li><a href="#core-data">Core Data</a>
24
+ <li><a href="#fonts">Fonts</a>
25
+ <li><a href="#interface-builder">Interface Builder files</a>
26
+ <li><a href="#json-and-yaml">JSON and YAML files</a>
27
+ <li><a href="#plists">Plists</a>
28
+ <li><a href="#strings">Localizable strings</a>
29
+ </ul>
30
+ </td>
31
+ </tr></table>
32
+
33
+ <span style="float:none" />
34
+
35
+ There are multiple benefits in using this:
36
+
37
+ * Avoid any risk of typo when using a String
38
+ * Free auto-completion
39
+ * Avoid the risk of using a non-existing asset name
40
+ * All this will be ensured by the compiler and thus avoid the risk of crashing at runtime.
41
+
42
+ Also, it's fully customizable thanks to Stencil templates, so even if it comes with predefined templates, you can make your own to generate whatever code fits your needs and your guidelines!
43
+
44
+ ## Installation
45
+
46
+ There are multiple possibilities to install SwiftGen on your machine or in your project, depending on your preferences and needs:
47
+
48
+ <details>
49
+ <summary><strong>Download the ZIP</strong> for the latest release</summary>
50
+
51
+ * [Go to the GitHub page for the latest release](https://github.com/SwiftGen/SwiftGen/releases/latest)
52
+ * Download the `swiftgen-x.y.z.zip` file associated with that release
53
+ * Extract the content of the zip archive in your project directory
54
+
55
+ We recommend that you **unarchive the ZIP inside your project directory** and **commit its content** to git. This way, **all coworkers will use the same version of SwiftGen for this project**.
56
+
57
+ If you unarchived the ZIP file in a folder e.g. called `swiftgen` at the root of your project directory, you can then invoke SwiftGen in your Script Build Phase using:
58
+
59
+ ```sh
60
+ "${PROJECT_DIR}/swiftgen/bin/swiftgen" …
61
+ ```
62
+
63
+ ---
64
+ </details>
65
+ <details>
66
+ <summary>Via <strong>CocoaPods</strong></summary>
67
+
68
+ If you're using CocoaPods, simply add `pod 'SwiftGen', '~> 6.0'` to your `Podfile`.
69
+
70
+ Then execute `pod install --repo-update` (or `pod update SwiftGen` if you want to update an existing SwiftGen installation) to download and install the `SwiftGen` binaries and dependencies in `Pods/SwiftGen/bin/swiftgen` next to your project.
71
+
72
+ Given that you can specify an exact version for `SwiftGen` in your `Podfile`, this allows you to ensure **all coworkers will use the same version of SwiftGen for this project**.
73
+
74
+ You can then invoke SwiftGen in your Script Build Phase using:
75
+
76
+ ```sh
77
+ if [[ -f "${PODS_ROOT}/SwiftGen/bin/swiftgen" ]]; then
78
+ "${PODS_ROOT}/SwiftGen/bin/swiftgen" …
79
+ else
80
+ echo "warning: SwiftGen is not installed. Run 'pod install --repo-update' to install it."
81
+ fi
82
+ ```
83
+
84
+ > Similarly, be sure to use `Pods/SwiftGen/bin/swiftgen` instead of just `swiftgen` where we mention commands with `swiftgen` in the rest of the documentation.
85
+
86
+ _Note: SwiftGen isn't really a pod, as it's not a library your code will depend on at runtime; so the installation via CocoaPods is just a trick that installs the SwiftGen binaries in the Pods/ folder, but you won't see any swift files in the Pods/SwiftGen group in your Xcode's Pods.xcodeproj. That's normal; the SwiftGen binary is still present in that folder in the Finder._
87
+
88
+ ---
89
+ </details>
90
+ <details>
91
+ <summary>Via <strong>Homebrew</strong> <em>(system-wide installation)</em></summary>
92
+
93
+ To install SwiftGen via [Homebrew](http://brew.sh), simply use:
94
+
95
+ ```sh
96
+ $ brew update
97
+ $ brew install swiftgen
98
+ ```
99
+
100
+ This will install SwiftGen **system-wide**. The same version of SwiftGen will be used for all projects on that machine, and you should make sure all your coworkers have the same version of SwiftGen installed on their machine too.
101
+
102
+ You can then invoke `swiftgen` directly in your Script Build Phase (as it will be in your `$PATH` already):
103
+
104
+ ```sh
105
+ swiftgen …
106
+ ```
107
+
108
+ ---
109
+ </details>
110
+ <details>
111
+ <summary>Via <strong>Mint</strong> <em>(system-wide installation)</em></summary>
112
+
113
+ > ❗️SwiftGen 6.0 or higher only.
114
+
115
+ To install SwiftGen via [Mint](https://github.com/yonaskolb/Mint), simply use:
116
+
117
+ ```sh
118
+ $ mint install SwiftGen/SwiftGen
119
+ ```
120
+ ---
121
+ </details>
122
+ <details>
123
+ <summary><strong>Compile from source</strong> <em>(only recommended if you need features from the `stable` branch or want to test a PR)</em></summary>
124
+
125
+ This solution is when you want to build and install the latest version from `stable` and have access to features which might not have been released yet.
126
+
127
+ * If you have `homebrew` installed, you can use the following command to build and install the latest commit:
128
+
129
+ ```sh
130
+ brew install swiftgen --HEAD
131
+ ```
132
+
133
+ * Alternatively, you can clone the repository and use `rake cli:install` to build the tool and install it from any branch, which could be useful to test SwiftGen in a fork or a Pull Request branch.
134
+
135
+ Some Ruby tools are used in the build process, and the system Ruby works well if you are running a recent macOS. However, if you are using `rbenv` you can run `rbenv install` to make sure you have a matching version of Ruby installed.
136
+
137
+ Then install the Ruby Gems:
138
+
139
+ ```sh
140
+ # Install bundle if it isn't installed
141
+ gem install bundle
142
+ # Install the Ruby gems from Gemfile
143
+ bundle install
144
+ ```
145
+
146
+ You can now install to the default locations (no parameter) or to custom locations:
147
+
148
+ ```sh
149
+ # Binary is installed in `./build/swiftgen/bin`, frameworks in `./build/swiftgen/lib` and templates in `./build/swiftgen/templates`
150
+ $ rake cli:install
151
+ # - OR -
152
+ # Binary will be installed in `~/swiftgen/bin`, frameworks in `~/swiftgen/fmk` and templates in `~/swiftgen/tpl`
153
+ $ rake cli:install[~/swiftgen/bin,~/swiftgen/fmk,~/swiftgen/tpl]
154
+ ```
155
+
156
+ You can then invoke SwiftGen using the path to the binary where you installed it:
157
+
158
+ ```sh
159
+ ~/swiftgen/bin/swiftgen …
160
+ ```
161
+
162
+ Or add the path to the `bin` folder to your `$PATH` and invoke `swiftgen` directly.
163
+
164
+ ---
165
+ </details>
166
+
167
+ ### Known Installation Issues On macOS Before 10.14.4
168
+
169
+ Starting with [SwiftGen 6.2.1](https://github.com/SwiftGen/SwiftGen/releases/6.2.1), if you get an error similar to `dyld: Symbol not found: _$s11SubSequenceSlTl` when running SwiftGen, you'll need to install the [Swift 5 Runtime Support for Command Line Tools](https://support.apple.com/kb/DL1998).
170
+
171
+ Alternatively, you can:
172
+
173
+ - Update to macOS 10.14.4 or later
174
+ - Install Xcode 10.2 or later at `/Applications/Xcode.app`
175
+ - Rebuild SwiftGen from source using Xcode 10.2 or later
176
+
177
+ ## Configuration File
178
+
179
+ > ❗️ If you're migrating from older SwiftGen versions, don't forget to [read the Migration Guide](Documentation/MigrationGuide.md).
180
+
181
+ SwiftGen is provided as a single command-line tool which uses a configuration file to define the various parsers to run (depending on the type of input files you need to parse) and their parameters.
182
+
183
+ To create a sample configuration file as a starting point to adapt to your needs, run `swiftgen config init`.
184
+
185
+ Each parser described in the [configuration file](Documentation/ConfigFile.md) (`strings`, `fonts`, `ib`, …) typically corresponds to a type of input resources to parse (strings files, IB files, Font files, JSON files, …), allowing you to generate constants for each types of those input files.
186
+
187
+ To use SwiftGen, simply create a `swiftgen.yml` YAML file (either manually or using `swiftgen config init`) then edit it to adapt to your project. The config file should list all the parsers to invoke, and for each parser, the list of inputs/outputs/templates/parameters to use for it.
188
+
189
+ For example:
190
+
191
+ ```yaml
192
+ strings:
193
+ inputs: Resources/Base.lproj
194
+ outputs:
195
+ - templateName: structured-swift5
196
+ output: Generated/Strings.swift
197
+ xcassets:
198
+ inputs:
199
+ - Resources/Images.xcassets
200
+ - Resources/MoreImages.xcassets
201
+ - Resources/Colors.xcassets
202
+ outputs:
203
+ - templateName: swift5
204
+ output: Generated/Assets.swift
205
+ ```
206
+
207
+ Then you just have to invoke `swiftgen config run`, or even just `swiftgen` for short, and it will execute what's described in the configuration file.
208
+
209
+ [The dedicated documentation](Documentation/ConfigFile.md) explains the syntax and possibilities in details – like how to pass custom parameters to your templates, use `swiftgen config lint` to validate your config file, how to use alternate config files, and other tips.
210
+
211
+ There are also additional subcommands you can invoke from the command line to manage and configure SwiftGen:
212
+
213
+ * The `swiftgen config` subcommand to help you with the configuration file, especially `swiftgen config init` to create a starting point for your config and `swiftgen config lint` to validate that your Config file is valid and has no errors
214
+ * The `swiftgen template` subcommands to help you print, duplicate, find and manage templates bundled with SwiftGen
215
+
216
+ Lastly, you can use `--help` on `swiftgen` or one of its subcommand to see the detailed usage.
217
+
218
+ <details>
219
+ <summary><strong>Directly invoking a parser without a config file</strong></summary>
220
+
221
+ While we highly recommend the use a configuration file for performance reasons (especially if you have multiple outputs, but also because it's more flexible), it's also possible to directly invoke the available parsers individually using `swiftgen run`:
222
+
223
+ * `swiftgen run colors [OPTIONS] DIRORFILE1 …`
224
+ * `swiftgen run coredata [OPTIONS] DIRORFILE1 …`
225
+ * `swiftgen run fonts [OPTIONS] DIRORFILE1 …`
226
+ * `swiftgen run ib [OPTIONS] DIRORFILE1 …`
227
+ * `swiftgen run json [OPTIONS] DIRORFILE1 …`
228
+ * `swiftgen run plist [OPTIONS] DIRORFILE1 …`
229
+ * `swiftgen run strings [OPTIONS] DIRORFILE1 …`
230
+ * `swiftgen run xcassets [OPTIONS] DIRORFILE1 …`
231
+ * `swiftgen run yaml [OPTIONS] DIRORFILE1 …`
232
+
233
+ One rare cases where this might be useful — as opposed to using a config file — is if you are working on a custom template and want to quickly test the specific parser you're working on at each iteration/version of your custom template, until you're happy with it.
234
+
235
+ Each parser command generally accepts the same options and syntax, and they mirror the options and parameters from the configuration file:
236
+
237
+ * `--output FILE` or `-o FILE`: set the file where to write the generated code. If omitted, the generated code will be printed on `stdout`.
238
+ * `--templateName NAME` or `-n NAME`: define the Stencil template to use (by name, see [here for more info](Documentation/templates)) to generate the output.
239
+ * `--templatePath PATH` or `-p PATH`: define the Stencil template to use, using a full path.
240
+ * Note: you should specify one and only one template when invoking SwiftGen. You have to use either `-t` or `-p` but should not use both at the same time (it wouldn't make sense anyway and you'll get an error if you try)
241
+ * `--filter REGEX` or `-f REGEX`: the filter to apply to each input path. Filters are applied to actual (relative) paths, not just the filename. Each command has a default filter that you can override with this option.
242
+ * Note: use `.+` to match multiple characters (at least one), and don't forget to escape the dot (`\.`) if you want to match a literal dot like for an extension. Add `$` at the end to ensure the path ends with the extension you want. Regular expressions will be case sensitive by default, and not anchored to the start/end of a path. For example, use `.+\.xib$` to match files with a `.xib` extension. Use a tool such as [RegExr](https://regexr.com) to ensure you're using a valid regular expression.
243
+ * Each command supports multiple input files (or directories where applicable).
244
+ * You can always use the `--help` flag to see what options a command accept, e.g. `swiftgen run xcassets --help`.
245
+
246
+ </details>
247
+
248
+ ## Choosing your template
249
+
250
+ SwiftGen is based on templates (it uses [Stencil](https://github.com/stencilproject/Stencil) as its template engine). This means that **you can choose the template that fits the Swift version you're using** — and also the one that best fits your preferences — to **adapt the generated code to your own conventions and Swift version**.
251
+
252
+ ### Bundled templates vs. Custom ones
253
+
254
+ SwiftGen comes bundled with some templates for each of the parsers (`colors`, `coredata`, `fonts`, `ib`, `json`, `plist`, `strings`, `xcassets`, `yaml`), which will fit most needs; simply use the `templateName` output option to specify the name of the template to use. But you can also create your own templates if the bundled ones don't suit your coding conventions or needs: just store them anywhere (like in your project repository) and use the `templatePath` output option instead of `templateName`, to specify their path.
255
+
256
+ 💡 You can use the `swiftgen template list` command to list all the available bundled templates for each parser, and use `swiftgen template cat` to show a template's content and duplicate it to create your own variation.
257
+
258
+ For more information about how to create your own templates, [see the dedicated documentation](Documentation/Articles/Creating-custom-templates.md).
259
+
260
+ ### Templates bundled with SwiftGen:
261
+
262
+ As explained above, you can use `swiftgen template list` to list all templates bundled with SwiftGen. For most SwiftGen parsers, we provide, among others:
263
+
264
+ * A `swift4` template, compatible with Swift 4
265
+ * A `swift5` template, compatible with Swift 5
266
+ * Other variants, like `flat-swift4/5` and `structured-swift4/5` templates for Strings, etc.
267
+
268
+ You can **find the documentation for each bundled template [here in the repo](Documentation/templates)**, with documentation organized as one folder per SwiftGen parser, then one MarkDown file per template. You can also use `swiftgen template doc` to open that documentation page in your browser directly from your terminal.
269
+
270
+ Each MarkDown file documents the Swift Version it's aimed for, the use case for that template (in which cases you might favor that template over others), the available parameters to customize it on invocation (using the `params:` key in your config file), and some code examples.
271
+
272
+ > Don't hesitate to make PRs to share your improvements suggestions on the bundled templates 😉
273
+
274
+ ## Additional documentation
275
+
276
+ ### Playground
277
+
278
+ The `SwiftGen.playground` available in this repository will allow you to play with the code that the tool typically generates, and see some examples of how you can take advantage of it.
279
+
280
+ This allows you to have a quick look at how typical code generated by SwiftGen looks like, and how you will then use the generated constants in your code.
281
+
282
+ ### Dedicated Documentation in Markdown
283
+
284
+ There is a lot of documentation in the form of Markdown files in this repository, and in the related [StencilSwiftKit](https://github.com/SwiftGen/StencilSwiftKit) repository as well.
285
+
286
+ Be sure to [check the "Documentation" folder](Documentation/) of each repository.
287
+
288
+ Especially, in addition to the previously mentioned [Migration Guide](Documentation/MigrationGuide.md) and [Configuration File](Documentation/ConfigFile.md) documentation, the `Documentation/` folder in the SwiftGen repository also includes:
289
+
290
+ * A [`templates` subdirectory](Documentation/templates/) that details the documentation for each of the templates bundled with SwiftGen (when to use each template, what the output will look like, and custom parameters to adjust them, …)
291
+ * A [`SwiftGenKit Contexts` subdirectory](Documentation/SwiftGenKit%20Contexts/) that details the structure of the "Stencil Contexts", i.e. the Dictionary/YAML representation resulting of parsing your input files. This documentation is useful for people wanting to write their own templates, so that they know the structure and various keys available when writing their template, to construct the wanted generated output accordingly.
292
+ * [Various articles](Documentation/Articles/) to provide best practices & tips on how to better take advantage of SwiftGen in your projects:
293
+ * [Integrate SwiftGen in your Xcode project](Documentation/Articles/Xcode-Integration.md) — so it rebuilds the constants every time you build
294
+ * [Configure SwiftLint to help your developers use constants generated by SwiftGen](Documentation/Articles/SwiftLint-Integration.md)
295
+ * [Create a custom template](Documentation/Articles/Creating-custom-templates.md), and [watch a folder to auto-regenerate an output every time you save the template you're working on](Documentation/Articles/Watch-a-folder-for-changes.md)
296
+ * …and more
297
+
298
+ ### Tutorials
299
+
300
+ You can also find other help & tutorial material on the internet, like [this classroom about Code Generation I gave at FrenchKit in Sept'17](https://github.com/FrenchKit/Mastering-code-generation-Classroom) — and its wiki detailing a step-by-step tutorial about installing and using SwiftGen (and Sourcery too)
301
+
302
+ ---
303
+
304
+ # Available Parsers
305
+
306
+ ## Asset Catalog
307
+
308
+ ```yaml
309
+ xcassets:
310
+ inputs: /dir/to/search/for/imageset/assets
311
+ outputs:
312
+ templateName: swift5
313
+ output: Assets.swift
314
+ ```
315
+
316
+ This will generate an `enum Asset` with one `static let` per asset (image set, color set, data set, …) in your assets catalog, so that you can use them as constants.
317
+
318
+ <details>
319
+ <summary>Example of code generated by the bundled template</summary>
320
+
321
+ ```swift
322
+ internal enum Asset {
323
+ internal enum Files {
324
+ internal static let data = DataAsset(value: "Data")
325
+ internal static let readme = DataAsset(value: "README")
326
+ }
327
+ internal enum Food {
328
+ internal enum Exotic {
329
+ internal static let banana = ImageAsset(value: "Exotic/Banana")
330
+ internal static let mango = ImageAsset(value: "Exotic/Mango")
331
+ }
332
+ internal static let `private` = ImageAsset(value: "private")
333
+ }
334
+ internal enum Styles {
335
+ internal enum Vengo {
336
+ internal static let primary = ColorAsset(value: "Vengo/Primary")
337
+ internal static let tint = ColorAsset(value: "Vengo/Tint")
338
+ }
339
+ }
340
+ internal enum Targets {
341
+ internal static let bottles = ARResourceGroupAsset(name: "Bottles")
342
+ internal static let paintings = ARResourceGroupAsset(name: "Paintings")
343
+ }
344
+ }
345
+ ```
346
+ </details>
347
+
348
+ ### Usage Example
349
+
350
+ ```swift
351
+ // You can create new images by referring to the enum instance and calling `.image` on it:
352
+ let bananaImage = Asset.Exotic.banana.image
353
+ let privateImage = Asset.private.image
354
+
355
+ // You can create colors by referring to the enum instance and calling `.color` on it:
356
+ let primaryColor = Asset.Styles.Vengo.primary.color
357
+ let tintColor = Asset.Styles.Vengo.tint.color
358
+
359
+ // You can create data items by referring to the enum instance and calling `.data` on it:
360
+ let data = Asset.data.data
361
+ let readme = Asset.readme.data
362
+
363
+ // you can load an AR resource group's items using:
364
+ let bottles = Asset.Targets.bottles.referenceObjects
365
+ let paintings = Asset.Targets.paintings.referenceImages
366
+ ```
367
+
368
+ ## Colors
369
+
370
+ > ❗️ We recommend to define your colors in your Assets Catalogs and use the `xcassets` parser (see above) to generate color constants, instead of using this `colors` parser described below.
371
+ > The `colors` parser below is mainly useful if you support older versions of iOS where colors can't be defined in Asset Catalogs, or if you want to use Android's `colors.xml` files as input.
372
+
373
+ ```yaml
374
+ colors:
375
+ inputs: /path/to/colors-file.txt
376
+ outputs:
377
+ templateName: swift5
378
+ output: Colors.swift
379
+ ```
380
+
381
+ This will generate a `enum ColorName` with one `static let` per color listed in the text file passed as argument.
382
+
383
+ The input file is expected to be either:
384
+
385
+ * a [plain text file](Tests/Fixtures/Resources/Colors/extra.txt), with one line per color to register, each line being composed by the Name to give to the color, followed by ":", followed by the Hex representation of the color (like `rrggbb` or `rrggbbaa`, optionally prefixed by `#` or `0x`) or the name of another color in the file. Whitespaces are ignored.
386
+ * a [JSON file](Tests/Fixtures/Resources/Colors/colors.json), representing a dictionary of names -> values, each value being the hex representation of the color
387
+ * a [XML file](Tests/Fixtures/Resources/Colors/colors.xml), expected to be the same format as the Android colors.xml files, containing tags `<color name="AColorName">AColorHexRepresentation</color>`
388
+ * a [`*.clr` file](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/DrawColor/Concepts/AboutColorLists.html#//apple_ref/doc/uid/20000757-BAJHJEDI) used by Apple's Color Palettes.
389
+
390
+ For example you can use this command to generate colors from one of your system color lists:
391
+
392
+ ```yaml
393
+ colors:
394
+ inputs: ~/Library/Colors/MyColors.clr
395
+ outputs:
396
+ templateName: swift5
397
+ output: Colors.swift
398
+ ```
399
+
400
+ Generated code will look the same as if you'd use a text file.
401
+
402
+ <details>
403
+ <summary>Example of code generated by the bundled template</summary>
404
+
405
+ Given the following `colors.txt` file:
406
+
407
+ ```
408
+ Cyan-Color : 0xff66ccff
409
+ ArticleTitle : #33fe66
410
+ ArticleBody : 339666
411
+ ArticleFootnote : ff66ccff
412
+ Translucent : ffffffcc
413
+ ```
414
+
415
+ The generated code will look like this:
416
+
417
+ ```swift
418
+ internal struct ColorName {
419
+ internal let rgbaValue: UInt32
420
+ internal var color: Color { return Color(named: self) }
421
+
422
+ /// <span style="display:block;width:3em;height:2em;border:1px solid black;background:#339666"></span>
423
+ /// Alpha: 100% <br/> (0x339666ff)
424
+ internal static let articleBody = ColorName(rgbaValue: 0x339666ff)
425
+ /// <span style="display:block;width:3em;height:2em;border:1px solid black;background:#ff66cc"></span>
426
+ /// Alpha: 100% <br/> (0xff66ccff)
427
+ internal static let articleFootnote = ColorName(rgbaValue: 0xff66ccff)
428
+
429
+ ...
430
+ }
431
+ ```
432
+ </details>
433
+
434
+ ### Usage Example
435
+
436
+ ```swift
437
+ // You can create colors with the convenience constructor like this:
438
+ let title = UIColor(named: .articleBody) // iOS
439
+ let footnote = NSColor(named: .articleFootnote) // macOS
440
+
441
+ // Or as an alternative, you can refer to enum instance and call .color on it:
442
+ let sameTitle = ColorName.articleBody.color
443
+ let sameFootnote = ColorName.articleFootnote.color
444
+ ```
445
+
446
+ This way, no need to enter the color red, green, blue, alpha values each time and create ugly constants in the global namespace for them.
447
+
448
+ ## Core Data
449
+
450
+ ```yaml
451
+ coredata:
452
+ inputs: /path/to/model.xcdatamodeld
453
+ outputs:
454
+ templateName: swift5
455
+ output: CoreData.swift
456
+ ```
457
+
458
+ This will parse the specified core data model(s), generate a class for each entity in your model containing all the attributes, and a few extensions if needed for relationships and predefined fetch requests.
459
+
460
+ <details>
461
+ <summary>Example of code generated by the bundled template</summary>
462
+
463
+ ```swift
464
+ internal class MainEntity: NSManagedObject {
465
+ internal class var entityName: String {
466
+ return "MainEntity"
467
+ }
468
+
469
+ internal class func entity(in managedObjectContext: NSManagedObjectContext) -> NSEntityDescription? {
470
+ return NSEntityDescription.entity(forEntityName: entityName, in: managedObjectContext)
471
+ }
472
+
473
+ @nonobjc internal class func makeFetchRequest() -> NSFetchRequest<MainEntity> {
474
+ return NSFetchRequest<MainEntity>(entityName: entityName)
475
+ }
476
+
477
+ @NSManaged internal var attributedString: NSAttributedString?
478
+ @NSManaged internal var binaryData: Data?
479
+ @NSManaged internal var boolean: Bool
480
+ @NSManaged internal var date: Date?
481
+ @NSManaged internal var float: Float
482
+ @NSManaged internal var int64: Int64
483
+ internal var integerEnum: IntegerEnum {
484
+ get {
485
+ let key = "integerEnum"
486
+ willAccessValue(forKey: key)
487
+ defer { didAccessValue(forKey: key) }
488
+
489
+ guard let value = primitiveValue(forKey: key) as? IntegerEnum.RawValue,
490
+ let result = IntegerEnum(rawValue: value) else {
491
+ fatalError("Could not convert value for key '\(key)' to type 'IntegerEnum'")
492
+ }
493
+ return result
494
+ }
495
+ set {
496
+ let key = "integerEnum"
497
+ willChangeValue(forKey: key)
498
+ defer { didChangeValue(forKey: key) }
499
+
500
+ setPrimitiveValue(newValue.rawValue, forKey: key)
501
+ }
502
+ }
503
+ @NSManaged internal var manyToMany: Set<SecondaryEntity>
504
+ }
505
+
506
+ // MARK: Relationship ManyToMany
507
+
508
+ extension MainEntity {
509
+ @objc(addManyToManyObject:)
510
+ @NSManaged public func addToManyToMany(_ value: SecondaryEntity)
511
+
512
+ @objc(removeManyToManyObject:)
513
+ @NSManaged public func removeFromManyToMany(_ value: SecondaryEntity)
514
+
515
+ @objc(addManyToMany:)
516
+ @NSManaged public func addToManyToMany(_ values: Set<SecondaryEntity>)
517
+
518
+ @objc(removeManyToMany:)
519
+ @NSManaged public func removeFromManyToMany(_ values: Set<SecondaryEntity>)
520
+ }
521
+ ```
522
+ </details>
523
+
524
+ ### Usage Example
525
+
526
+ ```swift
527
+ // Fetch all the instances of MainEntity
528
+ let request = MainEntity.makeFetchRequest()
529
+ let mainItems = try myContext.execute(request)
530
+
531
+ // Type-safe relationships: `relatedItem` will be a `SecondaryEntity?` in this case
532
+ let relatedItem = myMainItem.manyToMany.first
533
+ ```
534
+
535
+ ## Fonts
536
+
537
+ ```yaml
538
+ fonts:
539
+ inputs: /path/to/font/dir
540
+ outputs:
541
+ templateName: swift5
542
+ output: Fonts.swift
543
+ ```
544
+
545
+ This will recursively go through the specified directory, finding any typeface files (TTF, OTF, …), defining a `struct FontFamily` for each family, and an enum nested under that family that will represent the font styles.
546
+
547
+ <details>
548
+ <summary>Example of code generated by the bundled template</summary>
549
+
550
+ ```swift
551
+ internal enum FontFamily {
552
+ internal enum SFNSDisplay: String, FontConvertible {
553
+ internal static let regular = FontConvertible(name: ".SFNSDisplay-Regular", family: ".SF NS Display", path: "SFNSDisplay-Regular.otf")
554
+ }
555
+ internal enum ZapfDingbats: String, FontConvertible {
556
+ internal static let regular = FontConvertible(name: "ZapfDingbatsITC", family: "Zapf Dingbats", path: "ZapfDingbats.ttf")
557
+ }
558
+ }
559
+ ```
560
+ </details>
561
+
562
+ ### Usage Example
563
+
564
+ ```swift
565
+ // You can create fonts with the convenience constructor like this:
566
+ let displayRegular = UIFont(font: FontFamily.SFNSDisplay.regular, size: 20.0) // iOS
567
+ let dingbats = NSFont(font: FontFamily.ZapfDingbats.regular, size: 20.0) // macOS
568
+
569
+ // Or as an alternative, you can refer to enum instance and call .font on it:
570
+ let sameDisplayRegular = FontFamily.SFNSDisplay.regular.font(size: 20.0)
571
+ let sameDingbats = FontFamily.ZapfDingbats.regular.font(size: 20.0)
572
+ ```
573
+
574
+ ## Interface Builder
575
+
576
+ ```yaml
577
+ ib:
578
+ inputs: /dir/to/search/for/storyboards
579
+ outputs:
580
+ - templateName: scenes-swift5
581
+ output: Storyboard Scenes.swift
582
+ - templateName: segues-swift5
583
+ output: Storyboard Segues.swift
584
+ ```
585
+
586
+ This will generate an `enum` for each of your `NSStoryboard`/`UIStoryboard`, with respectively one `static let` per storyboard scene or segue.
587
+
588
+ <details>
589
+ <summary>Example of code generated by the bundled template</summary>
590
+
591
+ The generated code will look like this:
592
+
593
+ ```swift
594
+ // output from the scenes template
595
+
596
+ internal enum StoryboardScene {
597
+ internal enum Dependency: StoryboardType {
598
+ internal static let storyboardName = "Dependency"
599
+
600
+ internal static let dependent = SceneType<UIViewController>(storyboard: Dependency.self, identifier: "Dependent")
601
+ }
602
+ internal enum Message: StoryboardType {
603
+ internal static let storyboardName = "Message"
604
+
605
+ internal static let messagesList = SceneType<UITableViewController>(storyboard: Message.self, identifier: "MessagesList")
606
+ }
607
+ }
608
+
609
+ // output from the segues template
610
+
611
+ internal enum StoryboardSegue {
612
+ internal enum Message: String, SegueType {
613
+ case customBack = "CustomBack"
614
+ case embed = "Embed"
615
+ case nonCustom = "NonCustom"
616
+ case showNavCtrl = "Show-NavCtrl"
617
+ }
618
+ }
619
+ ```
620
+ </details>
621
+
622
+ ### Usage Example
623
+
624
+ ```swift
625
+ // You can instantiate scenes using the `instantiate` method:
626
+ let vc = StoryboardScene.Dependency.dependent.instantiate()
627
+
628
+ // You can perform segues using:
629
+ vc.perform(segue: StoryboardSegue.Message.embed)
630
+
631
+ // or match them (in prepareForSegue):
632
+ override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
633
+ switch StoryboardSegue.Message(segue) {
634
+ case .embed?:
635
+ // Prepare for your custom segue transition, passing information to the destionation VC
636
+ case .customBack?:
637
+ // Prepare for your custom segue transition, passing information to the destionation VC
638
+ default:
639
+ // Other segues from other scenes, not handled by this VC
640
+ break
641
+ }
642
+ }
643
+ ```
644
+
645
+ ## JSON and YAML
646
+
647
+ ```yaml
648
+ json:
649
+ inputs: /path/to/json/dir-or-file
650
+ outputs:
651
+ templateName: runtime-swift5
652
+ output: JSON.swift
653
+ yaml:
654
+ inputs: /path/to/yaml/dir-or-file
655
+ outputs:
656
+ templateName: inline-swift5
657
+ output: YAML.swift
658
+ ```
659
+
660
+ This will parse the given file, or when given a directory, recursively search for JSON and YAML files. It will define an `enum` for each file (and documents in a file where needed), and type-safe constants for the content of the file.
661
+
662
+ Unlike other parsers, this one is intended to allow you to use more custom inputs (as the formats are quite open to your needs) to generate your code. This means that for these parsers (and the `plist` one), you'll probably be more likely to use custom templates to generate code properly adapted/tuned to your inputs, rather than using the bundled templates. To read more about writing your own custom templates, see [see the dedicated documentation](Documentation/Articles/Creating-custom-templates.md).
663
+
664
+ <details>
665
+ <summary>Example of code generated by the bundled template</summary>
666
+
667
+ ```swift
668
+ internal enum JSONFiles {
669
+ internal enum Info {
670
+ private static let _document = JSONDocument(path: "info.json")
671
+ internal static let key1: String = _document["key1"]
672
+ internal static let key2: String = _document["key2"]
673
+ internal static let key3: [String: Any] = _document["key3"]
674
+ }
675
+ internal enum Sequence {
676
+ internal static let items: [Int] = objectFromJSON(at: "sequence.json")
677
+ }
678
+ }
679
+ ```
680
+ </details>
681
+
682
+ ### Usage Example
683
+
684
+ ```swift
685
+ // This will be a dictionary
686
+ let foo = JSONFiles.Info.key3
687
+
688
+ // This will be an [Int]
689
+ let bar = JSONFiles.Sequence.items
690
+ ```
691
+
692
+ ## Plists
693
+
694
+ ```yaml
695
+ plist:
696
+ inputs: /path/to/plist/dir-or-file
697
+ outputs:
698
+ templateName: runtime-swift5
699
+ output: Plist.swift
700
+ ```
701
+
702
+ This will parse the given file, or when given a directory, recursively search for Plist files. It will define an `enum` for each file (and documents in a file where needed), and type-safe constants for the content of the file.
703
+
704
+ Unlike other parsers, this one is intended to allow you to use more custom inputs (as the format is quite open to your needs) to generate your code. This means that for this parser (and the `json` and `yaml` ones), you'll probably be more likely to use custom templates to generate code properly adapted/tuned to your inputs, rather than using the bundled templates. To read more about writing your own custom templates, see [see the dedicated documentation](Documentation/Articles/Creating-custom-templates.md).
705
+
706
+ <details>
707
+ <summary>Example of code generated by the bundled template</summary>
708
+
709
+ ```swift
710
+ internal enum PlistFiles {
711
+ internal enum Test {
712
+ internal static let items: [String] = arrayFromPlist(at: "array.plist")
713
+ }
714
+ internal enum Stuff {
715
+ private static let _document = PlistDocument(path: "dictionary.plist")
716
+ internal static let key1: Int = _document["key1"]
717
+ internal static let key2: [String: Any] = _document["key2"]
718
+ }
719
+ }
720
+ ```
721
+ </details>
722
+
723
+ ### Usage Example
724
+
725
+ ```swift
726
+ // This will be an array
727
+ let foo = PlistFiles.Test.items
728
+
729
+ // This will be an Int
730
+ let bar = PlistFiles.Stuff.key1
731
+ ```
732
+
733
+ ## Strings
734
+
735
+ ```yaml
736
+ strings:
737
+ inputs: /path/to/language.lproj
738
+ outputs:
739
+ templateName: structured-swift5
740
+ output: Strings.swift
741
+ ```
742
+
743
+ This will generate a Swift `enum L10n` that will map all your `Localizable.strings` and `Localizable.stringsdict` (or other tables) keys to a `static let` constant. And if it detects placeholders like `%@`,`%d`,`%f`, it will generate a `static func` with the proper argument types instead, to provide type-safe formatting.
744
+
745
+ > Note that all dots within the key names are converted to dots in code (by using nested enums). You can provide a different separator than `.` to split key names into substructures by using a parser option – see [the parser documentation](Documentation/Parsers/strings.md).
746
+
747
+ <details>
748
+ <summary>Example of code generated by the structured bundled template</summary>
749
+
750
+ Given the following `Localizable.strings` file:
751
+
752
+ ```swift
753
+ "alert_title" = "Title of the alert";
754
+ "alert_message" = "Some alert body there";
755
+ "bananas.owner" = "Those %d bananas belong to %@.";
756
+ ```
757
+
758
+ And the following `Localizable.stringsdict` file:
759
+
760
+ ```xml
761
+ <?xml version="1.0" encoding="UTF-8"?>
762
+ <plist version="1.0">
763
+ <dict>
764
+ <key>apples.count</key>
765
+ <dict>
766
+ <key>NSStringLocalizedFormatKey</key>
767
+ <string>%#@apples@</string>
768
+ <key>apples</key>
769
+ <dict>
770
+ <key>NSStringFormatSpecTypeKey</key>
771
+ <string>NSStringPluralRuleType</string>
772
+ <key>NSStringFormatValueTypeKey</key>
773
+ <string>d</string>
774
+ <key>zero</key>
775
+ <string>You have no apples</string>
776
+ <key>one</key>
777
+ <string>You have one apple</string>
778
+ <key>other</key>
779
+ <string>You have %d apples. Wow that is a lot!</string>
780
+ </dict>
781
+ </dict>
782
+ </dict>
783
+ </plist>
784
+ ```
785
+
786
+ > _Reminder: Don't forget to end each line in your `*.strings` files with a semicolon `;`! Now that in Swift code we don't need semi-colons, it's easy to forget it's still required by the `Localizable.strings` file format 😉_
787
+
788
+ The generated code will contain this:
789
+
790
+ ```swift
791
+ internal enum L10n {
792
+ /// Some alert body there
793
+ internal static let alertMessage = L10n.tr("alert_message")
794
+ /// Title of the alert
795
+ internal static let alertTitle = L10n.tr("alert_title")
796
+
797
+ internal enum Apples {
798
+ /// Plural format key: "%#@apples@"
799
+ internal static func count(_ p1: Int) -> String {
800
+ return L10n.tr("apples.count", p1)
801
+ }
802
+ }
803
+
804
+ internal enum Bananas {
805
+ /// Those %d bananas belong to %@.
806
+ internal static func owner(_ p1: Int, _ p2: Any) -> String {
807
+ return L10n.tr("bananas.owner", p1, String(describing: p2))
808
+ }
809
+ }
810
+ }
811
+ ```
812
+ Note that if the same key is present in both the `.strings` and the `.stringsdict` files, SwiftGen will only consider the one in the `.stringsdict` file, as that's also how Foundation behaves at runtime.
813
+
814
+ </details>
815
+
816
+ ### Usage Example
817
+
818
+ Once the code has been generated by the script, you can use it this way in your Swift code:
819
+
820
+ ```swift
821
+ // Simple strings
822
+ let message = L10n.alertMessage
823
+ let title = L10n.alertTitle
824
+
825
+ // with parameters, note that each argument needs to be of the correct type
826
+ let apples = L10n.Apples.count(3)
827
+ let bananas = L10n.Bananas.owner(5, "Olivier")
828
+ ```
829
+
830
+ ### Flat Strings Support
831
+
832
+ SwiftGen also has a template to support flat strings files (i.e. without splitting the keys in substructures using "dot syntax"). The advantage is that your keys won't be mangled in any way; the disadvantage is that auto-completion won't be as nice.
833
+
834
+ <details>
835
+ <summary>Example of code generated by the flat bundled template</summary>
836
+
837
+ ```swift
838
+ internal enum L10n {
839
+ /// Some alert body there
840
+ internal static let alertMessage = L10n.tr("Localizable", "alert__message")
841
+ /// Title of the alert
842
+ internal static let alertTitle = L10n.tr("Localizable", "alert__title")
843
+ /// Plural format key: "%#@apples@"
844
+ internal static func applesCount(_ p1: Int) -> String {
845
+ return L10n.tr("Localizable", "apples.count", p1)
846
+ }
847
+ /// Those %d bananas belong to %@.
848
+ internal static func bananasOwner(_ p1: Int, _ p2: Any) -> String {
849
+ return L10n.tr("Localizable", "bananas.owner", p1, String(describing: p2))
850
+ }
851
+ }
852
+ ```
853
+ </details>
854
+
855
+ Given the same `Localizable.strings` and `Localizable.stringsdict` as above the usage will now be:
856
+
857
+ ```swift
858
+ // Simple strings
859
+ let message = L10n.alertMessage
860
+ let title = L10n.alertTitle
861
+
862
+ // with parameters, note that each argument needs to be of the correct type
863
+ let apples = L10n.applesCount(3)
864
+ let bananas = L10n.bananasOwner(5, "Olivier")
865
+ ```
866
+
867
+ ---
868
+
869
+ # Licence
870
+
871
+ This code and tool is under the MIT Licence. See the `LICENCE` file in this repository.
872
+
873
+ ## Attributions
874
+
875
+ This tool is powered by
876
+
877
+ - [Stencil](https://github.com/stencilproject/Stencil) and few other libs by [Kyle Fuller](https://github.com/kylef)
878
+ - SwiftGenKit and [StencilSwiftKit](https://github.com/SwiftGen/StencilSwiftKit), our internal frameworks at SwiftGen
879
+
880
+ It is currently mainly maintained by [@AliSoftware](https://github.com/AliSoftware) and [@djbe](https://github.com/djbe). But I couldn't thank enough all the other [contributors](https://github.com/SwiftGen/SwiftGen/graphs/contributors) to this tool along the different versions which helped make SwiftGen awesome! 🎉
881
+
882
+ If you want to contribute, don't hesitate to open a Pull Request, or even join the team!
883
+
884
+ ## Other Libraries / Tools
885
+
886
+ If you want to also get rid of String-based APIs not only for your ressources, but also for `UITableViewCell`, `UICollectionViewCell` and XIB-based views, you should take a look at my Mixin [Reusable](https://github.com/AliSoftware/Reusable).
887
+
888
+ If you want to generate Swift code from your own Swift code (so meta!), like generate `Equatable` conformance to your types and a lot of other similar things, use [Sourcery](https://github.com/krzysztofzablocki/Sourcery).
889
+
890
+ _SwiftGen and Sourcery are complementary tools. In fact, Sourcery uses `Stencil` too, as well as SwiftGen's `StencilSwiftKit` so you can use the exact same syntax for your templates for both!_
891
+
892
+ You can also [follow me on twitter](http://twitter.com/aligatr) for news/updates about other projects I am creating, or [read my blog](https://alisoftware.github.io).