Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
78be15d57d | |||
d6c4702390 | |||
1e073af5df | |||
188178fe6a | |||
c31d0b1618 | |||
b662fc64f3 | |||
9ab7e74991 | |||
fc427733ee | |||
5a3d273acc |
@ -102,6 +102,20 @@
|
|||||||
ReferencedContainer = "container:">
|
ReferencedContainer = "container:">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
|
<CommandLineArguments>
|
||||||
|
<CommandLineArgument
|
||||||
|
argument = "generate"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</CommandLineArgument>
|
||||||
|
<CommandLineArgument
|
||||||
|
argument = ""$(PROJECT_DIR)/../SampleFiles/resgenConfiguration.yml""
|
||||||
|
isEnabled = "YES">
|
||||||
|
</CommandLineArgument>
|
||||||
|
<CommandLineArgument
|
||||||
|
argument = "--project-directory "$(PROJECT_DIR)""
|
||||||
|
isEnabled = "YES">
|
||||||
|
</CommandLineArgument>
|
||||||
|
</CommandLineArguments>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
|
34
CHANGELOG.md
34
CHANGELOG.md
@ -0,0 +1,34 @@
|
|||||||
|
# v1.2 - Architecture generation
|
||||||
|
|
||||||
|
## New
|
||||||
|
- New section in configuration file: `architecture`. Define your ressources accessors achitecture and let ResgenSwift generate it for you. Check out Readme to know more.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
- Errors and Warnings are now shown in Xcode Issue Navigator
|
||||||
|
|
||||||
|
---
|
||||||
|
# v1.1 - SwiftUI compatibility
|
||||||
|
|
||||||
|
## New
|
||||||
|
- Update plist `UIAppFonts` when generated fonts (use plistBuddy)
|
||||||
|
- New parameter: `infoPlistPaths`
|
||||||
|
- Generate SwiftUI extensions for colors, fonts and images
|
||||||
|
- New parameter: `extensionNameSwiftUI`
|
||||||
|
- Adding Makefile to install, unsintall and create man page.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
Fix SwiftLint rule `trailing_newline`
|
||||||
|
|
||||||
|
---
|
||||||
|
# v1.0 - Configuration file
|
||||||
|
|
||||||
|
## Major
|
||||||
|
- A new command has been added: `generate`. Instead of runnning every single command, it will run all necessary command based on a `yaml` configuration file. Check out Readme to know more.
|
||||||
|
|
||||||
|
## Minors
|
||||||
|
- Code refactoring
|
||||||
|
- Huge performance improvements
|
||||||
|
- Readme.md update
|
||||||
|
- Add option to generate static properties/methods (`staticMembers`)
|
||||||
|
- Add option to specify the project directory (`--project-directory`). It allows to run ResgenSwift from anywhere
|
||||||
|
- Add `install.sh` script to install ResgenSwift in `/usr/local/bin`
|
||||||
|
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
@ -1,6 +1,6 @@
|
|||||||
library "openiumpipeline"
|
library "openiumpipeline"
|
||||||
|
|
||||||
env.DEVELOPER_DIR="/Applications/Xcode_13.3.0.app/Contents/Developer"
|
env.DEVELOPER_DIR= "/Applications/Xcode-14.3.0.app/Contents/Developer"
|
||||||
//env.SIMULATOR_DEVICE_TYPES="iPad--7th-generation-"
|
//env.SIMULATOR_DEVICE_TYPES="iPad--7th-generation-"
|
||||||
env.IS_PACKAGE_SWIFT=1
|
env.IS_PACKAGE_SWIFT=1
|
||||||
env.TARGETS_MACOS=1
|
env.TARGETS_MACOS=1
|
||||||
|
61
README.md
61
README.md
@ -261,6 +261,67 @@ tags: []
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### File architecture
|
||||||
|
|
||||||
|
ResgenSwift generate extension of classes. Those classes must exists in your project. You can create them yourself OR you can let ResgenSwift create them by specifying what you want. Do as follow:
|
||||||
|
|
||||||
|
```
|
||||||
|
architecture:
|
||||||
|
property: R *(required but not used)*
|
||||||
|
classname: R
|
||||||
|
path: ./path/to/generate
|
||||||
|
children:
|
||||||
|
- property: images
|
||||||
|
classname: R2Image
|
||||||
|
- property: strings
|
||||||
|
classname: R2String
|
||||||
|
- property: fonts
|
||||||
|
classname: R2Font
|
||||||
|
- property: images
|
||||||
|
classname: R2Image
|
||||||
|
- property: uikit
|
||||||
|
classname: R2UI
|
||||||
|
children:
|
||||||
|
- property: images
|
||||||
|
classname: R2UIImage
|
||||||
|
- property: fonts
|
||||||
|
classname: R2UIFont
|
||||||
|
- property: images
|
||||||
|
classname: R2UIImage
|
||||||
|
```
|
||||||
|
|
||||||
|
This will generate a file named as the architecture classname: `R.swift`. Based on the previous architecture, it will generate:
|
||||||
|
```
|
||||||
|
class R {
|
||||||
|
static let images = R2Image()
|
||||||
|
static let strings = R2String()
|
||||||
|
static let fonts = R2Font()
|
||||||
|
static let images = R2Image()
|
||||||
|
static let uikit = R2UI()
|
||||||
|
}
|
||||||
|
|
||||||
|
class R2Image {}
|
||||||
|
|
||||||
|
class R2String {}
|
||||||
|
|
||||||
|
class R2Font {}
|
||||||
|
|
||||||
|
class R2Image {}
|
||||||
|
|
||||||
|
class R2UI {
|
||||||
|
let images = R2UIImage()
|
||||||
|
let fonts = R2UIFont()
|
||||||
|
let images = R2UIImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
class R2UIImage {}
|
||||||
|
|
||||||
|
class R2UIFont {}
|
||||||
|
|
||||||
|
class R2UIImage {}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated by ResgenSwift.Color 1.0
|
// Generated by ResgenSwift.Color 1.2
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
@ -18,4 +18,4 @@ extension ColorYolo {
|
|||||||
var blue_light_dark: Color {
|
var blue_light_dark: Color {
|
||||||
Color("blue_light_dark")
|
Color("blue_light_dark")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated by ResgenSwift.Color 1.0
|
// Generated by ResgenSwift.Color 1.2
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@ -18,4 +18,4 @@ extension UIColorYolo {
|
|||||||
@objc var blue_light_dark: UIColor {
|
@objc var blue_light_dark: UIColor {
|
||||||
UIColor(named: "blue_light_dark")!
|
UIColor(named: "blue_light_dark")!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated by ResgenSwift.Fonts 1.0
|
// Generated by ResgenSwift.Fonts 1.2
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
@ -58,4 +58,4 @@ extension FontYolo {
|
|||||||
func LatoHairlineItalic(withSize size: CGFloat) -> Font {
|
func LatoHairlineItalic(withSize size: CGFloat) -> Font {
|
||||||
Font.custom(FontName.LatoHairlineItalic.rawValue, size: size)
|
Font.custom(FontName.LatoHairlineItalic.rawValue, size: size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated by ResgenSwift.Fonts 1.0
|
// Generated by ResgenSwift.Fonts 1.2
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@ -58,4 +58,4 @@ extension UIFontYolo {
|
|||||||
func LatoHairlineItalic(withSize size: CGFloat) -> UIFont {
|
func LatoHairlineItalic(withSize size: CGFloat) -> UIFont {
|
||||||
UIFont(name: FontName.LatoHairlineItalic.rawValue, size: size)!
|
UIFont(name: FontName.LatoHairlineItalic.rawValue, size: size)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated by ResgenSwift.Images 1.0
|
// Generated by ResgenSwift.Images 1.2
|
||||||
// Images from sampleImages
|
// Images from sampleImages
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
@ -28,4 +28,4 @@ extension ImageYolo {
|
|||||||
var ic_close_article: Image {
|
var ic_close_article: Image {
|
||||||
Image("ic_close_article")
|
Image("ic_close_article")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated by ResgenSwift.Images 1.0
|
// Generated by ResgenSwift.Images 1.2
|
||||||
// Images from sampleImages
|
// Images from sampleImages
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
@ -28,4 +28,4 @@ extension UIImage {
|
|||||||
var ic_close_article: UIImage {
|
var ic_close_article: UIImage {
|
||||||
UIImage(named: "ic_close_article")!
|
UIImage(named: "ic_close_article")!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated by ResgenSwift.Strings.Stringium 1.0
|
// Generated by ResgenSwift.Strings.Stringium 1.2
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@ -6,6 +6,15 @@ fileprivate let kStringsFileName = "sampleStrings"
|
|||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
|
|
||||||
|
enum Key: String {
|
||||||
|
case param_lang = "param_lang"
|
||||||
|
case generic_back = "generic_back"
|
||||||
|
case generic_loading_data = "generic_loading_data"
|
||||||
|
case generic_welcome_firstname_format = "generic_welcome_firstname_format"
|
||||||
|
case test_equal_symbol = "test_equal_symbol"
|
||||||
|
case placeholders_test_one = "placeholders_test_one"
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Webservice
|
// MARK: - Webservice
|
||||||
|
|
||||||
/// Translation in en :
|
/// Translation in en :
|
||||||
@ -61,4 +70,4 @@ extension String {
|
|||||||
func placeholders_test_one(arg0: String, arg1: String, arg2: Int) -> String {
|
func placeholders_test_one(arg0: String, arg1: String, arg2: Int) -> String {
|
||||||
String(format: self.placeholders_test_one, arg0, arg1, arg2)
|
String(format: self.placeholders_test_one, arg0, arg1, arg2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Apple Strings File
|
* Apple Strings File
|
||||||
* Generated by ResgenSwift 1.0
|
* Generated by ResgenSwift 1.2
|
||||||
* Language: en-us
|
* Language: en-us
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Apple Strings File
|
* Apple Strings File
|
||||||
* Generated by ResgenSwift 1.0
|
* Generated by ResgenSwift 1.2
|
||||||
* Language: en
|
* Language: en
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Apple Strings File
|
* Apple Strings File
|
||||||
* Generated by ResgenSwift 1.0
|
* Generated by ResgenSwift 1.2
|
||||||
* Language: fr
|
* Language: fr
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated by ResgenSwift.Strings.Tags 1.0
|
// Generated by ResgenSwift.Strings.Tags 1.2
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@ -17,4 +17,4 @@ extension Tags {
|
|||||||
var screen_two: String {
|
var screen_two: String {
|
||||||
"Ecran deux"
|
"Ecran deux"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,30 @@
|
|||||||
---
|
---
|
||||||
|
#
|
||||||
|
# Class architecture
|
||||||
|
#
|
||||||
|
architecture:
|
||||||
|
property: R
|
||||||
|
classname: R
|
||||||
|
path: ./Tags
|
||||||
|
children:
|
||||||
|
- property: images
|
||||||
|
classname: R2Image
|
||||||
|
- property: strings
|
||||||
|
classname: R2String
|
||||||
|
- property: fonts
|
||||||
|
classname: R2Font
|
||||||
|
- property: images
|
||||||
|
classname: R2Image
|
||||||
|
- property: ui
|
||||||
|
classname: R2UI
|
||||||
|
children:
|
||||||
|
- property: images
|
||||||
|
classname: R2UIImage
|
||||||
|
- property: fonts
|
||||||
|
classname: R2UIFont
|
||||||
|
- property: images
|
||||||
|
classname: R2UIImage
|
||||||
|
|
||||||
#
|
#
|
||||||
# Strings
|
# Strings
|
||||||
#
|
#
|
||||||
|
@ -77,21 +77,21 @@ struct Colors: ParsableCommand {
|
|||||||
// Check if input file exists
|
// Check if input file exists
|
||||||
guard fileManager.fileExists(atPath: options.inputFile) else {
|
guard fileManager.fileExists(atPath: options.inputFile) else {
|
||||||
let error = ColorsToolError.fileNotExists(options.inputFile)
|
let error = ColorsToolError.fileNotExists(options.inputFile)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Colors.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if xcassets file exists
|
// Check if xcassets file exists
|
||||||
guard fileManager.fileExists(atPath: options.xcassetsPath) else {
|
guard fileManager.fileExists(atPath: options.xcassetsPath) else {
|
||||||
let error = ColorsToolError.fileNotExists(options.xcassetsPath)
|
let error = ColorsToolError.fileNotExists(options.xcassetsPath)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Colors.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extension for UIKit and SwiftUI should have different name
|
// Extension for UIKit and SwiftUI should have different name
|
||||||
guard options.extensionName != options.extensionNameSwiftUI else {
|
guard options.extensionName != options.extensionNameSwiftUI else {
|
||||||
let error = ColorsToolError.extensionNamesCollision(options.extensionName)
|
let error = ColorsToolError.extensionNamesCollision(options.extensionName)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Colors.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ struct Colors: ParsableCommand {
|
|||||||
try fileManager.removeItem(atPath: assetsColorPath)
|
try fileManager.removeItem(atPath: assetsColorPath)
|
||||||
} catch {
|
} catch {
|
||||||
let error = ColorsToolError.deleteExistingColors("\(options.xcassetsPath)/Colors")
|
let error = ColorsToolError.deleteExistingColors("\(options.xcassetsPath)/Colors")
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Colors.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,28 +20,28 @@ enum ColorsToolError: Error {
|
|||||||
var description: String {
|
var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .extensionNamesCollision(let extensionName):
|
case .extensionNamesCollision(let extensionName):
|
||||||
return "error:[\(Fonts.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
|
return "error: [\(Fonts.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
|
||||||
|
|
||||||
case .badFormat(let info):
|
case .badFormat(let info):
|
||||||
return "error:[\(Colors.toolName)] Bad line format: \(info). Accepted format are: colorName=\"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\" \"#RGB/#ARGB\""
|
return "error: [\(Colors.toolName)] Bad line format: \(info). Accepted format are: colorName=\"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\" \"#RGB/#ARGB\""
|
||||||
|
|
||||||
case .writeAsset(let info):
|
case .writeAsset(let info):
|
||||||
return "error:[\(Colors.toolName)] An error occured while writing color in Xcasset: \(info)"
|
return "error: [\(Colors.toolName)] An error occured while writing color in Xcasset: \(info)"
|
||||||
|
|
||||||
case .createAssetFolder(let assetsFolder):
|
case .createAssetFolder(let assetsFolder):
|
||||||
return "error:[\(Colors.toolName)] An error occured while creating colors folder `\(assetsFolder)`"
|
return "error: [\(Colors.toolName)] An error occured while creating colors folder `\(assetsFolder)`"
|
||||||
|
|
||||||
case .writeExtension(let filename, let info):
|
case .writeExtension(let filename, let info):
|
||||||
return "error:[\(Colors.toolName)] An error occured while writing extension in \(filename): \(info)"
|
return "error: [\(Colors.toolName)] An error occured while writing extension in \(filename): \(info)"
|
||||||
|
|
||||||
case .fileNotExists(let filename):
|
case .fileNotExists(let filename):
|
||||||
return "error:[\(Colors.toolName)] File \(filename) does not exists"
|
return "error: [\(Colors.toolName)] File \(filename) does not exists"
|
||||||
|
|
||||||
case .badColorDefinition(let lightColor, let darkColor):
|
case .badColorDefinition(let lightColor, let darkColor):
|
||||||
return "error:[\(Colors.toolName)] One of these two colors has invalid synthax: -\(lightColor)- or -\(darkColor)-"
|
return "error: [\(Colors.toolName)] One of these two colors has invalid synthax: -\(lightColor)- or -\(darkColor)-"
|
||||||
|
|
||||||
case .deleteExistingColors(let assetsFolder):
|
case .deleteExistingColors(let assetsFolder):
|
||||||
return "error:[\(Colors.toolName)] An error occured while deleting colors folder `\(assetsFolder)`"
|
return "error: [\(Colors.toolName)] An error occured while deleting colors folder `\(assetsFolder)`"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ struct ColorExtensionGenerator {
|
|||||||
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch (let error) {
|
} catch (let error) {
|
||||||
let error = ColorsToolError.writeExtension(extensionFilePath, error.localizedDescription)
|
let error = ColorsToolError.writeExtension(extensionFilePath, error.localizedDescription)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Colors.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ struct ColorXcassetHelper {
|
|||||||
withIntermediateDirectories: true)
|
withIntermediateDirectories: true)
|
||||||
} catch {
|
} catch {
|
||||||
let error = ColorsToolError.createAssetFolder(colorSetPath)
|
let error = ColorsToolError.createAssetFolder(colorSetPath)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Colors.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ struct ColorXcassetHelper {
|
|||||||
try color.contentsJSON().write(to: contentsJsonPathURL, atomically: false, encoding: .utf8)
|
try color.contentsJSON().write(to: contentsJsonPathURL, atomically: false, encoding: .utf8)
|
||||||
} catch (let error) {
|
} catch (let error) {
|
||||||
let error = ColorsToolError.writeAsset(error.localizedDescription)
|
let error = ColorsToolError.writeAsset(error.localizedDescription)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Colors.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ struct ParsedColor {
|
|||||||
|
|
||||||
guard allComponents.contains(true) == false else {
|
guard allComponents.contains(true) == false else {
|
||||||
let error = ColorsToolError.badColorDefinition(light, dark)
|
let error = ColorsToolError.badColorDefinition(light, dark)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Colors.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ class ColorFileParser {
|
|||||||
|
|
||||||
guard colorContent.count >= 2 else {
|
guard colorContent.count >= 2 else {
|
||||||
let error = ColorsToolError.badFormat(colorLine)
|
let error = ColorsToolError.badFormat(colorLine)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Colors.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,14 +74,14 @@ struct Fonts: ParsableCommand {
|
|||||||
// Check input file exists
|
// Check input file exists
|
||||||
guard fileManager.fileExists(atPath: options.inputFile) else {
|
guard fileManager.fileExists(atPath: options.inputFile) else {
|
||||||
let error = FontsToolError.fileNotExists(options.inputFile)
|
let error = FontsToolError.fileNotExists(options.inputFile)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Fonts.exit(withError: error)
|
Fonts.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extension for UIKit and SwiftUI should have different name
|
// Extension for UIKit and SwiftUI should have different name
|
||||||
guard options.extensionName != options.extensionNameSwiftUI else {
|
guard options.extensionName != options.extensionNameSwiftUI else {
|
||||||
let error = FontsToolError.extensionNamesCollision(options.extensionName)
|
let error = FontsToolError.extensionNamesCollision(options.extensionName)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Fonts.exit(withError: error)
|
Fonts.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,22 +14,22 @@ enum FontsToolError: Error {
|
|||||||
case fileNotExists(String)
|
case fileNotExists(String)
|
||||||
case writeExtension(String, String)
|
case writeExtension(String, String)
|
||||||
|
|
||||||
var localizedDescription: String {
|
var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .extensionNamesCollision(let extensionName):
|
case .extensionNamesCollision(let extensionName):
|
||||||
return "error:[\(Fonts.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
|
return "error: [\(Fonts.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
|
||||||
|
|
||||||
case .fcScan(let path, let code, let output):
|
case .fcScan(let path, let code, let output):
|
||||||
return "error:[\(Fonts.toolName)] Error while getting fontName (fc-scan --format %{postscriptname} \(path). fc-scan exit with \(code) and output is: \(output ?? "no output")"
|
return "error: [\(Fonts.toolName)] Error while getting fontName (fc-scan --format %{postscriptname} \(path). fc-scan exit with \(code) and output is: \(output ?? "no output")"
|
||||||
|
|
||||||
case .inputFolderNotFound(let inputFolder):
|
case .inputFolderNotFound(let inputFolder):
|
||||||
return " error:[\(Fonts.toolName)] Input folder not found: \(inputFolder)"
|
return "error: [\(Fonts.toolName)] Input folder not found: \(inputFolder)"
|
||||||
|
|
||||||
case .fileNotExists(let filename):
|
case .fileNotExists(let filename):
|
||||||
return " error:[\(Fonts.toolName)] File \(filename) does not exists"
|
return "error: [\(Fonts.toolName)] File \(filename) does not exists"
|
||||||
|
|
||||||
case .writeExtension(let filename, let info):
|
case .writeExtension(let filename, let info):
|
||||||
return "error:[\(Fonts.toolName)] An error occured while writing extension in \(filename): \(info)"
|
return "error: [\(Fonts.toolName)] An error occured while writing extension in \(filename): \(info)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ class FontsToolHelper {
|
|||||||
let fileManager = FileManager()
|
let fileManager = FileManager()
|
||||||
guard fileManager.fileExists(atPath: inputFolder) else {
|
guard fileManager.fileExists(atPath: inputFolder) else {
|
||||||
let error = FontsToolError.inputFolderNotFound(inputFolder)
|
let error = FontsToolError.inputFolderNotFound(inputFolder)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Fonts.exit(withError: error)
|
Fonts.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ class FontsToolHelper {
|
|||||||
|
|
||||||
guard let fontName = task.output, task.terminationStatus == 0 else {
|
guard let fontName = task.output, task.terminationStatus == 0 else {
|
||||||
let error = FontsToolError.fcScan(path, task.terminationStatus, task.output)
|
let error = FontsToolError.fcScan(path, task.terminationStatus, task.output)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Fonts.exit(withError: error)
|
Fonts.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ class FontExtensionGenerator {
|
|||||||
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch (let error) {
|
} catch (let error) {
|
||||||
let error = FontsToolError.writeExtension(extensionFilePath, error.localizedDescription)
|
let error = FontsToolError.writeExtension(extensionFilePath, error.localizedDescription)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Fonts.exit(withError: error)
|
Fonts.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,10 @@ struct Generate: ParsableCommand {
|
|||||||
print(" - \(configuration.tags.count) tags configuration(s)")
|
print(" - \(configuration.tags.count) tags configuration(s)")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
print("Input file: \(configuration.colors.first?.inputFile ?? "no input file")")
|
if let architecture = configuration.architecture {
|
||||||
|
ArchitectureGenerator.writeArchitecture(architecture,
|
||||||
|
projectDirectory: options.projectDirectory)
|
||||||
|
}
|
||||||
|
|
||||||
// Execute commands
|
// Execute commands
|
||||||
configuration.runnableConfigurations
|
configuration.runnableConfigurations
|
||||||
|
@ -11,20 +11,24 @@ enum GenerateError: Error {
|
|||||||
case fileNotExists(String)
|
case fileNotExists(String)
|
||||||
case invalidConfigurationFile(String)
|
case invalidConfigurationFile(String)
|
||||||
case commandError([String], String)
|
case commandError([String], String)
|
||||||
|
case writeFile(String, String)
|
||||||
|
|
||||||
var localizedDescription: String {
|
var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .fileNotExists(let filename):
|
case .fileNotExists(let filename):
|
||||||
return " error:[\(Generate.toolName)] File \(filename) does not exists"
|
return "error: [\(Generate.toolName)] File \(filename) does not exists"
|
||||||
|
|
||||||
case .invalidConfigurationFile(let filename):
|
case .invalidConfigurationFile(let filename):
|
||||||
return " error:[\(Generate.toolName)] File \(filename) is not a valid configuration file"
|
return "error: [\(Generate.toolName)] File \(filename) is not a valid configuration file"
|
||||||
|
|
||||||
case .commandError(let command, let terminationStatus):
|
case .commandError(let command, let terminationStatus):
|
||||||
let readableCommand = command
|
let readableCommand = command
|
||||||
.map { $0 }
|
.map { $0 }
|
||||||
.joined(separator: " ")
|
.joined(separator: " ")
|
||||||
return "error:[\(Generate.toolName)] An error occured while running command '\(readableCommand)'. Command terminate with status code: \(terminationStatus)"
|
return "error: [\(Generate.toolName)] An error occured while running command '\(readableCommand)'. Command terminate with status code: \(terminationStatus)"
|
||||||
|
|
||||||
|
case .writeFile(let filename, let info):
|
||||||
|
return "error: [\(Generate.toolName)] An error occured while writing file in \(filename): \(info)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// ArchitectureGenerator.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Thibaut Schmitt on 18/11/2022.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct ArchitectureGenerator {
|
||||||
|
static func writeArchitecture(_ architecture: ConfigurationArchitecture, projectDirectory: String) {
|
||||||
|
// Create extension content
|
||||||
|
let architectureContent = [
|
||||||
|
"// Generated by ResgenSwift.\(Generate.toolName) \(ResgenSwiftVersion)",
|
||||||
|
architecture.getClass()
|
||||||
|
]
|
||||||
|
.joined(separator: "\n\n")
|
||||||
|
|
||||||
|
let filename = "\(architecture.classname).swift"
|
||||||
|
guard let filePath = architecture.path?.prependIfRelativePath(projectDirectory) else {
|
||||||
|
let error = GenerateError.writeFile(filename, "Path of file is not defined.")
|
||||||
|
print(error.description)
|
||||||
|
Generate.exit(withError: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write content
|
||||||
|
let architectureFilePathURL = URL(fileURLWithPath: "\(filePath)/\(filename)")
|
||||||
|
do {
|
||||||
|
try architectureContent.write(to: architectureFilePathURL, atomically: false, encoding: .utf8)
|
||||||
|
} catch (let error) {
|
||||||
|
let error = GenerateError.writeFile(filename, error.localizedDescription)
|
||||||
|
print(error.description)
|
||||||
|
Generate.exit(withError: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct ConfigurationFile: Codable, CustomDebugStringConvertible {
|
struct ConfigurationFile: Codable, CustomDebugStringConvertible {
|
||||||
|
var architecture: ConfigurationArchitecture?
|
||||||
var colors: [ColorsConfiguration]
|
var colors: [ColorsConfiguration]
|
||||||
var fonts: [FontsConfiguration]
|
var fonts: [FontsConfiguration]
|
||||||
var images: [ImagesConfiguration]
|
var images: [ImagesConfiguration]
|
||||||
@ -38,6 +39,42 @@ struct ConfigurationFile: Codable, CustomDebugStringConvertible {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ConfigurationArchitecture: Codable {
|
||||||
|
let property: String
|
||||||
|
let classname: String
|
||||||
|
let path: String?
|
||||||
|
let children: [ConfigurationArchitecture]?
|
||||||
|
|
||||||
|
func getProperty(isStatic: Bool) -> String {
|
||||||
|
" \(isStatic ? "static " : "")let \(property) = \(classname)()"
|
||||||
|
}
|
||||||
|
|
||||||
|
func getClass(generateStaticProperty: Bool = true) -> String {
|
||||||
|
guard children?.isEmpty == false else {
|
||||||
|
return "class \(classname) {}"
|
||||||
|
}
|
||||||
|
|
||||||
|
let classDefinition = [
|
||||||
|
"class \(classname) {",
|
||||||
|
children?.map { $0.getProperty(isStatic: generateStaticProperty) }.joined(separator: "\n"),
|
||||||
|
"}"
|
||||||
|
]
|
||||||
|
.compactMap { $0 }
|
||||||
|
.joined(separator: "\n")
|
||||||
|
|
||||||
|
return [classDefinition, "", getSubclass()]
|
||||||
|
.compactMap { $0 }
|
||||||
|
.joined(separator: "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSubclass() -> String? {
|
||||||
|
guard let children else { return nil }
|
||||||
|
return children.compactMap { arch in
|
||||||
|
arch.getClass(generateStaticProperty: false)
|
||||||
|
}
|
||||||
|
.joined(separator: "\n\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
|
struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
|
||||||
let inputFile: String
|
let inputFile: String
|
||||||
@ -267,4 +304,3 @@ struct TagsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,13 +12,13 @@ class ConfigurationFileParser {
|
|||||||
static func parse(_ configurationFile: String) -> ConfigurationFile {
|
static func parse(_ configurationFile: String) -> ConfigurationFile {
|
||||||
guard let data = FileManager().contents(atPath: configurationFile) else {
|
guard let data = FileManager().contents(atPath: configurationFile) else {
|
||||||
let error = GenerateError.fileNotExists(configurationFile)
|
let error = GenerateError.fileNotExists(configurationFile)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Generate.exit(withError: error)
|
Generate.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let configuration = try? YAMLDecoder().decode(ConfigurationFile.self, from: data) else {
|
guard let configuration = try? YAMLDecoder().decode(ConfigurationFile.self, from: data) else {
|
||||||
let error = GenerateError.invalidConfigurationFile(configurationFile)
|
let error = GenerateError.invalidConfigurationFile(configurationFile)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Generate.exit(withError: error)
|
Generate.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ extension FileManager {
|
|||||||
var files = [String]()
|
var files = [String]()
|
||||||
guard let enumerator = self.enumerator(at: URL(string: directory)!, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else {
|
guard let enumerator = self.enumerator(at: URL(string: directory)!, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else {
|
||||||
let error = ImagesError.unknown("Cannot enumerate file in \(directory)")
|
let error = ImagesError.unknown("Cannot enumerate file in \(directory)")
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ extension FileManager {
|
|||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
let error = ImagesError.getFileAttributed(fileURL.relativePath, error.localizedDescription)
|
let error = ImagesError.getFileAttributed(fileURL.relativePath, error.localizedDescription)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,7 +35,7 @@ extension FileManager {
|
|||||||
var files = [String]()
|
var files = [String]()
|
||||||
guard let enumerator = self.enumerator(at: URL(string: directory)!, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else {
|
guard let enumerator = self.enumerator(at: URL(string: directory)!, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else {
|
||||||
let error = ImagesError.unknown("Cannot enumerate imageset directory in \(directory)")
|
let error = ImagesError.unknown("Cannot enumerate imageset directory in \(directory)")
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ extension FileManager {
|
|||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
let error = ImagesError.getFileAttributed(fileURL.relativePath, error.localizedDescription)
|
let error = ImagesError.getFileAttributed(fileURL.relativePath, error.localizedDescription)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ class ImageExtensionGenerator {
|
|||||||
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch (let error) {
|
} catch (let error) {
|
||||||
let error = ImagesError.writeFile(extensionFilePath, error.localizedDescription)
|
let error = ImagesError.writeFile(extensionFilePath, error.localizedDescription)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ class XcassetsGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let error = ImagesError.unknownImageExtension(parsedImage.name)
|
let error = ImagesError.unknownImageExtension(parsedImage.name)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ class XcassetsGenerator {
|
|||||||
withIntermediateDirectories: true)
|
withIntermediateDirectories: true)
|
||||||
} catch {
|
} catch {
|
||||||
let error = ImagesError.createAssetFolder(imagesetPath)
|
let error = ImagesError.createAssetFolder(imagesetPath)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ struct Images: ParsableCommand {
|
|||||||
// Input file
|
// Input file
|
||||||
guard fileManager.fileExists(atPath: options.inputFile) else {
|
guard fileManager.fileExists(atPath: options.inputFile) else {
|
||||||
let error = ImagesError.fileNotExists(options.inputFile)
|
let error = ImagesError.fileNotExists(options.inputFile)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ struct Images: ParsableCommand {
|
|||||||
// Extension for UIKit and SwiftUI should have different name
|
// Extension for UIKit and SwiftUI should have different name
|
||||||
guard options.extensionName != options.extensionNameSwiftUI else {
|
guard options.extensionName != options.extensionNameSwiftUI else {
|
||||||
let error = ImagesError.extensionNamesCollision(options.extensionName)
|
let error = ImagesError.extensionNamesCollision(options.extensionName)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ struct Images: ParsableCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let error = ImagesError.rsvgConvertNotFound
|
let error = ImagesError.rsvgConvertNotFound
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,34 +18,34 @@ enum ImagesError: Error {
|
|||||||
case createAssetFolder(String)
|
case createAssetFolder(String)
|
||||||
case unknown(String)
|
case unknown(String)
|
||||||
|
|
||||||
var localizedDescription: String {
|
var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .extensionNamesCollision(let extensionName):
|
case .extensionNamesCollision(let extensionName):
|
||||||
return "error:[\(Fonts.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
|
return "error: [\(Fonts.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
|
||||||
|
|
||||||
case .inputFolderNotFound(let inputFolder):
|
case .inputFolderNotFound(let inputFolder):
|
||||||
return " error:[\(Images.toolName)] Input folder not found: \(inputFolder)"
|
return "error: [\(Images.toolName)] Input folder not found: \(inputFolder)"
|
||||||
|
|
||||||
case .fileNotExists(let filename):
|
case .fileNotExists(let filename):
|
||||||
return " error:[\(Images.toolName)] File \(filename) does not exists"
|
return "error: [\(Images.toolName)] File \(filename) does not exists"
|
||||||
|
|
||||||
case .unknownImageExtension(let filename):
|
case .unknownImageExtension(let filename):
|
||||||
return " error:[\(Images.toolName)] File \(filename) have an unhandled file extension. Cannot generate image."
|
return "error: [\(Images.toolName)] File \(filename) have an unhandled file extension. Cannot generate image."
|
||||||
|
|
||||||
case .getFileAttributed(let filename, let errorDescription):
|
case .getFileAttributed(let filename, let errorDescription):
|
||||||
return " error:[\(Images.toolName)] Getting file attributes of \(filename) failed with error: \(errorDescription)"
|
return "error: [\(Images.toolName)] Getting file attributes of \(filename) failed with error: \(errorDescription)"
|
||||||
|
|
||||||
case .rsvgConvertNotFound:
|
case .rsvgConvertNotFound:
|
||||||
return " error:[\(Images.toolName)] Can't find rsvg-convert (can be installed with 'brew remove imagemagick && brew install imagemagick --with-librsvg')"
|
return "error: [\(Images.toolName)] Can't find rsvg-convert (can be installed with 'brew remove imagemagick && brew install imagemagick --with-librsvg')"
|
||||||
|
|
||||||
case .writeFile(let subErrorDescription, let filename):
|
case .writeFile(let subErrorDescription, let filename):
|
||||||
return " error:[\(Images.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
|
return "error: [\(Images.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
|
||||||
|
|
||||||
case .createAssetFolder(let folder):
|
case .createAssetFolder(let folder):
|
||||||
return "error:[\(Colors.toolName)] An error occured while creating folder `\(folder)`"
|
return "error: [\(Colors.toolName)] An error occured while creating folder `\(folder)`"
|
||||||
|
|
||||||
case .unknown(let errorDescription):
|
case .unknown(let errorDescription):
|
||||||
return " error:[\(Images.toolName)] Unknown error: \(errorDescription)"
|
return "error: [\(Images.toolName)] Unknown error: \(errorDescription)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,12 @@ class StringsFileGenerator {
|
|||||||
|
|
||||||
// MARK: - Strings Files
|
// MARK: - Strings Files
|
||||||
|
|
||||||
static func writeStringsFiles(sections: [Section], langs: [String], defaultLang: String, tags: [String], outputPath: String, inputFilenameWithoutExt: String) {
|
static func writeStringsFiles(sections: [Section],
|
||||||
|
langs: [String],
|
||||||
|
defaultLang: String,
|
||||||
|
tags: [String],
|
||||||
|
outputPath: String,
|
||||||
|
inputFilenameWithoutExt: String) {
|
||||||
var stringsFilesContent = [String: String]()
|
var stringsFilesContent = [String: String]()
|
||||||
for lang in langs {
|
for lang in langs {
|
||||||
stringsFilesContent[lang] = Self.generateStringsFileContent(lang: lang,
|
stringsFilesContent[lang] = Self.generateStringsFileContent(lang: lang,
|
||||||
@ -31,13 +36,16 @@ class StringsFileGenerator {
|
|||||||
try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8)
|
try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch (let error) {
|
} catch (let error) {
|
||||||
let error = StringiumError.writeFile(error.localizedDescription, stringsFilePath)
|
let error = StringiumError.writeFile(error.localizedDescription, stringsFilePath)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func generateStringsFileContent(lang: String, defaultLang: String, tags inputTags: [String], sections: [Section]) -> String {
|
static func generateStringsFileContent(lang: String,
|
||||||
|
defaultLang: String,
|
||||||
|
tags inputTags: [String],
|
||||||
|
sections: [Section]) -> String {
|
||||||
var stringsFileContent = """
|
var stringsFileContent = """
|
||||||
/**
|
/**
|
||||||
* Apple Strings File
|
* Apple Strings File
|
||||||
@ -75,7 +83,7 @@ class StringsFileGenerator {
|
|||||||
stringsFileContent += "\"\(definition.name)\" = \"\(translation)\";\n\n"
|
stringsFileContent += "\"\(definition.name)\" = \"\(translation)\";\n\n"
|
||||||
} else if skipDefinition == false {
|
} else if skipDefinition == false {
|
||||||
let error = StringiumError.langNotDefined(lang, definition.name, definition.reference != nil)
|
let error = StringiumError.langNotDefined(lang, definition.name, definition.reference != nil)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,14 +94,22 @@ class StringsFileGenerator {
|
|||||||
|
|
||||||
// MARK: - Extension file
|
// MARK: - Extension file
|
||||||
|
|
||||||
static func writeExtensionFiles(sections: [Section], defaultLang lang: String, tags: [String], staticVar: Bool, inputFilename: String, extensionName: String, extensionFilePath: String) {
|
static func writeExtensionFiles(sections: [Section],
|
||||||
|
defaultLang lang: String,
|
||||||
|
tags: [String],
|
||||||
|
staticVar: Bool,
|
||||||
|
inputFilename: String,
|
||||||
|
extensionName: String,
|
||||||
|
extensionFilePath: String,
|
||||||
|
extensionSuffix: String) {
|
||||||
// Get extension content
|
// Get extension content
|
||||||
let extensionFileContent = Self.getExtensionContent(sections: sections,
|
let extensionFileContent = Self.getExtensionContent(sections: sections,
|
||||||
defaultLang: lang,
|
defaultLang: lang,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
staticVar: staticVar,
|
staticVar: staticVar,
|
||||||
inputFilename: inputFilename,
|
inputFilename: inputFilename,
|
||||||
extensionName: extensionName)
|
extensionName: extensionName,
|
||||||
|
extensionSuffix: extensionSuffix)
|
||||||
|
|
||||||
// Write content
|
// Write content
|
||||||
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
||||||
@ -101,16 +117,23 @@ class StringsFileGenerator {
|
|||||||
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch (let error) {
|
} catch (let error) {
|
||||||
let error = StringiumError.writeFile(extensionFilePath, error.localizedDescription)
|
let error = StringiumError.writeFile(extensionFilePath, error.localizedDescription)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Extension content
|
// MARK: - Extension content
|
||||||
|
|
||||||
static func getExtensionContent(sections: [Section], defaultLang lang: String, tags: [String], staticVar: Bool, inputFilename: String, extensionName: String) -> String {
|
static func getExtensionContent(sections: [Section],
|
||||||
|
defaultLang lang: String,
|
||||||
|
tags: [String],
|
||||||
|
staticVar: Bool,
|
||||||
|
inputFilename: String,
|
||||||
|
extensionName: String,
|
||||||
|
extensionSuffix: String) -> String {
|
||||||
[
|
[
|
||||||
Self.getHeader(stringsFilename: inputFilename, extensionClassname: extensionName),
|
Self.getHeader(stringsFilename: inputFilename, extensionClassname: extensionName),
|
||||||
|
Self.getEnumKey(sections: sections, tags: tags, extensionSuffix: extensionSuffix),
|
||||||
Self.getProperties(sections: sections, defaultLang: lang, tags: tags, staticVar: staticVar),
|
Self.getProperties(sections: sections, defaultLang: lang, tags: tags, staticVar: staticVar),
|
||||||
Self.getFooter()
|
Self.getFooter()
|
||||||
]
|
]
|
||||||
@ -131,6 +154,29 @@ class StringsFileGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static func getEnumKey(sections: [Section], tags: [String], extensionSuffix: String) -> String {
|
||||||
|
var enumDefinition = "\n enum Key\(extensionSuffix.uppercasedFirst()): String {\n"
|
||||||
|
|
||||||
|
sections.forEach { section in
|
||||||
|
// Check that at least one string will be generated
|
||||||
|
guard section.hasOneOrMoreMatchingTags(tags: tags) else {
|
||||||
|
return // Go to next section
|
||||||
|
}
|
||||||
|
|
||||||
|
section.definitions.forEach { definition in
|
||||||
|
guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else {
|
||||||
|
return // Go to next definition
|
||||||
|
}
|
||||||
|
debugPrint("Found definition")
|
||||||
|
enumDefinition += " case \(definition.name) = \"\(definition.name)\"\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enumDefinition += " }"
|
||||||
|
|
||||||
|
return enumDefinition
|
||||||
|
}
|
||||||
|
|
||||||
private static func getProperties(sections: [Section], defaultLang lang: String, tags: [String], staticVar: Bool) -> String {
|
private static func getProperties(sections: [Section], defaultLang lang: String, tags: [String], staticVar: Bool) -> String {
|
||||||
sections.compactMap { section in
|
sections.compactMap { section in
|
||||||
// Check that at least one string will be generated
|
// Check that at least one string will be generated
|
||||||
|
@ -24,7 +24,7 @@ class TagsGenerator {
|
|||||||
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch (let error) {
|
} catch (let error) {
|
||||||
let error = StringiumError.writeFile(extensionFilePath, error.localizedDescription)
|
let error = StringiumError.writeFile(extensionFilePath, error.localizedDescription)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ class Definition {
|
|||||||
func getNSLocalizedStringProperty(forLang lang: String) -> String {
|
func getNSLocalizedStringProperty(forLang lang: String) -> String {
|
||||||
guard let translation = translations[lang] else {
|
guard let translation = translations[lang] else {
|
||||||
let error = StringiumError.langNotDefined(lang, name, reference != nil)
|
let error = StringiumError.langNotDefined(lang, name, reference != nil)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ class Definition {
|
|||||||
func getNSLocalizedStringStaticProperty(forLang lang: String) -> String {
|
func getNSLocalizedStringStaticProperty(forLang lang: String) -> String {
|
||||||
guard let translation = translations[lang] else {
|
guard let translation = translations[lang] else {
|
||||||
let error = StringiumError.langNotDefined(lang, name, reference != nil)
|
let error = StringiumError.langNotDefined(lang, name, reference != nil)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ class Definition {
|
|||||||
func getProperty(forLang lang: String) -> String {
|
func getProperty(forLang lang: String) -> String {
|
||||||
guard let translation = translations[lang] else {
|
guard let translation = translations[lang] else {
|
||||||
let error = StringiumError.langNotDefined(lang, name, reference != nil)
|
let error = StringiumError.langNotDefined(lang, name, reference != nil)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +173,7 @@ class Definition {
|
|||||||
func getStaticProperty(forLang lang: String) -> String {
|
func getStaticProperty(forLang lang: String) -> String {
|
||||||
guard let translation = translations[lang] else {
|
guard let translation = translations[lang] else {
|
||||||
let error = StringiumError.langNotDefined(lang, name, reference != nil)
|
let error = StringiumError.langNotDefined(lang, name, reference != nil)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ class TwineFileParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if invalidDefinitionNames.count > 0 {
|
if invalidDefinitionNames.count > 0 {
|
||||||
print(" warning:[\(Stringium.toolName)] Found \(invalidDefinitionNames.count) definition (\(invalidDefinitionNames.joined(separator: ", "))")
|
print("warning: [\(Stringium.toolName)] Found \(invalidDefinitionNames.count) definition (\(invalidDefinitionNames.joined(separator: ", "))")
|
||||||
}
|
}
|
||||||
|
|
||||||
return sections
|
return sections
|
||||||
|
@ -57,7 +57,8 @@ struct Stringium: ParsableCommand {
|
|||||||
staticVar: options.staticMembers,
|
staticVar: options.staticMembers,
|
||||||
inputFilename: options.inputFilenameWithoutExt,
|
inputFilename: options.inputFilenameWithoutExt,
|
||||||
extensionName: options.extensionName,
|
extensionName: options.extensionName,
|
||||||
extensionFilePath: options.extensionFilePath)
|
extensionFilePath: options.extensionFilePath,
|
||||||
|
extensionSuffix: options.extensionSuffix)
|
||||||
|
|
||||||
print("[\(Self.toolName)] Strings generated")
|
print("[\(Self.toolName)] Strings generated")
|
||||||
}
|
}
|
||||||
@ -70,20 +71,20 @@ struct Stringium: ParsableCommand {
|
|||||||
// Input file
|
// Input file
|
||||||
guard fileManager.fileExists(atPath: options.inputFile) else {
|
guard fileManager.fileExists(atPath: options.inputFile) else {
|
||||||
let error = StringiumError.fileNotExists(options.inputFile)
|
let error = StringiumError.fileNotExists(options.inputFile)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Langs
|
// Langs
|
||||||
guard options.langs.isEmpty == false else {
|
guard options.langs.isEmpty == false else {
|
||||||
let error = StringiumError.langsListEmpty
|
let error = StringiumError.langsListEmpty
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard options.langs.contains(options.defaultLang) else {
|
guard options.langs.contains(options.defaultLang) else {
|
||||||
let error = StringiumError.defaultLangsNotInLangs
|
let error = StringiumError.defaultLangsNotInLangs
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,25 +14,25 @@ enum StringiumError: Error {
|
|||||||
case writeFile(String, String)
|
case writeFile(String, String)
|
||||||
case langNotDefined(String, String, Bool)
|
case langNotDefined(String, String, Bool)
|
||||||
|
|
||||||
var localizedDescription: String {
|
var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .fileNotExists(let filename):
|
case .fileNotExists(let filename):
|
||||||
return " error:[\(Stringium.toolName)] File \(filename) does not exists "
|
return "error: [\(Stringium.toolName)] File \(filename) does not exists "
|
||||||
|
|
||||||
case .langsListEmpty:
|
case .langsListEmpty:
|
||||||
return " error:[\(Stringium.toolName)] Langs list is empty"
|
return "error: [\(Stringium.toolName)] Langs list is empty"
|
||||||
|
|
||||||
case .defaultLangsNotInLangs:
|
case .defaultLangsNotInLangs:
|
||||||
return " error:[\(Stringium.toolName)] Langs list does not contains the default lang"
|
return "error: [\(Stringium.toolName)] Langs list does not contains the default lang"
|
||||||
|
|
||||||
case .writeFile(let subErrorDescription, let filename):
|
case .writeFile(let subErrorDescription, let filename):
|
||||||
return " error:[\(Stringium.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
|
return "error: [\(Stringium.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
|
||||||
|
|
||||||
case .langNotDefined(let lang, let definitionName, let isReference):
|
case .langNotDefined(let lang, let definitionName, let isReference):
|
||||||
if isReference {
|
if isReference {
|
||||||
return " error:[\(Stringium.toolName)] Reference are handled only by TwineTool. Please use it or remove reference from you strings file."
|
return "error: [\(Stringium.toolName)] Reference are handled only by Twine. Please use it or remove reference from you strings file."
|
||||||
}
|
}
|
||||||
return " error:[\(Stringium.toolName)] Lang \"\(lang)\" not found for \"\(definitionName)\""
|
return "error: [\(Stringium.toolName)] Lang \"\(lang)\" not found for \"\(definitionName)\""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,8 @@ struct StringiumOptions: ParsableArguments {
|
|||||||
@Option(help: "Extension name. If not specified, it will generate an String extension.")
|
@Option(help: "Extension name. If not specified, it will generate an String extension.")
|
||||||
var extensionName: String = Stringium.defaultExtensionName
|
var extensionName: String = Stringium.defaultExtensionName
|
||||||
|
|
||||||
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+{extensionSuffix}.swift")
|
@Option(help: "Extension suffix: {extensionName}+{extensionSuffix}.swift")
|
||||||
var extensionSuffix: String?
|
var extensionSuffix: String
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private var getter
|
// MARK: - Private var getter
|
||||||
@ -68,10 +68,7 @@ extension StringiumOptions {
|
|||||||
|
|
||||||
extension StringiumOptions {
|
extension StringiumOptions {
|
||||||
var extensionFileName: String {
|
var extensionFileName: String {
|
||||||
if let extensionSuffix = extensionSuffix {
|
"\(extensionName)+\(extensionSuffix).swift"
|
||||||
return "\(extensionName)+\(extensionSuffix).swift"
|
|
||||||
}
|
|
||||||
return "\(extensionName).swift"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensionFilePath: String {
|
var extensionFilePath: String {
|
||||||
|
@ -62,7 +62,7 @@ struct Tags: ParsableCommand {
|
|||||||
// Input file
|
// Input file
|
||||||
guard fileManager.fileExists(atPath: options.inputFile) else {
|
guard fileManager.fileExists(atPath: options.inputFile) else {
|
||||||
let error = StringiumError.fileNotExists(options.inputFile)
|
let error = StringiumError.fileNotExists(options.inputFile)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,20 +66,20 @@ struct Twine: ParsableCommand {
|
|||||||
// Input file
|
// Input file
|
||||||
guard fileManager.fileExists(atPath: options.inputFile) else {
|
guard fileManager.fileExists(atPath: options.inputFile) else {
|
||||||
let error = TwineError.fileNotExists(options.inputFile)
|
let error = TwineError.fileNotExists(options.inputFile)
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Twine.exit(withError: error)
|
Twine.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Langs
|
// Langs
|
||||||
guard options.langs.isEmpty == false else {
|
guard options.langs.isEmpty == false else {
|
||||||
let error = TwineError.langsListEmpty
|
let error = TwineError.langsListEmpty
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Twine.exit(withError: error)
|
Twine.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard options.langs.contains(options.defaultLang) else {
|
guard options.langs.contains(options.defaultLang) else {
|
||||||
let error = TwineError.defaultLangsNotInLangs
|
let error = TwineError.defaultLangsNotInLangs
|
||||||
print(error.localizedDescription)
|
print(error.description)
|
||||||
Twine.exit(withError: error)
|
Twine.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,16 +12,16 @@ enum TwineError: Error {
|
|||||||
case langsListEmpty
|
case langsListEmpty
|
||||||
case defaultLangsNotInLangs
|
case defaultLangsNotInLangs
|
||||||
|
|
||||||
var localizedDescription: String {
|
var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .fileNotExists(let filename):
|
case .fileNotExists(let filename):
|
||||||
return " error:[\(Twine.toolName)] File \(filename) does not exists "
|
return "error: [\(Twine.toolName)] File \(filename) does not exists "
|
||||||
|
|
||||||
case .langsListEmpty:
|
case .langsListEmpty:
|
||||||
return " error:[\(Twine.toolName)] Langs list is empty"
|
return "error: [\(Twine.toolName)] Langs list is empty"
|
||||||
|
|
||||||
case .defaultLangsNotInLangs:
|
case .defaultLangsNotInLangs:
|
||||||
return " error:[\(Twine.toolName)] Langs list does not contains the default lang"
|
return "error: [\(Twine.toolName)] Langs list does not contains the default lang"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,4 +85,8 @@ public extension String {
|
|||||||
blue = String(colorClean.prefix(2))
|
blue = String(colorClean.prefix(2))
|
||||||
return (alpha: alpha, red: red, green: green, blue: blue)
|
return (alpha: alpha, red: red, green: green, blue: blue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func uppercasedFirst() -> String {
|
||||||
|
prefix(1).uppercased() + dropFirst()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,4 +7,4 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public let ResgenSwiftVersion = "1.1"
|
public let ResgenSwiftVersion = "1.2"
|
||||||
|
@ -131,7 +131,8 @@ final class StringsFileGeneratorTests: XCTestCase {
|
|||||||
tags: ["ios", "iosonly", "notranslation"],
|
tags: ["ios", "iosonly", "notranslation"],
|
||||||
staticVar: false,
|
staticVar: false,
|
||||||
inputFilename: "myInputFilename",
|
inputFilename: "myInputFilename",
|
||||||
extensionName: "GenStrings")
|
extensionName: "GenStrings",
|
||||||
|
extensionSuffix: "strings")
|
||||||
|
|
||||||
// Expect
|
// Expect
|
||||||
let expect = """
|
let expect = """
|
||||||
@ -207,7 +208,8 @@ final class StringsFileGeneratorTests: XCTestCase {
|
|||||||
tags: ["ios", "iosonly", "notranslation"],
|
tags: ["ios", "iosonly", "notranslation"],
|
||||||
staticVar: true,
|
staticVar: true,
|
||||||
inputFilename: "myInputFilename",
|
inputFilename: "myInputFilename",
|
||||||
extensionName: "GenStrings")
|
extensionName: "GenStrings",
|
||||||
|
extensionSuffix: "strings")
|
||||||
|
|
||||||
// Expect
|
// Expect
|
||||||
let expect = """
|
let expect = """
|
||||||
|
Reference in New Issue
Block a user