9
9
10
10
import Foundation
11
11
12
- // MARK: Types
13
-
14
- let ResourceFilename = " R.generated.swift "
15
-
16
- struct AssetFolder {
17
- let name : String
18
- let imageAssets : [ String ]
12
+ // MARK: Helper functions
19
13
20
- init ( url: NSURL , fileManager: NSFileManager ) {
21
- name = url. filename!
14
+ let indent = indentWithString ( IndentationString)
22
15
23
- let contents = fileManager. contentsOfDirectoryAtURL ( url, includingPropertiesForKeys: nil , options: NSDirectoryEnumerationOptions . SkipsHiddenFiles, error: nil ) as [ NSURL ]
24
- imageAssets = contents. map { $0. filename! }
25
- }
16
+ func warn( warning: String ) {
17
+ println ( " warning: \( warning) " )
26
18
}
27
19
28
- struct Storyboard {
29
- let name : String
30
- let segues : [ String ]
31
- let viewControllers : [ ViewController ]
32
- let usedImageIdentifiers : [ String ]
33
-
34
- init ( url: NSURL ) {
35
- name = url. filename!
36
-
37
- let parserDelegate = StoryboardParserDelegate ( )
38
-
39
- let parser = NSXMLParser ( contentsOfURL: url) !
40
- parser. delegate = parserDelegate
41
- parser. parse ( )
42
-
43
- segues = parserDelegate. segues
44
- viewControllers = parserDelegate. viewControllers
45
- usedImageIdentifiers = parserDelegate. usedImageIdentifiers
46
- }
47
-
48
- struct ViewController {
49
- let storyboardIdentifier : String
50
- let customModule : String ?
51
- let customClass : String
52
-
53
- func fullyQualifiedClass( ) -> String {
54
- if let customModule = customModule {
55
- return customModule + " . " + customClass
56
- }
57
-
58
- return customClass
59
- }
60
- }
20
+ func fail( error: String ) {
21
+ println ( " error: \( error) " )
61
22
}
62
23
63
- class StoryboardParserDelegate : NSObject , NSXMLParserDelegate {
64
- var segues : [ String ] = [ ]
65
- var viewControllers : [ Storyboard . ViewController ] = [ ]
66
- var usedImageIdentifiers : [ String ] = [ ]
67
-
68
- func parser( parser: NSXMLParser ! , didStartElement elementName: String ! , namespaceURI: String ! , qualifiedName qName: String ! , attributes attributeDict: [ NSObject : AnyObject ] ! ) {
69
- switch elementName {
70
- case " segue " :
71
- if let segueIdentifier = attributeDict [ " identifier " ] as? String {
72
- segues. append ( segueIdentifier)
73
- }
74
-
75
- case " image " :
76
- if let imageIdentifier = attributeDict [ " name " ] as? String {
77
- usedImageIdentifiers. append ( imageIdentifier)
78
- }
79
-
80
- default :
81
- if let viewController = viewControllerFromAttributes ( attributeDict) {
82
- viewControllers. append ( viewController)
83
- }
84
- }
85
- }
86
-
87
- func viewControllerFromAttributes( attributeDict: [ NSObject : AnyObject ] ) -> Storyboard . ViewController ? {
88
- if attributeDict [ " sceneMemberID " ] as? String == " viewController " {
89
- if let storyboardIdentifier = attributeDict [ " storyboardIdentifier " ] as? String {
90
- let customModule = attributeDict [ " customModule " ] as? String
91
- let customClass = attributeDict [ " customClass " ] as? String ?? " UIViewController "
92
-
93
- return Storyboard . ViewController ( storyboardIdentifier: storyboardIdentifier, customModule: customModule, customClass: customClass)
94
- }
95
- }
96
-
97
- return nil
24
+ func failOnError( error: NSError ? ) {
25
+ if let error = error {
26
+ fail ( " \( error) " )
98
27
}
99
28
}
100
29
101
- // MARK: Helper functions
102
-
103
- let IndentationString = " "
104
- let indent = indentWithString ( IndentationString)
105
-
106
30
func inputDirectories( processInfo: NSProcessInfo ) -> [ NSURL ] {
107
31
return processInfo. arguments. skip ( 1 ) . map { NSURL ( fileURLWithPath: $0 as String ) ! }
108
32
}
109
33
110
34
func filterDirectoryContentsRecursively( fileManager: NSFileManager , filter: ( NSURL ) -> Bool ) ( url: NSURL ) -> [ NSURL ] {
111
35
var assetFolders = [ NSURL] ( )
112
36
113
- if let enumerator = fileManager. enumeratorAtURL ( url, includingPropertiesForKeys: [ NSURLIsDirectoryKey] , options: NSDirectoryEnumerationOptions . SkipsHiddenFiles|NSDirectoryEnumerationOptions . SkipsPackageDescendants, errorHandler: nil ) {
37
+ let errorHandler : ( NSURL ! , NSError ! ) -> Bool = { url, error in
38
+ failOnError ( error)
39
+ return true
40
+ }
41
+
42
+ if let enumerator = fileManager. enumeratorAtURL ( url, includingPropertiesForKeys: [ NSURLIsDirectoryKey] , options: NSDirectoryEnumerationOptions . SkipsHiddenFiles|NSDirectoryEnumerationOptions . SkipsPackageDescendants, errorHandler: errorHandler) {
114
43
115
44
while let enumeratorItem: AnyObject = enumerator. nextObject ( ) {
116
45
if let url = enumeratorItem as? NSURL {
@@ -126,55 +55,110 @@ func filterDirectoryContentsRecursively(fileManager: NSFileManager, filter: (NSU
126
55
return assetFolders
127
56
}
128
57
129
- func sanitizedSwiftName( name: String ) -> String {
58
+ func sanitizedSwiftName( name: String , lowercaseFirstCharacter : Bool = true ) -> String {
130
59
var components = name. componentsSeparatedByString ( " - " )
131
60
let firstComponent = components. removeAtIndex ( 0 )
132
- return components. reduce ( firstComponent) { $0 + $1. capitalizedString } . lowercaseFirstCharacter
61
+ let swiftName = components. reduce ( firstComponent) { $0 + $1. capitalizedString }
62
+
63
+ return lowercaseFirstCharacter ? swiftName. lowercaseFirstCharacter : swiftName
133
64
}
134
65
135
66
func writeResourceFile( code: String , toFolderURL folderURL: NSURL ) {
136
67
let outputURL = folderURL. URLByAppendingPathComponent ( ResourceFilename)
137
- code. writeToURL ( outputURL, atomically: true , encoding: NSUTF8StringEncoding, error: nil )
68
+
69
+ var error : NSError ?
70
+ code. writeToURL ( outputURL, atomically: true , encoding: NSUTF8StringEncoding, error: & error)
71
+
72
+ failOnError ( error)
138
73
}
139
74
140
- // MARK: Code generator functions
75
+ func readResourceFile( folderURL: NSURL ) -> String ? {
76
+ let inputURL = folderURL. URLByAppendingPathComponent ( ResourceFilename)
77
+
78
+ if let resourceFileString = String ( contentsOfURL: inputURL, encoding: NSUTF8StringEncoding, error: nil ) {
79
+ return resourceFileString
80
+ }
141
81
142
- func swiftImports( ) -> String {
143
- return " import UIKit "
82
+ return nil
144
83
}
145
84
146
- func swiftImageStructWithAssetFolders( assetFolders: [ AssetFolder ] ) -> String {
147
- return distinct ( assetFolders. flatMap { $0. imageAssets } )
148
- . reduce ( " struct image { \n " ) {
149
- $0 + " static var \( sanitizedSwiftName ( $1) ) : UIImage? { return UIImage(named: \" \( $1) \" ) } \n "
150
- } + " } "
85
+ // MARK: Struct/function generators
86
+
87
+ // Image
88
+
89
+ func imageStructFromAssetFolders( assetFolders: [ AssetFolder ] ) -> Struct {
90
+ let vars = distinct ( assetFolders. flatMap { $0. imageAssets } )
91
+ . map { Var ( name: $0, type: Type . _UIImage. asOptional ( ) , getter: " return UIImage(named: \" \( $0) \" ) " ) }
92
+
93
+ return Struct ( name: " image " , vars: vars, functions: [ ] , structs: [ ] )
151
94
}
152
95
153
- func swiftSegueStructWithStoryboards( storyboards: [ Storyboard ] ) -> String {
154
- return distinct ( storyboards. flatMap { $0. segues } )
155
- . reduce ( " struct segue { \n " ) {
156
- $0 + " static var \( sanitizedSwiftName ( $1) ) : String { return \" \( $1) \" } \n "
157
- } + " } "
96
+ // Segue
97
+
98
+ func segueStructFromStoryboards( storyboards: [ Storyboard ] ) -> Struct {
99
+ let vars = distinct ( storyboards. flatMap { $0. segues } )
100
+ . map { Var ( name: $0, type: Type . _String, getter: " return \" \( $0) \" " ) }
101
+
102
+ return Struct ( name: " segue " , vars: vars, functions: [ ] , structs: [ ] )
158
103
}
159
104
160
- func swiftStructForStoryboard( storyboard: Storyboard ) -> String {
161
- let instanceVar = " static var instance: UIStoryboard { return UIStoryboard(name: \" \( storyboard. name) \" , bundle: nil) } "
105
+ // Storyboard
162
106
163
- let viewControllers = storyboard. viewControllers. reduce ( " " ) {
164
- $0 + " static var \( sanitizedSwiftName ( $1. storyboardIdentifier) ) : \( $1. fullyQualifiedClass ( ) ) ? { return instance.instantiateViewControllerWithIdentifier( \" \( $1. storyboardIdentifier) \" ) as? \( $1. fullyQualifiedClass ( ) ) } \n "
165
- }
107
+ func storyboardStructFromStoryboards( storyboards: [ Storyboard ] ) -> Struct {
108
+ return Struct ( name: " storyboard " , vars: [ ] , functions: [ ] , structs: storyboards. map ( storyboardStructForStoryboard) )
109
+ }
110
+
111
+ func storyboardStructForStoryboard( storyboard: Storyboard ) -> Struct {
112
+ let instanceVars = [ Var ( name: " instance " , type: Type . _UIStoryboard, getter: " return UIStoryboard(name: \" \( storyboard. name) \" , bundle: nil) " ) ]
166
113
167
- let validateStoryboardImages = distinct ( storyboard. usedImageIdentifiers)
168
- . reduce ( " static func validateImages() { \n " ) {
169
- $0 + " assert(UIImage(named: \" \( $1) \" ) != nil, \" [R.swift] Image named ' \( $1) ' is used in storyboard ' \( storyboard. name) ', but couldn't be loaded. \" ) \n "
170
- } + " } "
114
+ let viewControllerVars = storyboard. viewControllers
115
+ . map { Var ( name: $0. storyboardIdentifier, type: $0. type. asOptional ( ) , getter: " return instance.instantiateViewControllerWithIdentifier( \" \( $0. storyboardIdentifier) \" ) as? \( $0. type. asNonOptional ( ) ) " ) }
116
+
117
+ let validateImagesLines = distinct ( storyboard. usedImageIdentifiers)
118
+ . map { " assert(UIImage(named: \" \( $0) \" ) != nil, \" [R.swift] Image named ' \( $0) ' is used in storyboard ' \( storyboard. name) ', but couldn't be loaded. \" ) " }
119
+ let validateImagesFunc = Function ( name: " validateImages " , parameters: [ ] , returnType: Type . _Void, body: join ( " \n " , validateImagesLines) )
120
+
121
+ let validateViewControllersLines = storyboard. viewControllers
122
+ . map { " assert( \( sanitizedSwiftName ( $0. storyboardIdentifier) ) != nil, \" [R.swift] ViewController with identifier ' \( sanitizedSwiftName ( $0. storyboardIdentifier) ) ' could not be loaded from storyboard ' \( storyboard. name) ' as ' \( $0. type) '. \" ) " }
123
+ let validateViewControllersFunc = Function ( name: " validateViewControllers " , parameters: [ ] , returnType: Type . _Void, body: join ( " \n " , validateViewControllersLines) )
124
+
125
+ return Struct ( name: storyboard. name, vars: instanceVars + viewControllerVars, functions: [ validateImagesFunc, validateViewControllersFunc] , structs: [ ] )
126
+ }
127
+
128
+ // Nib
129
+
130
+ func nibStructFromNibs( nibs: [ Nib ] ) -> Struct {
131
+ return Struct ( name: " nib " , vars: [ ] , functions: [ ] , structs: nibs. map ( nibStructForNib) )
132
+ }
133
+
134
+ func nibStructForNib( nib: Nib ) -> Struct {
135
+ let ownerOrNilParameter = Function . Parameter ( name: " ownerOrNil " , type: Type . _AnyObject. asOptional ( ) )
136
+ let optionsOrNilParameter = Function . Parameter ( name: " options " , localName: " optionsOrNil " , type: Type ( className: " [NSObject : AnyObject] " , optional: true ) )
137
+
138
+ let instanceVars = [ Var ( name: " instance " , type: Type . _UINib, getter: " return UINib.init(nibName: \" \( nib. name) \" , bundle: nil) " ) ]
139
+ let instantiateFunc = Function ( name: " instantiateWithOwner " , parameters: [ ownerOrNilParameter, optionsOrNilParameter] , returnType: Type ( className: " [AnyObject] " ) , body: " return instance.instantiateWithOwner(ownerOrNil, options: optionsOrNil) " )
140
+
141
+ let viewFuncs = zip ( nib. rootViews, Ordinals)
142
+ . map { ( view: $0. 0 , ordinal: $0. 1 ) }
143
+ . map { Function ( name: " \( $0. ordinal. word) View " , parameters: [ ownerOrNilParameter, optionsOrNilParameter] , returnType: $0. view. asOptional ( ) , body: " return instantiateWithOwner(ownerOrNil, options: optionsOrNil)[ \( $0. ordinal. number - 1 ) ] as? \( $0. view) " ) }
144
+
145
+ return Struct ( name: nib. name, vars: instanceVars, functions: [ instantiateFunc] + viewFuncs, structs: [ ] )
146
+ }
147
+
148
+ // Reuse identifiers
149
+
150
+ func reuseIdentifierStructFromReuseIdentifierContainers( containers: [ ReuseIdentifierContainer ] ) -> Struct {
151
+ let reuseIdentifierVars = containers
152
+ . flatMap { $0. reuseIdentifiers }
153
+ . map { Var ( name: $0, type: Type . _String, getter: " return \" \( $0) \" " ) }
154
+
155
+ return Struct ( name: " reuseIdentifier " , vars: reuseIdentifierVars, functions: [ ] , structs: [ ] )
156
+ }
171
157
172
- let validateStoryboardViewControllers = storyboard. viewControllers
173
- . reduce ( " static func validateViewControllers() { \n " ) {
174
- $0 + " assert( \( sanitizedSwiftName ( $1. storyboardIdentifier) ) != nil, \" [R.swift] ViewController with identifier ' \( sanitizedSwiftName ( $1. storyboardIdentifier) ) ' could not be loaded from storyboard ' \( storyboard. name) ' as ' \( $1. fullyQualifiedClass ( ) ) '. \" ) \n "
175
- } + " } "
158
+ // Validation
176
159
177
- return " struct \( sanitizedSwiftName ( storyboard. name) ) { \n " + indent( string: instanceVar) + " \n " + indent( string: viewControllers) + indent( string: validateStoryboardImages) + " \n " + indent( string: validateStoryboardViewControllers) + " } "
160
+ func validateAllFunctionWithStoryboards( storyboards: [ Storyboard ] ) -> Function {
161
+ return Function ( name: " validate " , parameters: [ ] , returnType: Type . _Void, body: storyboards. map ( swiftCallStoryboardValidators) . reduce ( " " , combine: + ) )
178
162
}
179
163
180
164
func swiftCallStoryboardValidators( storyboard: Storyboard ) -> String {
0 commit comments