Compare commits
No commits in common. "feat/RES-34-fix-plist-font-filename" and "master" have entirely different histories.
feat/RES-3
...
master
309
.swiftlint.yml
309
.swiftlint.yml
@ -1,276 +1,43 @@
|
|||||||
# All rules here : https://realm.github.io/SwiftLint/rule-directory.html
|
disabled_rules: # rule identifiers to exclude from running
|
||||||
|
|
||||||
analyzer_rules:
|
|
||||||
- capture_variable
|
|
||||||
- typesafe_array_init
|
|
||||||
- unused_declaration
|
|
||||||
- unused_import
|
|
||||||
|
|
||||||
included:
|
|
||||||
- Sources
|
|
||||||
|
|
||||||
## Rules configuration
|
|
||||||
|
|
||||||
attributes:
|
|
||||||
always_on_line_above: ["@InjectedValue", "@ViewBuilder", "@IBOutlet"]
|
|
||||||
always_on_same_line: ["@Environment", "@EnvironmentObject", "@StateObject", "@State"]
|
|
||||||
|
|
||||||
identifier_name:
|
|
||||||
min_length:
|
|
||||||
- 2
|
|
||||||
max_length:
|
|
||||||
- 60
|
|
||||||
excluded:
|
|
||||||
- x
|
|
||||||
- y
|
|
||||||
|
|
||||||
type_name:
|
|
||||||
min_length: 3
|
|
||||||
max_length: 60
|
|
||||||
excluded:
|
|
||||||
- T
|
|
||||||
allowed_symbols:
|
|
||||||
- _
|
|
||||||
|
|
||||||
# line_length:
|
|
||||||
# warning: 150
|
|
||||||
|
|
||||||
disabled_rules:
|
|
||||||
- blanket_disable_command # do not warn when rule is not re-enable later in the file
|
|
||||||
- type_contents_order
|
|
||||||
- legacy_objc_type
|
|
||||||
- indentation_width
|
|
||||||
- function_parameter_count
|
|
||||||
- line_length
|
|
||||||
- function_body_length
|
|
||||||
- cyclomatic_complexity
|
|
||||||
- optional_data_string_conversion
|
|
||||||
|
|
||||||
opt_in_rules:
|
|
||||||
# Default rules :
|
|
||||||
- block_based_kvo
|
|
||||||
- class_delegate_protocol
|
|
||||||
- closing_brace
|
|
||||||
- closure_parameter_position
|
|
||||||
- colon
|
|
||||||
- comma
|
|
||||||
- comment_spacing
|
|
||||||
- compiler_protocol_init
|
|
||||||
- computed_accessors_order
|
|
||||||
- control_statement
|
|
||||||
- custom_rules
|
|
||||||
# - cyclomatic_complexity
|
|
||||||
- deployment_target
|
|
||||||
- discouraged_direct_init
|
|
||||||
- duplicate_enum_cases
|
|
||||||
- duplicate_imports
|
|
||||||
- duplicated_key_in_dictionary_literal
|
|
||||||
- dynamic_inline
|
|
||||||
- empty_enum_arguments
|
|
||||||
- empty_parameters
|
|
||||||
- empty_parentheses_with_trailing_closure
|
|
||||||
- file_length
|
|
||||||
- for_where
|
|
||||||
- force_unwrapping
|
|
||||||
- force_cast
|
|
||||||
- force_try
|
|
||||||
- trailing_whitespace
|
|
||||||
# - function_body_length
|
|
||||||
# - function_parameter_count
|
|
||||||
- generic_type_name
|
|
||||||
- identifier_name
|
|
||||||
- implicit_getter
|
|
||||||
- inclusive_language
|
|
||||||
- is_disjoint
|
|
||||||
- large_tuple
|
|
||||||
- leading_whitespace
|
- leading_whitespace
|
||||||
- legacy_cggeometry_functions
|
- trailing_whitespace
|
||||||
- legacy_constant
|
- identifier_name
|
||||||
- legacy_constructor
|
- large_tuple
|
||||||
- legacy_hashing
|
- file_length
|
||||||
- legacy_nsgeometry_functions
|
- line_length
|
||||||
- legacy_random
|
- force_try
|
||||||
# - line_length
|
|
||||||
- mark
|
|
||||||
- multiple_closures_with_trailing_closure
|
|
||||||
- nesting
|
|
||||||
- no_fallthrough_only
|
|
||||||
- no_space_in_method_call
|
|
||||||
- notification_center_detachment
|
|
||||||
- ns_number_init_as_function_reference
|
|
||||||
- nsobject_prefer_isequal
|
|
||||||
- opening_brace
|
|
||||||
- operator_whitespace
|
|
||||||
- orphaned_doc_comment
|
|
||||||
- private_over_fileprivate
|
|
||||||
- private_unit_test
|
|
||||||
- protocol_property_accessors_order
|
|
||||||
- reduce_boolean
|
|
||||||
- redundant_discardable_let
|
|
||||||
- redundant_objc_attribute
|
|
||||||
- redundant_optional_initialization
|
|
||||||
- redundant_set_access_control
|
|
||||||
- redundant_string_enum_value
|
|
||||||
- redundant_void_return
|
|
||||||
- return_arrow_whitespace
|
|
||||||
- self_in_property_initialization
|
|
||||||
- shorthand_operator
|
- shorthand_operator
|
||||||
- statement_position
|
|
||||||
- superfluous_disable_command
|
|
||||||
- switch_case_alignment
|
|
||||||
- syntactic_sugar
|
|
||||||
- todo
|
|
||||||
- trailing_comma
|
|
||||||
- trailing_newline
|
|
||||||
- trailing_semicolon
|
|
||||||
- type_body_length
|
- type_body_length
|
||||||
- type_name
|
- function_body_length
|
||||||
- unavailable_condition
|
- function_parameter_count
|
||||||
- unneeded_break_in_switch
|
- redundant_string_enum_value
|
||||||
- unused_closure_parameter
|
- unused_closure_parameter
|
||||||
- unused_control_flow_label
|
- cyclomatic_complexity
|
||||||
- unused_enumerated
|
- syntactic_sugar
|
||||||
- unused_optional_binding
|
- empty_enum_arguments
|
||||||
- unused_setter_value
|
- force_cast
|
||||||
- valid_ibinspectable
|
- multiple_closures_with_trailing_closure
|
||||||
- vertical_parameter_alignment
|
- private_over_fileprivate
|
||||||
- vertical_whitespace
|
- trailing_comma
|
||||||
- void_function_in_ternary
|
- comment_spacing
|
||||||
- void_return
|
excluded: # paths to ignore during linting. Takes precedence over `included`.
|
||||||
- xctfail_message
|
- DerivedData
|
||||||
- accessibility_trait_for_button
|
- Carthage
|
||||||
- array_init
|
- Pods
|
||||||
- attributes
|
- vendor
|
||||||
- closure_body_length
|
- Vendor
|
||||||
- closure_end_indentation
|
- "*/R2Tag+tags.swift"
|
||||||
- closure_spacing
|
type_name:
|
||||||
- collection_alignment
|
min_length: 1 # only warning
|
||||||
- comma_inheritance
|
max_length: # warning and error
|
||||||
- contains_over_filter_count
|
warning: 50
|
||||||
- contains_over_filter_is_empty
|
error: 60
|
||||||
- contains_over_first_not_nil
|
allowed_symbols: ["_"]
|
||||||
- contains_over_range_nil_comparison
|
nesting:
|
||||||
- convenience_type
|
type_level:
|
||||||
- discarded_notification_center_observer
|
warning: 3
|
||||||
- discouraged_assert
|
error: 6
|
||||||
- empty_count
|
statement_level:
|
||||||
- empty_string
|
warning: 5
|
||||||
- empty_xctest_method
|
error: 10
|
||||||
- enum_case_associated_values_count
|
|
||||||
- explicit_init
|
|
||||||
- fallthrough
|
|
||||||
- fatal_error_message
|
|
||||||
- file_header
|
|
||||||
- first_where
|
|
||||||
- flatmap_over_map_reduce
|
|
||||||
- ibinspectable_in_extension
|
|
||||||
- implicit_return
|
|
||||||
- implicitly_unwrapped_optional
|
|
||||||
- joined_default_parameter
|
|
||||||
- last_where
|
|
||||||
- legacy_multiple
|
|
||||||
- let_var_whitespace
|
|
||||||
- literal_expression_end_indentation
|
|
||||||
- lower_acl_than_parent
|
|
||||||
# - missing_docs
|
|
||||||
- modifier_order
|
|
||||||
- multiline_arguments
|
|
||||||
- multiline_arguments_brackets
|
|
||||||
- multiline_function_chains
|
|
||||||
- multiline_literal_brackets
|
|
||||||
- multiline_parameters
|
|
||||||
- multiline_parameters_brackets
|
|
||||||
- nimble_operator
|
|
||||||
- no_extension_access_modifier
|
|
||||||
- no_grouping_extension
|
|
||||||
- nslocalizedstring_key
|
|
||||||
- nslocalizedstring_require_bundle
|
|
||||||
- number_separator
|
|
||||||
- operator_usage_whitespace
|
|
||||||
- optional_enum_case_matching
|
|
||||||
- overridden_super_call
|
|
||||||
- override_in_extension
|
|
||||||
- pattern_matching_keywords
|
|
||||||
- prefer_self_in_static_references
|
|
||||||
- prefer_self_type_over_type_of_self
|
|
||||||
- prefer_zero_over_explicit_init
|
|
||||||
- prefixed_toplevel_constant
|
|
||||||
- private_action
|
|
||||||
- private_outlet
|
|
||||||
- prohibited_interface_builder
|
|
||||||
- prohibited_super_call
|
|
||||||
- quick_discouraged_call
|
|
||||||
- quick_discouraged_focused_test
|
|
||||||
- quick_discouraged_pending_test
|
|
||||||
- redundant_nil_coalescing
|
|
||||||
- redundant_type_annotation
|
|
||||||
- required_enum_case
|
|
||||||
- return_value_from_void_function
|
|
||||||
- self_binding
|
|
||||||
- shorthand_optional_binding
|
|
||||||
- single_test_class
|
|
||||||
- sorted_first_last
|
|
||||||
- sorted_imports
|
|
||||||
- strong_iboutlet
|
|
||||||
- test_case_accessibility
|
|
||||||
- toggle_bool
|
|
||||||
- trailing_closure
|
|
||||||
- unavailable_function
|
|
||||||
- unneeded_parentheses_in_closure_argument
|
|
||||||
- unowned_variable_capture
|
|
||||||
- untyped_error_in_catch
|
|
||||||
- vertical_parameter_alignment_on_call
|
|
||||||
- vertical_whitespace_between_cases
|
|
||||||
- vertical_whitespace_closing_braces
|
|
||||||
- weak_delegate
|
|
||||||
- xct_specific_matcher
|
|
||||||
|
|
||||||
custom_rules:
|
|
||||||
|
|
||||||
# Empty line before and after MARK -------------------------------------------
|
|
||||||
# mark_spacing:
|
|
||||||
# name: "Surround MARK by empty lines"
|
|
||||||
# regex: '\n[^\n]([^\n]*\/\/ MARK[^\n]*)\n[^\n]'
|
|
||||||
# message: "Surround MARK by empty lines"
|
|
||||||
# severity: warning
|
|
||||||
|
|
||||||
# Empty line -----------------------------------------------------------------
|
|
||||||
# no_empty_line_after_func:
|
|
||||||
# name: "No empty line after init or func"
|
|
||||||
# regex: '(func|init|let\s|var\s)[^\n]*\{[^\n\{\}]*\n\n'
|
|
||||||
# message: "No empty line after init or func"
|
|
||||||
# severity: warning
|
|
||||||
|
|
||||||
# Empty line after canImport -----------------------------------------------------------------
|
|
||||||
no_empty_line_after_can_import:
|
|
||||||
name: "Add empty line after #if canImport"
|
|
||||||
regex: '#if canImport\(.*\)\n[^\n]*(import|class|struct|enum|extension|protocol)'
|
|
||||||
message: "Add empty line after #if canImport"
|
|
||||||
severity: warning
|
|
||||||
|
|
||||||
# Spacings -------------------------------------------------------------------
|
|
||||||
empty_line_required:
|
|
||||||
name: "Add empty line after class, struct, enum, extension or protocol"
|
|
||||||
regex: '(class |struct |enum |extension |protocol )[^\n]*\{\n[^\n]*(class|struct|enum|extension|protocol|func|let|var|weak|private|internal|public|open|static|final|\/\/|init|case|@)'
|
|
||||||
message: "Add empty line after class, struct, enum, extension or protocol"
|
|
||||||
severity: warning
|
|
||||||
match_kinds:
|
|
||||||
- argument
|
|
||||||
- attribute.builtin
|
|
||||||
- attribute.id
|
|
||||||
- buildconfig.id
|
|
||||||
- buildconfig.keyword
|
|
||||||
- comment
|
|
||||||
- comment.mark
|
|
||||||
- comment.url
|
|
||||||
- identifier
|
|
||||||
- keyword
|
|
||||||
- number
|
|
||||||
- objectliteral
|
|
||||||
- parameter
|
|
||||||
- placeholder
|
|
||||||
- string
|
|
||||||
- string_interpolation_anchor
|
|
||||||
- typeidentifier
|
|
||||||
|
|
||||||
|
|
||||||
|
6
Jenkinsfile
vendored
6
Jenkinsfile
vendored
@ -1,10 +1,8 @@
|
|||||||
library "openiumpipeline"
|
library "openiumpipeline"
|
||||||
|
|
||||||
env.DEVELOPER_DIR="/Applications/Xcode-16.3.0.app/Contents/Developer"
|
env.DEVELOPER_DIR="/Applications/Xcode-15.4.0.app/Contents/Developer"
|
||||||
// env.SIMULATOR_DEVICE_TYPES="iPhone-14-Pro"
|
//env.SIMULATOR_DEVICE_TYPES="iPad--7th-generation-"
|
||||||
// env.SLACK_CHANNEL = "prj-skdevkit"
|
|
||||||
env.IS_PACKAGE_SWIFT=1
|
env.IS_PACKAGE_SWIFT=1
|
||||||
env.TARGETS_MACOS=1
|
env.TARGETS_MACOS=1
|
||||||
env.PACKAGE_NAME="ResgenSwift" // xcodebuild -list => Only 1 scheme
|
|
||||||
|
|
||||||
iOSpipeline()
|
iOSpipeline()
|
||||||
|
@ -1,5 +1,32 @@
|
|||||||
{
|
{
|
||||||
"pins" : [
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "collectionconcurrencykit",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95",
|
||||||
|
"version" : "0.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "cryptoswift",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "c9c3df6ab812de32bae61fc0cd1bf6d45170ebf0",
|
||||||
|
"version" : "1.8.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "sourcekitten",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/jpsim/SourceKitten.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56",
|
||||||
|
"version" : "0.34.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "swift-argument-parser",
|
"identity" : "swift-argument-parser",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
@ -10,12 +37,39 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"identity" : "swiftlintplugin",
|
"identity" : "swift-syntax",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/lukepistrol/SwiftLintPlugin",
|
"location" : "https://github.com/apple/swift-syntax.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "87454f5c9ff4d644086aec2a0df1ffba678e7f3c",
|
"revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036",
|
||||||
"version" : "0.57.1"
|
"version" : "509.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swiftlint",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/realm/SwiftLint.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "f17a4f9dfb6a6afb0408426354e4180daaf49cee",
|
||||||
|
"version" : "0.54.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swiftytexttable",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/scottrhoyt/SwiftyTextTable.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3",
|
||||||
|
"version" : "0.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swxmlhash",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/drmohundro/SWXMLHash.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f",
|
||||||
|
"version" : "7.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,25 +1,16 @@
|
|||||||
// swift-tools-version:5.9
|
// swift-tools-version:5.6
|
||||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
import PackageDescription
|
import PackageDescription
|
||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "ResgenSwift",
|
name: "ResgenSwift",
|
||||||
platforms: [.macOS(.v14)],
|
platforms: [.macOS(.v12)],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
// Dependencies declare other packages that this package depends on.
|
// Dependencies declare other packages that this package depends on.
|
||||||
.package(
|
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"),
|
||||||
url: "https://github.com/apple/swift-argument-parser",
|
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.1"),
|
||||||
from: "1.0.0"
|
.package(url: "https://github.com/realm/SwiftLint.git", .upToNextMajor(from: "0.54.0")),
|
||||||
),
|
|
||||||
.package(
|
|
||||||
url: "https://github.com/jpsim/Yams.git",
|
|
||||||
from: "5.0.1"
|
|
||||||
),
|
|
||||||
.package(
|
|
||||||
url: "https://github.com/lukepistrol/SwiftLintPlugin",
|
|
||||||
exact: "0.57.1"
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||||
@ -28,15 +19,10 @@ let package = Package(
|
|||||||
name: "ResgenSwift",
|
name: "ResgenSwift",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
"ToolCore",
|
"ToolCore",
|
||||||
"Yams",
|
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||||
.product(
|
"Yams"
|
||||||
name: "ArgumentParser",
|
|
||||||
package: "swift-argument-parser"
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")]
|
||||||
.plugin(name: "SwiftLint", package: "SwiftLintPlugin")
|
|
||||||
]
|
|
||||||
),
|
),
|
||||||
|
|
||||||
// Helper targets
|
// Helper targets
|
||||||
|
@ -6,16 +6,16 @@
|
|||||||
<array/>
|
<array/>
|
||||||
<key>UIAppFonts</key>
|
<key>UIAppFonts</key>
|
||||||
<array>
|
<array>
|
||||||
<string>Lato-Italic.ttf</string>
|
<string>Lato-Italic</string>
|
||||||
<string>Lato-LightItalic.ttf</string>
|
<string>Lato-LightItalic</string>
|
||||||
<string>Lato-Thin.ttf</string>
|
<string>Lato-Hairline</string>
|
||||||
<string>Lato-Bold.ttf</string>
|
<string>Lato-Bold</string>
|
||||||
<string>Lato-Black.ttf</string>
|
<string>Lato-Black</string>
|
||||||
<string>Lato-Regular.ttf</string>
|
<string>Lato-Regular</string>
|
||||||
<string>Lato-BlackItalic.ttf</string>
|
<string>Lato-BlackItalic</string>
|
||||||
<string>Lato-BoldItalic.ttf</string>
|
<string>Lato-BoldItalic</string>
|
||||||
<string>Lato-Light.ttf</string>
|
<string>Lato-Light</string>
|
||||||
<string>Lato-ThinItalic.ttf</string>
|
<string>Lato-HairlineItalic</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -6,16 +6,16 @@
|
|||||||
<array/>
|
<array/>
|
||||||
<key>UIAppFonts</key>
|
<key>UIAppFonts</key>
|
||||||
<array>
|
<array>
|
||||||
<string>Lato-Italic.ttf</string>
|
<string>Lato-Italic</string>
|
||||||
<string>Lato-LightItalic.ttf</string>
|
<string>Lato-LightItalic</string>
|
||||||
<string>Lato-Thin.ttf</string>
|
<string>Lato-Hairline</string>
|
||||||
<string>Lato-Bold.ttf</string>
|
<string>Lato-Bold</string>
|
||||||
<string>Lato-Black.ttf</string>
|
<string>Lato-Black</string>
|
||||||
<string>Lato-Regular.ttf</string>
|
<string>Lato-Regular</string>
|
||||||
<string>Lato-BlackItalic.ttf</string>
|
<string>Lato-BlackItalic</string>
|
||||||
<string>Lato-BoldItalic.ttf</string>
|
<string>Lato-BoldItalic</string>
|
||||||
<string>Lato-Light.ttf</string>
|
<string>Lato-Light</string>
|
||||||
<string>Lato-ThinItalic.ttf</string>
|
<string>Lato-HairlineItalic</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
FORCE_FLAG="$1"
|
FORCE_FLAG="$1"
|
||||||
|
|
||||||
## Font
|
## Font
|
||||||
swift run -c release ResgenSwift fonts $FORCE_FLAG "./Fonts/sampleFontsAll.txt" \
|
#swift run -c release ResgenSwift fonts $FORCE_FLAG "./Fonts/sampleFontsAll.txt" \
|
||||||
--extension-output-path "./Fonts/Generated" \
|
# --extension-output-path "./Fonts/Generated" \
|
||||||
--extension-name "FontYolo" \
|
# --extension-name "FontYolo" \
|
||||||
--extension-name-ui-kit "UIFontYolo" \
|
# --extension-name-ui-kit "UIFontYolo" \
|
||||||
--extension-suffix "GenAllScript" \
|
# --extension-suffix "GenAllScript" \
|
||||||
--info-plist-paths "./Fonts/Generated/test.plist ./Fonts/Generated/test2.plist"
|
# --info-plist-paths "./Fonts/Generated/test.plist ./Fonts/Generated/test2.plist"
|
||||||
#
|
#
|
||||||
#echo "\n-------------------------\n"
|
#echo "\n-------------------------\n"
|
||||||
#
|
#
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
// Created by Loris Perret on 08/12/2023.
|
// Created by Loris Perret on 08/12/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
struct Analytics: ParsableCommand {
|
struct Analytics: ParsableCommand {
|
||||||
|
|
||||||
@ -42,17 +42,15 @@ struct Analytics: ParsableCommand {
|
|||||||
guard checkRequirements() else { return }
|
guard checkRequirements() else { return }
|
||||||
|
|
||||||
// Parse input file
|
// Parse input file
|
||||||
let sections = AnalyticsFileParser().parse(options.inputFile, target: options.target)
|
let sections = AnalyticsFileParser.parse(options.inputFile, target: options.target)
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
AnalyticsGenerator.writeExtensionFiles(
|
AnalyticsGenerator.writeExtensionFiles(sections: sections,
|
||||||
sections: sections,
|
target: options.target,
|
||||||
target: options.target,
|
tags: ["ios", "iosonly"],
|
||||||
tags: ["ios", "iosonly"],
|
staticVar: options.staticMembers,
|
||||||
staticVar: options.staticMembers,
|
extensionName: options.extensionName,
|
||||||
extensionName: options.extensionName,
|
extensionFilePath: options.extensionFilePath)
|
||||||
extensionFilePath: options.extensionFilePath
|
|
||||||
)
|
|
||||||
|
|
||||||
print("[\(Self.toolName)] Analytics generated")
|
print("[\(Self.toolName)] Analytics generated")
|
||||||
}
|
}
|
||||||
@ -66,21 +64,19 @@ struct Analytics: ParsableCommand {
|
|||||||
guard fileManager.fileExists(atPath: options.inputFile) else {
|
guard fileManager.fileExists(atPath: options.inputFile) else {
|
||||||
let error = AnalyticsError.fileNotExists(options.inputFile)
|
let error = AnalyticsError.fileNotExists(options.inputFile)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard TrackerType.hasValidTarget(in: options.target) else {
|
guard TrackerType.hasValidTarget(in: options.target) else {
|
||||||
let error = AnalyticsError.noValidTracker(options.target)
|
let error = AnalyticsError.noValidTracker(options.target)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if needed to regenerate
|
// Check if needed to regenerate
|
||||||
guard GeneratorChecker.shouldGenerate(
|
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration,
|
||||||
force: options.forceGeneration,
|
inputFilePath: options.inputFile,
|
||||||
inputFilePath: options.inputFile,
|
extensionFilePath: options.extensionFilePath) else {
|
||||||
extensionFilePath: options.extensionFilePath
|
|
||||||
) else {
|
|
||||||
print("[\(Self.toolName)] Analytics are already up to date :) ")
|
print("[\(Self.toolName)] Analytics are already up to date :) ")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum AnalyticsError: Error {
|
enum AnalyticsError: Error {
|
||||||
|
|
||||||
case noValidTracker(String)
|
case noValidTracker(String)
|
||||||
case fileNotExists(String)
|
case fileNotExists(String)
|
||||||
case missingElement(String)
|
case missingElement(String)
|
||||||
@ -33,7 +32,7 @@ enum AnalyticsError: Error {
|
|||||||
case .parseFailed(let baseError):
|
case .parseFailed(let baseError):
|
||||||
return "error: [\(Analytics.toolName)] Parse input file failed: \(baseError)"
|
return "error: [\(Analytics.toolName)] Parse input file failed: \(baseError)"
|
||||||
|
|
||||||
case let .writeFile(subErrorDescription, filename):
|
case .writeFile(let subErrorDescription, let filename):
|
||||||
return "error: [\(Analytics.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
|
return "error: [\(Analytics.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,10 @@
|
|||||||
// Created by Loris Perret on 08/12/2023.
|
// Created by Loris Perret on 08/12/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
// swiftlint:disable no_grouping_extension
|
|
||||||
|
|
||||||
struct AnalyticsOptions: ParsableArguments {
|
struct AnalyticsOptions: ParsableArguments {
|
||||||
|
|
||||||
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
||||||
var forceGeneration = false
|
var forceGeneration = false
|
||||||
|
|
||||||
@ -37,9 +34,8 @@ struct AnalyticsOptions: ParsableArguments {
|
|||||||
// MARK: - Computed var
|
// MARK: - Computed var
|
||||||
|
|
||||||
extension AnalyticsOptions {
|
extension AnalyticsOptions {
|
||||||
|
|
||||||
var extensionFileName: String {
|
var extensionFileName: String {
|
||||||
if let extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
return "\(extensionName)+\(extensionSuffix).swift"
|
return "\(extensionName)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionName).swift"
|
return "\(extensionName).swift"
|
||||||
|
@ -5,50 +5,34 @@
|
|||||||
// Created by Loris Perret on 08/12/2023.
|
// Created by Loris Perret on 08/12/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CoreVideo
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import CoreVideo
|
||||||
|
|
||||||
// Disabled cause it's a pain to handle in generated string
|
class AnalyticsGenerator {
|
||||||
|
static var targets: [TrackerType] = []
|
||||||
|
|
||||||
enum AnalyticsGenerator {
|
static func writeExtensionFiles(sections: [AnalyticsCategory], target: String, tags: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) {
|
||||||
|
|
||||||
// MARK: - Write content
|
|
||||||
|
|
||||||
static func writeExtensionFiles(
|
|
||||||
sections: [AnalyticsCategory],
|
|
||||||
target: String,
|
|
||||||
tags: [String],
|
|
||||||
staticVar: Bool,
|
|
||||||
extensionName: String,
|
|
||||||
extensionFilePath: String
|
|
||||||
) {
|
|
||||||
// Get target type from enum
|
// Get target type from enum
|
||||||
let targetsString: [String] = target.components(separatedBy: " ")
|
let targetsString: [String] = target.components(separatedBy: " ")
|
||||||
let targets = {
|
|
||||||
var targets = [TrackerType]()
|
TrackerType.allCases.forEach { enumTarget in
|
||||||
TrackerType.allCases.forEach { enumTarget in
|
if targetsString.contains(enumTarget.value) {
|
||||||
if targetsString.contains(enumTarget.value) {
|
targets.append(enumTarget)
|
||||||
targets.append(enumTarget)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return targets
|
}
|
||||||
}()
|
|
||||||
|
|
||||||
// Get extension content
|
// Get extension content
|
||||||
let extensionFileContent = getExtensionContent(
|
let extensionFileContent = Self.getExtensionContent(sections: sections,
|
||||||
targets: targets,
|
tags: tags,
|
||||||
sections: sections,
|
staticVar: staticVar,
|
||||||
tags: tags,
|
extensionName: extensionName)
|
||||||
staticVar: staticVar,
|
|
||||||
extensionName: extensionName
|
|
||||||
)
|
|
||||||
|
|
||||||
// Write content
|
// Write content
|
||||||
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
||||||
do {
|
do {
|
||||||
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch {
|
} catch let error {
|
||||||
let error = AnalyticsError.writeFile(extensionFilePath, error.localizedDescription)
|
let error = AnalyticsError.writeFile(extensionFilePath, error.localizedDescription)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
@ -57,57 +41,38 @@ enum AnalyticsGenerator {
|
|||||||
|
|
||||||
// MARK: - Extension content
|
// MARK: - Extension content
|
||||||
|
|
||||||
static func getExtensionContent(
|
static func getExtensionContent(sections: [AnalyticsCategory], tags: [String], staticVar: Bool, extensionName: String) -> String {
|
||||||
targets: [TrackerType],
|
|
||||||
sections: [AnalyticsCategory],
|
|
||||||
tags: [String],
|
|
||||||
staticVar: Bool,
|
|
||||||
extensionName: String
|
|
||||||
) -> String {
|
|
||||||
[
|
[
|
||||||
getHeader(
|
Self.getHeader(extensionClassname: extensionName, staticVar: staticVar),
|
||||||
targets: targets,
|
Self.getProperties(sections: sections, tags: tags, staticVar: staticVar),
|
||||||
extensionClassname: extensionName,
|
Self.getFooter()
|
||||||
staticVar: staticVar
|
|
||||||
),
|
|
||||||
getProperties(
|
|
||||||
sections: sections,
|
|
||||||
tags: tags,
|
|
||||||
staticVar: staticVar
|
|
||||||
),
|
|
||||||
getFooter()
|
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Extension part
|
// MARK: - Extension part
|
||||||
|
|
||||||
private static func getHeader(
|
private static func getHeader(extensionClassname: String, staticVar: Bool) -> String {
|
||||||
targets: [TrackerType],
|
|
||||||
extensionClassname: String,
|
|
||||||
staticVar: Bool
|
|
||||||
) -> String {
|
|
||||||
"""
|
"""
|
||||||
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
|
||||||
|
|
||||||
\(getImport(targets: targets))
|
\(Self.getImport())
|
||||||
|
|
||||||
\(getAnalyticsProtocol(targets: targets))
|
\(Self.getAnalyticsProtocol())
|
||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
|
|
||||||
class AnalyticsManager {
|
class AnalyticsManager {
|
||||||
|
|
||||||
static var shared = AnalyticsManager()
|
static var shared = AnalyticsManager()
|
||||||
|
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
|
|
||||||
var managers: [AnalyticsManagerProtocol] = []
|
var managers: [AnalyticsManagerProtocol] = []
|
||||||
|
|
||||||
\(getEnabledContent())
|
\(Self.getEnabledContent())
|
||||||
|
|
||||||
\(getAnalyticsProperties(targets: targets))
|
\(Self.getAnalyticsProperties())
|
||||||
|
|
||||||
\(getPrivateLogFunction())
|
\(Self.getPrivateLogFunction())
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +88,7 @@ enum AnalyticsGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getImport(targets: [TrackerType]) -> String {
|
private static func getImport() -> String {
|
||||||
var result: [String] = []
|
var result: [String] = []
|
||||||
|
|
||||||
if targets.contains(TrackerType.matomo) {
|
if targets.contains(TrackerType.matomo) {
|
||||||
@ -166,7 +131,7 @@ enum AnalyticsGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getAnalyticsProperties(targets: [TrackerType]) -> String {
|
private static func getAnalyticsProperties() -> String {
|
||||||
var header = ""
|
var header = ""
|
||||||
var content: [String] = []
|
var content: [String] = []
|
||||||
let footer = " }"
|
let footer = " }"
|
||||||
@ -199,12 +164,11 @@ enum AnalyticsGenerator {
|
|||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getAnalyticsProtocol(targets: [TrackerType]) -> String {
|
private static func getAnalyticsProtocol() -> String {
|
||||||
let proto = """
|
let proto = """
|
||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
|
|
||||||
func logScreen(name: String, path: String)
|
func logScreen(name: String, path: String)
|
||||||
func logEvent(
|
func logEvent(
|
||||||
name: String,
|
name: String,
|
||||||
@ -229,11 +193,7 @@ enum AnalyticsGenerator {
|
|||||||
return result.joined(separator: "\n")
|
return result.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getProperties(
|
private static func getProperties(sections: [AnalyticsCategory], tags: [String], staticVar: Bool) -> String {
|
||||||
sections: [AnalyticsCategory],
|
|
||||||
tags: [String],
|
|
||||||
staticVar: Bool
|
|
||||||
) -> String {
|
|
||||||
sections
|
sections
|
||||||
.compactMap { section in
|
.compactMap { section in
|
||||||
// Check that at least one string will be generated
|
// Check that at least one string will be generated
|
||||||
|
@ -11,10 +11,10 @@ enum FirebaseGenerator {
|
|||||||
|
|
||||||
static var service: String {
|
static var service: String {
|
||||||
[
|
[
|
||||||
Self.header,
|
FirebaseGenerator.header,
|
||||||
Self.logScreen,
|
FirebaseGenerator.logScreen,
|
||||||
Self.logEvent,
|
FirebaseGenerator.logEvent,
|
||||||
Self.footer
|
FirebaseGenerator.footer
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,11 @@ enum MatomoGenerator {
|
|||||||
|
|
||||||
static var service: String {
|
static var service: String {
|
||||||
[
|
[
|
||||||
Self.header,
|
MatomoGenerator.header,
|
||||||
Self.setup,
|
MatomoGenerator.setup,
|
||||||
Self.logScreen,
|
MatomoGenerator.logScreen,
|
||||||
Self.logEvent,
|
MatomoGenerator.logEvent,
|
||||||
Self.footer
|
MatomoGenerator.footer
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class AnalyticsCategory {
|
class AnalyticsCategory {
|
||||||
|
|
||||||
// MARK: - Properties
|
|
||||||
|
|
||||||
let id: String // OnBoarding
|
let id: String // OnBoarding
|
||||||
var definitions = [AnalyticsDefinition]()
|
var definitions = [AnalyticsDefinition]()
|
||||||
|
|
||||||
|
@ -9,9 +9,6 @@ import Foundation
|
|||||||
import ToolCore
|
import ToolCore
|
||||||
|
|
||||||
class AnalyticsDefinition {
|
class AnalyticsDefinition {
|
||||||
|
|
||||||
// MARK: - Properties
|
|
||||||
|
|
||||||
let id: String
|
let id: String
|
||||||
var name: String
|
var name: String
|
||||||
var path: String = ""
|
var path: String = ""
|
||||||
|
@ -8,19 +8,16 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct AnalyticsFile: Codable {
|
struct AnalyticsFile: Codable {
|
||||||
|
|
||||||
var categories: [AnalyticsCategoryDTO]
|
var categories: [AnalyticsCategoryDTO]
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AnalyticsCategoryDTO: Codable {
|
struct AnalyticsCategoryDTO: Codable {
|
||||||
|
|
||||||
var id: String
|
var id: String
|
||||||
var screens: [AnalyticsDefinitionScreenDTO]?
|
var screens: [AnalyticsDefinitionScreenDTO]?
|
||||||
var events: [AnalyticsDefinitionEventDTO]?
|
var events: [AnalyticsDefinitionEventDTO]?
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AnalyticsDefinitionScreenDTO: Codable {
|
struct AnalyticsDefinitionScreenDTO: Codable {
|
||||||
|
|
||||||
var id: String
|
var id: String
|
||||||
var name: String
|
var name: String
|
||||||
var tags: String
|
var tags: String
|
||||||
@ -31,7 +28,6 @@ struct AnalyticsDefinitionScreenDTO: Codable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct AnalyticsDefinitionEventDTO: Codable {
|
struct AnalyticsDefinitionEventDTO: Codable {
|
||||||
|
|
||||||
var id: String
|
var id: String
|
||||||
var name: String
|
var name: String
|
||||||
var tags: String
|
var tags: String
|
||||||
@ -43,7 +39,6 @@ struct AnalyticsDefinitionEventDTO: Codable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct AnalyticsParameterDTO: Codable {
|
struct AnalyticsParameterDTO: Codable {
|
||||||
|
|
||||||
var name: String
|
var name: String
|
||||||
var type: String
|
var type: String
|
||||||
var replaceIn: String?
|
var replaceIn: String?
|
||||||
|
@ -8,9 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class AnalyticsParameter {
|
class AnalyticsParameter {
|
||||||
|
|
||||||
// MARK: - Properties
|
|
||||||
|
|
||||||
var name: String
|
var name: String
|
||||||
var type: String
|
var type: String
|
||||||
var replaceIn: [String] = []
|
var replaceIn: [String] = []
|
||||||
|
@ -10,7 +10,6 @@ import Foundation
|
|||||||
extension AnalyticsDefinition {
|
extension AnalyticsDefinition {
|
||||||
|
|
||||||
enum TagType {
|
enum TagType {
|
||||||
|
|
||||||
case screen
|
case screen
|
||||||
case event
|
case event
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum TrackerType: CaseIterable, Sendable {
|
enum TrackerType: CaseIterable {
|
||||||
|
|
||||||
case matomo
|
case matomo
|
||||||
case firebase
|
case firebase
|
||||||
|
|
||||||
@ -16,7 +15,6 @@ enum TrackerType: CaseIterable, Sendable {
|
|||||||
switch self {
|
switch self {
|
||||||
case .matomo:
|
case .matomo:
|
||||||
"matomo"
|
"matomo"
|
||||||
|
|
||||||
case .firebase:
|
case .firebase:
|
||||||
"firebase"
|
"firebase"
|
||||||
}
|
}
|
||||||
|
@ -9,48 +9,10 @@ import Foundation
|
|||||||
import Yams
|
import Yams
|
||||||
|
|
||||||
class AnalyticsFileParser {
|
class AnalyticsFileParser {
|
||||||
|
private static var inputFile: String = ""
|
||||||
|
private static var target: String = ""
|
||||||
|
|
||||||
// MARK: - Properties
|
private static func parseYaml() -> AnalyticsFile {
|
||||||
|
|
||||||
private var inputFile: String = ""
|
|
||||||
private var target: String = ""
|
|
||||||
|
|
||||||
// MARK: - Methods
|
|
||||||
|
|
||||||
func parse(_ inputFile: String, target: String) -> [AnalyticsCategory] {
|
|
||||||
self.inputFile = inputFile
|
|
||||||
self.target = target
|
|
||||||
|
|
||||||
let tagFile = parseYaml()
|
|
||||||
|
|
||||||
return tagFile
|
|
||||||
.categories
|
|
||||||
.map { categorie in
|
|
||||||
let section = AnalyticsCategory(id: categorie.id)
|
|
||||||
|
|
||||||
if let screens = categorie.screens {
|
|
||||||
section
|
|
||||||
.definitions
|
|
||||||
.append(
|
|
||||||
contentsOf: getTagDefinitionScreen(from: screens)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let events = categorie.events {
|
|
||||||
section
|
|
||||||
.definitions
|
|
||||||
.append(
|
|
||||||
contentsOf: getTagDefinitionEvent(from: events)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return section
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Private methods
|
|
||||||
|
|
||||||
private func parseYaml() -> AnalyticsFile {
|
|
||||||
guard let data = FileManager().contents(atPath: inputFile) else {
|
guard let data = FileManager().contents(atPath: inputFile) else {
|
||||||
let error = AnalyticsError.fileNotExists(inputFile)
|
let error = AnalyticsError.fileNotExists(inputFile)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
@ -67,9 +29,10 @@ class AnalyticsFileParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
private static func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
||||||
parameters.map { dtoParameter in
|
parameters.map { dtoParameter in
|
||||||
// Type
|
// Type
|
||||||
|
|
||||||
let type = dtoParameter.type.uppercasedFirst()
|
let type = dtoParameter.type.uppercasedFirst()
|
||||||
|
|
||||||
guard
|
guard
|
||||||
@ -96,7 +59,7 @@ class AnalyticsFileParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getTagDefinition(
|
private static func getTagDefinition(
|
||||||
id: String,
|
id: String,
|
||||||
name: String,
|
name: String,
|
||||||
type: AnalyticsDefinition.TagType,
|
type: AnalyticsDefinition.TagType,
|
||||||
@ -109,20 +72,20 @@ class AnalyticsFileParser {
|
|||||||
.components(separatedBy: ",")
|
.components(separatedBy: ",")
|
||||||
.map { $0.removeLeadingTrailingWhitespace() }
|
.map { $0.removeLeadingTrailingWhitespace() }
|
||||||
|
|
||||||
if let comments {
|
if let comments = comments {
|
||||||
definition.comments = comments
|
definition.comments = comments
|
||||||
}
|
}
|
||||||
|
|
||||||
if let parameters {
|
if let parameters = parameters {
|
||||||
definition.parameters = getParameters(from: parameters)
|
definition.parameters = Self.getParameters(from: parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
return definition
|
return definition
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getTagDefinitionScreen(from screens: [AnalyticsDefinitionScreenDTO]) -> [AnalyticsDefinition] {
|
private static func getTagDefinitionScreen(from screens: [AnalyticsDefinitionScreenDTO]) -> [AnalyticsDefinition] {
|
||||||
screens.map { screen in
|
screens.map { screen in
|
||||||
let definition: AnalyticsDefinition = getTagDefinition(
|
let definition: AnalyticsDefinition = Self.getTagDefinition(
|
||||||
id: screen.id,
|
id: screen.id,
|
||||||
name: screen.name,
|
name: screen.name,
|
||||||
type: .screen,
|
type: .screen,
|
||||||
@ -147,9 +110,9 @@ class AnalyticsFileParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getTagDefinitionEvent(from events: [AnalyticsDefinitionEventDTO]) -> [AnalyticsDefinition] {
|
private static func getTagDefinitionEvent(from events: [AnalyticsDefinitionEventDTO]) -> [AnalyticsDefinition] {
|
||||||
events.map { event in
|
events.map { event in
|
||||||
let definition: AnalyticsDefinition = getTagDefinition(
|
let definition: AnalyticsDefinition = Self.getTagDefinition(
|
||||||
id: event.id,
|
id: event.id,
|
||||||
name: event.name,
|
name: event.name,
|
||||||
type: .event,
|
type: .event,
|
||||||
@ -181,4 +144,35 @@ class AnalyticsFileParser {
|
|||||||
return definition
|
return definition
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func parse(_ inputFile: String, target: String) -> [AnalyticsCategory] {
|
||||||
|
self.inputFile = inputFile
|
||||||
|
self.target = target
|
||||||
|
|
||||||
|
let tagFile = Self.parseYaml()
|
||||||
|
|
||||||
|
return tagFile
|
||||||
|
.categories
|
||||||
|
.map { categorie in
|
||||||
|
let section: AnalyticsCategory = AnalyticsCategory(id: categorie.id)
|
||||||
|
|
||||||
|
if let screens = categorie.screens {
|
||||||
|
section
|
||||||
|
.definitions
|
||||||
|
.append(
|
||||||
|
contentsOf: Self.getTagDefinitionScreen(from: screens)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let events = categorie.events {
|
||||||
|
section
|
||||||
|
.definitions
|
||||||
|
.append(
|
||||||
|
contentsOf: Self.getTagDefinitionEvent(from: events)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return section
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,15 @@
|
|||||||
// Created by Thibaut Schmitt on 20/12/2021.
|
// Created by Thibaut Schmitt on 20/12/2021.
|
||||||
//
|
//
|
||||||
|
|
||||||
@preconcurrency import ArgumentParser
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
struct Colors: ParsableCommand {
|
struct Colors: ParsableCommand {
|
||||||
|
|
||||||
// MARK: - CommandConfiguration
|
// MARK: - CommandConfiguration
|
||||||
|
|
||||||
static let configuration = CommandConfiguration(
|
static var configuration = CommandConfiguration(
|
||||||
abstract: "A utility for generate colors assets and their getters.",
|
abstract: "A utility for generate colors assets and their getters.",
|
||||||
version: ResgenSwiftVersion
|
version: ResgenSwiftVersion
|
||||||
)
|
)
|
||||||
@ -31,7 +31,7 @@ struct Colors: ParsableCommand {
|
|||||||
|
|
||||||
// MARK: - Run
|
// MARK: - Run
|
||||||
|
|
||||||
func run() throws {
|
public func run() throws {
|
||||||
print("[\(Self.toolName)] Starting colors generation")
|
print("[\(Self.toolName)] Starting colors generation")
|
||||||
|
|
||||||
// Check requirements
|
// Check requirements
|
||||||
@ -43,36 +43,28 @@ struct Colors: ParsableCommand {
|
|||||||
deleteCurrentColors()
|
deleteCurrentColors()
|
||||||
|
|
||||||
// Get colors to generate
|
// Get colors to generate
|
||||||
let parsedColors = ColorFileParser.parse(
|
let parsedColors = ColorFileParser.parse(options.inputFile,
|
||||||
options.inputFile,
|
colorStyle: options.style)
|
||||||
colorStyle: options.style
|
|
||||||
)
|
|
||||||
// -> Time: 0.0020350217819213867 seconds
|
// -> Time: 0.0020350217819213867 seconds
|
||||||
|
|
||||||
// Generate all colors in xcassets
|
// Generate all colors in xcassets
|
||||||
ColorXcassetHelper.generateXcassetColors(
|
ColorXcassetHelper.generateXcassetColors(colors: parsedColors,
|
||||||
colors: parsedColors,
|
to: options.xcassetsPath)
|
||||||
to: options.xcassetsPath
|
|
||||||
)
|
|
||||||
// -> Time: 3.4505380392074585 seconds
|
// -> Time: 3.4505380392074585 seconds
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
ColorExtensionGenerator.writeExtensionFile(
|
ColorExtensionGenerator.writeExtensionFile(colors: parsedColors,
|
||||||
colors: parsedColors,
|
staticVar: options.staticMembers,
|
||||||
staticVar: options.staticMembers,
|
extensionName: options.extensionName,
|
||||||
extensionName: options.extensionName,
|
extensionFilePath: options.extensionFilePath,
|
||||||
extensionFilePath: options.extensionFilePath,
|
isSwiftUI: true)
|
||||||
isSwiftUI: true
|
|
||||||
)
|
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
ColorExtensionGenerator.writeExtensionFile(
|
ColorExtensionGenerator.writeExtensionFile(colors: parsedColors,
|
||||||
colors: parsedColors,
|
staticVar: options.staticMembers,
|
||||||
staticVar: options.staticMembers,
|
extensionName: options.extensionNameUIKit,
|
||||||
extensionName: options.extensionNameUIKit,
|
extensionFilePath: options.extensionFilePathUIKit,
|
||||||
extensionFilePath: options.extensionFilePathUIKit,
|
isSwiftUI: false)
|
||||||
isSwiftUI: false
|
|
||||||
)
|
|
||||||
|
|
||||||
print("[\(Self.toolName)] Colors generated")
|
print("[\(Self.toolName)] Colors generated")
|
||||||
}
|
}
|
||||||
@ -86,29 +78,27 @@ struct Colors: ParsableCommand {
|
|||||||
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.description)
|
print(error.description)
|
||||||
Self.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.description)
|
print(error.description)
|
||||||
Self.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.extensionNameUIKit else {
|
guard options.extensionName != options.extensionNameUIKit else {
|
||||||
let error = ColorsToolError.extensionNamesCollision(options.extensionName)
|
let error = ColorsToolError.extensionNamesCollision(options.extensionName)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if needed to regenerate
|
// Check if needed to regenerate
|
||||||
guard GeneratorChecker.shouldGenerate(
|
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration,
|
||||||
force: options.forceGeneration,
|
inputFilePath: options.inputFile,
|
||||||
inputFilePath: options.inputFile,
|
extensionFilePath: options.extensionFilePath) else {
|
||||||
extensionFilePath: options.extensionFilePath
|
|
||||||
) else {
|
|
||||||
print("[\(Self.toolName)] Colors are already up to date :) ")
|
print("[\(Self.toolName)] Colors are already up to date :) ")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -128,7 +118,7 @@ struct Colors: ParsableCommand {
|
|||||||
} catch {
|
} catch {
|
||||||
let error = ColorsToolError.deleteExistingColors("\(options.xcassetsPath)/Colors")
|
let error = ColorsToolError.deleteExistingColors("\(options.xcassetsPath)/Colors")
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum ColorsToolError: Error {
|
enum ColorsToolError: Error {
|
||||||
|
|
||||||
case extensionNamesCollision(String)
|
case extensionNamesCollision(String)
|
||||||
case badFormat(String)
|
case badFormat(String)
|
||||||
case writeAsset(String)
|
case writeAsset(String)
|
||||||
@ -32,13 +31,13 @@ enum ColorsToolError: Error {
|
|||||||
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 let .writeExtension(filename, 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 let .badColorDefinition(lightColor, 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):
|
||||||
|
@ -5,13 +5,10 @@
|
|||||||
// Created by Thibaut Schmitt on 17/01/2022.
|
// Created by Thibaut Schmitt on 17/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
// swiftlint:disable no_grouping_extension
|
|
||||||
|
|
||||||
struct ColorsToolOptions: ParsableArguments {
|
struct ColorsToolOptions: ParsableArguments {
|
||||||
|
|
||||||
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
||||||
var forceGeneration = false
|
var forceGeneration = false
|
||||||
|
|
||||||
@ -47,7 +44,7 @@ extension ColorsToolOptions {
|
|||||||
// MARK: - SwiftUI
|
// MARK: - SwiftUI
|
||||||
|
|
||||||
var extensionFileName: String {
|
var extensionFileName: String {
|
||||||
if let extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
return "\(extensionName)+\(extensionSuffix).swift"
|
return "\(extensionName)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionName).swift"
|
return "\(extensionName).swift"
|
||||||
@ -60,7 +57,7 @@ extension ColorsToolOptions {
|
|||||||
// MARK: - UIKit
|
// MARK: - UIKit
|
||||||
|
|
||||||
var extensionFileNameUIKit: String {
|
var extensionFileNameUIKit: String {
|
||||||
if let extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionNameUIKit).swift"
|
return "\(extensionNameUIKit).swift"
|
||||||
|
@ -15,38 +15,32 @@ struct ColorExtensionGenerator {
|
|||||||
|
|
||||||
// MARK: - UIKit
|
// MARK: - UIKit
|
||||||
|
|
||||||
static func writeExtensionFile(
|
static func writeExtensionFile(colors: [ParsedColor],
|
||||||
colors: [ParsedColor],
|
staticVar: Bool,
|
||||||
staticVar: Bool,
|
extensionName: String,
|
||||||
extensionName: String,
|
extensionFilePath: String,
|
||||||
extensionFilePath: String,
|
isSwiftUI: Bool) {
|
||||||
isSwiftUI: Bool
|
|
||||||
) {
|
|
||||||
// Create extension content
|
// Create extension content
|
||||||
let extensionContent = Self.getExtensionContent(
|
let extensionContent = Self.getExtensionContent(colors: colors,
|
||||||
colors: colors,
|
staticVar: staticVar,
|
||||||
staticVar: staticVar,
|
extensionName: extensionName,
|
||||||
extensionName: extensionName,
|
isSwiftUI: isSwiftUI)
|
||||||
isSwiftUI: isSwiftUI
|
|
||||||
)
|
|
||||||
|
|
||||||
// Write content
|
// Write content
|
||||||
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
||||||
do {
|
do {
|
||||||
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch {
|
} catch let error {
|
||||||
let error = ColorsToolError.writeExtension(extensionFilePath, error.localizedDescription)
|
let error = ColorsToolError.writeExtension(extensionFilePath, error.localizedDescription)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Colors.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getExtensionContent(
|
static func getExtensionContent(colors: [ParsedColor],
|
||||||
colors: [ParsedColor],
|
staticVar: Bool,
|
||||||
staticVar: Bool,
|
extensionName: String,
|
||||||
extensionName: String,
|
isSwiftUI: Bool) -> String {
|
||||||
isSwiftUI: Bool
|
|
||||||
) -> String {
|
|
||||||
[
|
[
|
||||||
Self.getHeader(extensionClassname: extensionName, isSwiftUI: isSwiftUI),
|
Self.getHeader(extensionClassname: extensionName, isSwiftUI: isSwiftUI),
|
||||||
Self.getProperties(for: colors, withStaticVar: staticVar, isSwiftUI: isSwiftUI),
|
Self.getProperties(for: colors, withStaticVar: staticVar, isSwiftUI: isSwiftUI),
|
||||||
@ -72,11 +66,9 @@ struct ColorExtensionGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getProperties(
|
private static func getProperties(for colors: [ParsedColor],
|
||||||
for colors: [ParsedColor],
|
withStaticVar staticVar: Bool,
|
||||||
withStaticVar staticVar: Bool,
|
isSwiftUI: Bool) -> String {
|
||||||
isSwiftUI: Bool
|
|
||||||
) -> String {
|
|
||||||
colors.map {
|
colors.map {
|
||||||
$0.getColorProperty(isStatic: staticVar, isSwiftUI: isSwiftUI)
|
$0.getColorProperty(isStatic: staticVar, isSwiftUI: isSwiftUI)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
|
||||||
enum ColorXcassetHelper {
|
struct ColorXcassetHelper {
|
||||||
|
|
||||||
static func generateXcassetColors(colors: [ParsedColor], to xcassetsPath: String) {
|
static func generateXcassetColors(colors: [ParsedColor], to xcassetsPath: String) {
|
||||||
colors.forEach {
|
colors.forEach {
|
||||||
@ -25,10 +25,8 @@ enum ColorXcassetHelper {
|
|||||||
let fileManager = FileManager()
|
let fileManager = FileManager()
|
||||||
if fileManager.fileExists(atPath: colorSetPath) == false {
|
if fileManager.fileExists(atPath: colorSetPath) == false {
|
||||||
do {
|
do {
|
||||||
try fileManager.createDirectory(
|
try fileManager.createDirectory(atPath: colorSetPath,
|
||||||
atPath: colorSetPath,
|
withIntermediateDirectories: true)
|
||||||
withIntermediateDirectories: true
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
let error = ColorsToolError.createAssetFolder(colorSetPath)
|
let error = ColorsToolError.createAssetFolder(colorSetPath)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
@ -40,7 +38,7 @@ enum ColorXcassetHelper {
|
|||||||
let contentsJsonPathURL = URL(fileURLWithPath: contentsJsonPath)
|
let contentsJsonPathURL = URL(fileURLWithPath: contentsJsonPath)
|
||||||
do {
|
do {
|
||||||
try color.contentsJSON().write(to: contentsJsonPathURL, atomically: false, encoding: .utf8)
|
try color.contentsJSON().write(to: contentsJsonPathURL, atomically: false, encoding: .utf8)
|
||||||
} catch {
|
} catch let error {
|
||||||
let error = ColorsToolError.writeAsset(error.localizedDescription)
|
let error = ColorsToolError.writeAsset(error.localizedDescription)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Colors.exit(withError: error)
|
Colors.exit(withError: error)
|
||||||
|
@ -5,11 +5,10 @@
|
|||||||
// Created by Thibaut Schmitt on 29/08/2022.
|
// Created by Thibaut Schmitt on 29/08/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
enum ColorStyle: String, Decodable, ExpressibleByArgument {
|
enum ColorStyle: String, Decodable, ExpressibleByArgument {
|
||||||
|
|
||||||
case light
|
case light
|
||||||
case all
|
case all
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct ParsedColor {
|
struct ParsedColor {
|
||||||
|
|
||||||
let name: String
|
let name: String
|
||||||
let light: String
|
let light: String
|
||||||
let dark: String
|
let dark: String
|
||||||
|
@ -7,11 +7,10 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum ColorFileParser {
|
class ColorFileParser {
|
||||||
|
|
||||||
static func parse(_ inputFile: String, colorStyle: ColorStyle) -> [ParsedColor] {
|
static func parse(_ inputFile: String, colorStyle: ColorStyle) -> [ParsedColor] {
|
||||||
// Get content of input file
|
// Get content of input file
|
||||||
let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8) // swiftlint:disable:this force_try
|
let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8)
|
||||||
let colorsByLines = inputFileContent.components(separatedBy: CharacterSet.newlines)
|
let colorsByLines = inputFileContent.components(separatedBy: CharacterSet.newlines)
|
||||||
|
|
||||||
// Iterate on each line of input file
|
// Iterate on each line of input file
|
||||||
@ -21,9 +20,9 @@ enum ColorFileParser {
|
|||||||
static func parseLines(lines: [String], colorStyle: ColorStyle) -> [ParsedColor] {
|
static func parseLines(lines: [String], colorStyle: ColorStyle) -> [ParsedColor] {
|
||||||
lines
|
lines
|
||||||
.enumerated()
|
.enumerated()
|
||||||
.compactMap { _, colorLine in // swiftlint:disable:this unused_enumerated
|
.compactMap { lineNumber, colorLine in
|
||||||
// Required format:
|
// Required format:
|
||||||
// colorName = "#RGB/#ARGB", colorName "#RGB/#ARGB", colorName "#RGB/#ARGB" "#RGB/#ARGB"
|
// colorName = "#RGB/#ARGB", colorName "#RGB/#ARGB", colorName "#RGB/#ARGB" "#RGB/#ARGB"
|
||||||
let colorLineCleanedUp = colorLine
|
let colorLineCleanedUp = colorLine
|
||||||
.removeLeadingWhitespace()
|
.removeLeadingWhitespace()
|
||||||
.removeTrailingWhitespace()
|
.removeTrailingWhitespace()
|
||||||
|
@ -5,13 +5,10 @@
|
|||||||
// Created by Thibaut Schmitt on 17/01/2022.
|
// Created by Thibaut Schmitt on 17/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
// swiftlint:disable no_grouping_extension
|
|
||||||
|
|
||||||
struct FontsOptions: ParsableArguments {
|
struct FontsOptions: ParsableArguments {
|
||||||
|
|
||||||
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
||||||
var forceGeneration = false
|
var forceGeneration = false
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
// Created by Thibaut Schmitt on 13/12/2021.
|
// Created by Thibaut Schmitt on 13/12/2021.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
struct Fonts: ParsableCommand {
|
struct Fonts: ParsableCommand {
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ struct Fonts: ParsableCommand {
|
|||||||
|
|
||||||
// MARK: - Run
|
// MARK: - Run
|
||||||
|
|
||||||
func run() throws {
|
public func run() throws {
|
||||||
print("[\(Self.toolName)] Starting fonts generation")
|
print("[\(Self.toolName)] Starting fonts generation")
|
||||||
print("[\(Self.toolName)] Will use inputFile \(options.inputFile) to generate fonts")
|
print("[\(Self.toolName)] Will use inputFile \(options.inputFile) to generate fonts")
|
||||||
|
|
||||||
@ -43,31 +43,22 @@ struct Fonts: ParsableCommand {
|
|||||||
let fontsToGenerate = FontFileParser.parse(options.inputFile)
|
let fontsToGenerate = FontFileParser.parse(options.inputFile)
|
||||||
|
|
||||||
// Get real font names
|
// Get real font names
|
||||||
let inputFolder = URL(fileURLWithPath: options.inputFile)
|
let inputFolder = URL(fileURLWithPath: options.inputFile).deletingLastPathComponent().relativePath
|
||||||
.deletingLastPathComponent()
|
let fontsNames = FontsToolHelper.getFontPostScriptName(for: fontsToGenerate,
|
||||||
.relativePath
|
inputFolder: inputFolder)
|
||||||
|
|
||||||
let fontsNames = FontsToolHelper.getFontPostScriptName(
|
|
||||||
for: fontsToGenerate,
|
|
||||||
inputFolder: inputFolder
|
|
||||||
)
|
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
FontExtensionGenerator.writeExtensionFile(
|
FontExtensionGenerator.writeExtensionFile(fontsNames: fontsNames,
|
||||||
fontsNames: fontsNames,
|
staticVar: options.staticMembers,
|
||||||
staticVar: options.staticMembers,
|
extensionName: options.extensionName,
|
||||||
extensionName: options.extensionName,
|
extensionFilePath: options.extensionFilePath,
|
||||||
extensionFilePath: options.extensionFilePath,
|
isSwiftUI: true)
|
||||||
isSwiftUI: true
|
|
||||||
)
|
|
||||||
|
|
||||||
FontExtensionGenerator.writeExtensionFile(
|
FontExtensionGenerator.writeExtensionFile(fontsNames: fontsNames,
|
||||||
fontsNames: fontsNames,
|
staticVar: options.staticMembers,
|
||||||
staticVar: options.staticMembers,
|
extensionName: options.extensionNameUIKit,
|
||||||
extensionName: options.extensionNameUIKit,
|
extensionFilePath: options.extensionFilePathUIKit,
|
||||||
extensionFilePath: options.extensionFilePathUIKit,
|
isSwiftUI: false)
|
||||||
isSwiftUI: false
|
|
||||||
)
|
|
||||||
|
|
||||||
print("Info.plist has been updated with:")
|
print("Info.plist has been updated with:")
|
||||||
print("\(FontPlistGenerator.generatePlistUIAppsFontContent(for: fontsNames, infoPlistPaths: options.infoPlistPaths))")
|
print("\(FontPlistGenerator.generatePlistUIAppsFontContent(for: fontsNames, infoPlistPaths: options.infoPlistPaths))")
|
||||||
@ -84,22 +75,20 @@ struct Fonts: ParsableCommand {
|
|||||||
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.description)
|
print(error.description)
|
||||||
Self.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.extensionNameUIKit else {
|
guard options.extensionName != options.extensionNameUIKit else {
|
||||||
let error = FontsToolError.extensionNamesCollision(options.extensionName)
|
let error = FontsToolError.extensionNamesCollision(options.extensionName)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Fonts.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if needed to regenerate
|
// Check if needed to regenerate
|
||||||
guard GeneratorChecker.shouldGenerate(
|
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration,
|
||||||
force: options.forceGeneration,
|
inputFilePath: options.inputFile,
|
||||||
inputFilePath: options.inputFile,
|
extensionFilePath: options.extensionFilePath) else {
|
||||||
extensionFilePath: options.extensionFilePath
|
|
||||||
) else {
|
|
||||||
print("[\(Self.toolName)] Fonts are already up to date :) ")
|
print("[\(Self.toolName)] Fonts are already up to date :) ")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum FontsToolError: Error {
|
enum FontsToolError: Error {
|
||||||
|
|
||||||
case extensionNamesCollision(String)
|
case extensionNamesCollision(String)
|
||||||
case fcScan(String, Int32, String?)
|
case fcScan(String, Int32, String?)
|
||||||
case inputFolderNotFound(String)
|
case inputFolderNotFound(String)
|
||||||
@ -20,7 +19,7 @@ enum FontsToolError: Error {
|
|||||||
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 let .fcScan(path, code, 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):
|
||||||
@ -29,7 +28,7 @@ enum FontsToolError: Error {
|
|||||||
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 let .writeExtension(filename, 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)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
|
||||||
enum FontsToolHelper {
|
class FontsToolHelper {
|
||||||
|
|
||||||
static func getFontPostScriptName(for fonts: [String], inputFolder: String) -> [FontName] {
|
static func getFontPostScriptName(for fonts: [String], inputFolder: String) -> [FontName] {
|
||||||
let fontsFilenames = Self.getFontsFilenames(fromInputFolder: inputFolder)
|
let fontsFilenames = Self.getFontsFilenames(fromInputFolder: inputFolder)
|
||||||
@ -43,10 +43,10 @@ enum FontsToolHelper {
|
|||||||
Fonts.exit(withError: error)
|
Fonts.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
let enumerator: FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: inputFolder)! // swiftlint:disable:this force_unwrapping
|
let enumerator: FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: inputFolder)!
|
||||||
|
|
||||||
// Filters font files
|
// Filters font files
|
||||||
let fontsFileNames: [String] = (enumerator.allObjects as! [String]) // swiftlint:disable:this force_cast
|
let fontsFileNames: [String] = (enumerator.allObjects as! [String])
|
||||||
.filter {
|
.filter {
|
||||||
if $0.hasSuffix(".ttf") || $0.hasSuffix(".otf") {
|
if $0.hasSuffix(".ttf") || $0.hasSuffix(".otf") {
|
||||||
return true
|
return true
|
||||||
@ -57,26 +57,17 @@ enum FontsToolHelper {
|
|||||||
return fontsFileNames
|
return fontsFileNames
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getFontName(atPath path: String) -> FontName {
|
private static func getFontName(atPath path: String) -> String {
|
||||||
// print("fc-scan --format %{postscriptname} \(path)")
|
//print("fc-scan --format %{postscriptname} \(path)")
|
||||||
// Get real font name
|
// Get real font name
|
||||||
let task = Shell.shell(["fc-scan", "--format", "%{postscriptname}", path])
|
let task = Shell.shell(["fc-scan", "--format", "%{postscriptname}", path])
|
||||||
|
|
||||||
guard let postscriptName = 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.description)
|
print(error.description)
|
||||||
Fonts.exit(withError: error)
|
Fonts.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
let pathURL = URL(fileURLWithPath: path)
|
return fontName
|
||||||
let filename = pathURL
|
|
||||||
.deletingPathExtension()
|
|
||||||
.lastPathComponent
|
|
||||||
|
|
||||||
return FontName(
|
|
||||||
postscriptName: postscriptName,
|
|
||||||
filename: filename,
|
|
||||||
fileExtension: pathURL.pathExtension
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
|
||||||
enum FontPlistGenerator {
|
class FontPlistGenerator {
|
||||||
|
|
||||||
static func generatePlistUIAppsFontContent(for fonts: [FontName], infoPlistPaths: [String]) -> String {
|
static func generatePlistUIAppsFontContent(for fonts: [FontName], infoPlistPaths: [String]) -> String {
|
||||||
let fontsToAddToPlist = fonts
|
let fontsToAddToPlist = fonts
|
||||||
.compactMap { $0 }
|
.compactMap { $0 }
|
||||||
@ -17,32 +16,26 @@ enum FontPlistGenerator {
|
|||||||
// Update each plist
|
// Update each plist
|
||||||
infoPlistPaths.forEach { infoPlist in
|
infoPlistPaths.forEach { infoPlist in
|
||||||
// Remove UIAppFonts value
|
// Remove UIAppFonts value
|
||||||
Shell.shell(
|
Shell.shell(launchPath: "/usr/libexec/PlistBuddy",
|
||||||
launchPath: "/usr/libexec/PlistBuddy",
|
["-c", "delete :UIAppFonts", infoPlist])
|
||||||
["-c", "delete :UIAppFonts", infoPlist]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Add UIAppFonts empty array
|
// Add UIAppFonts empty array
|
||||||
debugPrint("Will PlistBuddy -c add :UIAppFonts array \(infoPlist)")
|
debugPrint("Will PlistBuddy -c add :UIAppFonts array \(infoPlist)")
|
||||||
Shell.shell(
|
Shell.shell(launchPath: "/usr/libexec/PlistBuddy",
|
||||||
launchPath: "/usr/libexec/PlistBuddy",
|
["-c", "add :UIAppFonts array", infoPlist])
|
||||||
["-c", "add :UIAppFonts array", infoPlist]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Fill array with fonts
|
// Fill array with fonts
|
||||||
fontsToAddToPlist
|
fontsToAddToPlist
|
||||||
.forEach { fontName in
|
.forEach {
|
||||||
Shell.shell(
|
Shell.shell(launchPath: "/usr/libexec/PlistBuddy",
|
||||||
launchPath: "/usr/libexec/PlistBuddy",
|
["-c", "add :UIAppFonts: string \($0)", infoPlist])
|
||||||
["-c", "add :UIAppFonts: string \(fontName.filename).\(fontName.fileExtension)", infoPlist]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var plistData = "<key>UIAppFonts</key>\n\t<array>\n"
|
var plistData = "<key>UIAppFonts</key>\n\t<array>\n"
|
||||||
fontsToAddToPlist
|
fontsToAddToPlist
|
||||||
.forEach { fontName in
|
.forEach {
|
||||||
plistData += "\t\t<string>\(fontName.filename).\(fontName.fileExtension)</string>\n"
|
plistData += "\t\t<string>\($0)</string>\n"
|
||||||
}
|
}
|
||||||
plistData += "\t</array>"
|
plistData += "\t</array>"
|
||||||
|
|
||||||
|
@ -8,51 +8,45 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
|
||||||
enum FontExtensionGenerator {
|
class FontExtensionGenerator {
|
||||||
|
|
||||||
private static func getFontNameEnum(fontsNames: [FontName]) -> String {
|
private static func getFontNameEnum(fontsNames: [String]) -> String {
|
||||||
var enumDefinition = " enum FontName: String {\n"
|
var enumDefinition = " enum FontName: String {\n"
|
||||||
|
|
||||||
fontsNames.forEach {
|
fontsNames.forEach {
|
||||||
enumDefinition += " case \($0.fontNameSanitize) = \"\($0.postscriptName)\"\n"
|
enumDefinition += " case \($0.fontNameSanitize) = \"\($0)\"\n"
|
||||||
}
|
}
|
||||||
enumDefinition += " }\n"
|
enumDefinition += " }\n"
|
||||||
|
|
||||||
return enumDefinition
|
return enumDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
static func writeExtensionFile(
|
static func writeExtensionFile(fontsNames: [String],
|
||||||
fontsNames: [FontName],
|
staticVar: Bool,
|
||||||
staticVar: Bool,
|
extensionName: String,
|
||||||
extensionName: String,
|
extensionFilePath: String,
|
||||||
extensionFilePath: String,
|
isSwiftUI: Bool) {
|
||||||
isSwiftUI: Bool
|
|
||||||
) {
|
|
||||||
// Create extension content
|
// Create extension content
|
||||||
let extensionContent = Self.getExtensionContent(
|
let extensionContent = Self.getExtensionContent(fontsNames: fontsNames,
|
||||||
fontsNames: fontsNames,
|
staticVar: staticVar,
|
||||||
staticVar: staticVar,
|
extensionName: extensionName,
|
||||||
extensionName: extensionName,
|
isSwiftUI: isSwiftUI)
|
||||||
isSwiftUI: isSwiftUI
|
|
||||||
)
|
|
||||||
|
|
||||||
// Write content
|
// Write content
|
||||||
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
||||||
do {
|
do {
|
||||||
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch {
|
} catch let error {
|
||||||
let error = FontsToolError.writeExtension(extensionFilePath, error.localizedDescription)
|
let error = FontsToolError.writeExtension(extensionFilePath, error.localizedDescription)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Fonts.exit(withError: error)
|
Fonts.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getExtensionContent(
|
static func getExtensionContent(fontsNames: [String],
|
||||||
fontsNames: [FontName],
|
staticVar: Bool,
|
||||||
staticVar: Bool,
|
extensionName: String,
|
||||||
extensionName: String,
|
isSwiftUI: Bool) -> String {
|
||||||
isSwiftUI: Bool
|
|
||||||
) -> String {
|
|
||||||
[
|
[
|
||||||
Self.getHeader(extensionClassname: extensionName, isSwiftUI: isSwiftUI),
|
Self.getHeader(extensionClassname: extensionName, isSwiftUI: isSwiftUI),
|
||||||
Self.getFontNameEnum(fontsNames: fontsNames),
|
Self.getFontNameEnum(fontsNames: fontsNames),
|
||||||
|
@ -7,19 +7,11 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
// swiftlint:disable no_grouping_extension
|
typealias FontName = String
|
||||||
|
|
||||||
struct FontName: Hashable {
|
|
||||||
|
|
||||||
let postscriptName: String
|
|
||||||
let filename: String
|
|
||||||
let fileExtension: String
|
|
||||||
}
|
|
||||||
|
|
||||||
extension FontName {
|
extension FontName {
|
||||||
|
|
||||||
var fontNameSanitize: String {
|
var fontNameSanitize: String {
|
||||||
postscriptName.removeCharacters(from: "[]+-_")
|
self.removeCharacters(from: "[]+-_")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getProperty(isStatic: Bool, isSwiftUI: Bool) -> String {
|
func getProperty(isStatic: Bool, isSwiftUI: Bool) -> String {
|
||||||
|
@ -7,13 +7,10 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum FontFileParser {
|
class FontFileParser {
|
||||||
|
|
||||||
static func parse(_ inputFile: String) -> [String] {
|
static func parse(_ inputFile: String) -> [String] {
|
||||||
let inputFileContent = try! String( // swiftlint:disable:this force_try
|
let inputFileContent = try! String(contentsOfFile: inputFile,
|
||||||
contentsOfFile: inputFile,
|
encoding: .utf8)
|
||||||
encoding: .utf8
|
|
||||||
)
|
|
||||||
return inputFileContent.components(separatedBy: CharacterSet.newlines)
|
return inputFileContent.components(separatedBy: CharacterSet.newlines)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
// Created by Thibaut Schmitt on 30/08/2022.
|
// Created by Thibaut Schmitt on 30/08/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
struct Generate: ParsableCommand {
|
struct Generate: ParsableCommand {
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ struct Generate: ParsableCommand {
|
|||||||
|
|
||||||
// MARK: - Run
|
// MARK: - Run
|
||||||
|
|
||||||
func run() throws {
|
public func run() throws {
|
||||||
print("[\(Self.toolName)] Starting Resgen with configuration: \(options.configurationFile)")
|
print("[\(Self.toolName)] Starting Resgen with configuration: \(options.configurationFile)")
|
||||||
|
|
||||||
// Parse
|
// Parse
|
||||||
@ -43,20 +43,16 @@ struct Generate: ParsableCommand {
|
|||||||
print()
|
print()
|
||||||
|
|
||||||
if let architecture = configuration.architecture {
|
if let architecture = configuration.architecture {
|
||||||
ArchitectureGenerator.writeArchitecture(
|
ArchitectureGenerator.writeArchitecture(architecture,
|
||||||
architecture,
|
projectDirectory: options.projectDirectory)
|
||||||
projectDirectory: options.projectDirectory
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute commands
|
// Execute commands
|
||||||
configuration.runnableConfigurations
|
configuration.runnableConfigurations
|
||||||
.forEach {
|
.forEach {
|
||||||
let begin = Date()
|
let begin = Date()
|
||||||
$0.run(
|
$0.run(projectDirectory: options.projectDirectory,
|
||||||
projectDirectory: options.projectDirectory,
|
force: options.forceGeneration)
|
||||||
force: options.forceGeneration
|
|
||||||
)
|
|
||||||
print("Took: \(Date().timeIntervalSince(begin))s\n")
|
print("Took: \(Date().timeIntervalSince(begin))s\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum GenerateError: Error {
|
enum GenerateError: Error {
|
||||||
|
|
||||||
case fileNotExists(String)
|
case fileNotExists(String)
|
||||||
case invalidConfigurationFile(String, String)
|
case invalidConfigurationFile(String, String)
|
||||||
case commandError([String], String)
|
case commandError([String], String)
|
||||||
@ -19,15 +18,16 @@ enum GenerateError: Error {
|
|||||||
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 let .invalidConfigurationFile(filename, underneathErrorDescription):
|
case .invalidConfigurationFile(let filename, let underneathErrorDescription):
|
||||||
return "error: [\(Generate.toolName)] File \(filename) is not a valid configuration file. Underneath error: \(underneathErrorDescription)"
|
return "error: [\(Generate.toolName)] File \(filename) is not a valid configuration file. Underneath error: \(underneathErrorDescription)"
|
||||||
|
|
||||||
case let .commandError(command, terminationStatus):
|
case .commandError(let command, let terminationStatus):
|
||||||
let readableCommand = command
|
let readableCommand = command
|
||||||
|
.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 let .writeFile(filename, info):
|
case .writeFile(let filename, let info):
|
||||||
return "error: [\(Generate.toolName)] An error occured while writing file in \(filename): \(info)"
|
return "error: [\(Generate.toolName)] An error occured while writing file in \(filename): \(info)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,10 @@
|
|||||||
// Created by Thibaut Schmitt on 30/08/2022.
|
// Created by Thibaut Schmitt on 30/08/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
struct GenerateOptions: ParsableArguments {
|
struct GenerateOptions: ParsableArguments {
|
||||||
|
|
||||||
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
||||||
var forceGeneration = false
|
var forceGeneration = false
|
||||||
|
|
||||||
|
@ -5,11 +5,10 @@
|
|||||||
// Created by Thibaut Schmitt on 18/11/2022.
|
// Created by Thibaut Schmitt on 18/11/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
|
||||||
enum ArchitectureGenerator {
|
struct ArchitectureGenerator {
|
||||||
|
|
||||||
static func writeArchitecture(_ architecture: ConfigurationArchitecture, projectDirectory: String) {
|
static func writeArchitecture(_ architecture: ConfigurationArchitecture, projectDirectory: String) {
|
||||||
// Create extension content
|
// Create extension content
|
||||||
var architectureContent = [
|
var architectureContent = [
|
||||||
@ -31,7 +30,7 @@ enum ArchitectureGenerator {
|
|||||||
let architectureFilePathURL = URL(fileURLWithPath: "\(filePath)/\(filename)")
|
let architectureFilePathURL = URL(fileURLWithPath: "\(filePath)/\(filename)")
|
||||||
do {
|
do {
|
||||||
try architectureContent.write(to: architectureFilePathURL, atomically: false, encoding: .utf8)
|
try architectureContent.write(to: architectureFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch {
|
} catch let error {
|
||||||
let error = GenerateError.writeFile(filename, error.localizedDescription)
|
let error = GenerateError.writeFile(filename, error.localizedDescription)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Generate.exit(withError: error)
|
Generate.exit(withError: error)
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct ConfigurationFile: Codable, CustomDebugStringConvertible {
|
struct ConfigurationFile: Codable, CustomDebugStringConvertible {
|
||||||
|
|
||||||
var architecture: ConfigurationArchitecture?
|
var architecture: ConfigurationArchitecture?
|
||||||
var analytics: [AnalyticsConfiguration]
|
var analytics: [AnalyticsConfiguration]
|
||||||
var colors: [ColorsConfiguration]
|
var colors: [ColorsConfiguration]
|
||||||
@ -45,11 +44,10 @@ struct ConfigurationFile: Codable, CustomDebugStringConvertible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ConfigurationArchitecture: Codable {
|
struct ConfigurationArchitecture: Codable {
|
||||||
|
|
||||||
let property: String
|
let property: String
|
||||||
let classname: String
|
let classname: String
|
||||||
let path: String?
|
let path: String?
|
||||||
let children: [Self]?
|
let children: [ConfigurationArchitecture]?
|
||||||
|
|
||||||
func getProperty(isStatic: Bool) -> String {
|
func getProperty(isStatic: Bool) -> String {
|
||||||
" \(isStatic ? "static " : "")let \(property) = \(classname)()"
|
" \(isStatic ? "static " : "")let \(property) = \(classname)()"
|
||||||
@ -83,7 +81,6 @@ struct ConfigurationArchitecture: Codable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct AnalyticsConfiguration: Codable, CustomDebugStringConvertible {
|
struct AnalyticsConfiguration: Codable, CustomDebugStringConvertible {
|
||||||
|
|
||||||
let inputFile: String
|
let inputFile: String
|
||||||
let target: String
|
let target: String
|
||||||
let extensionOutputPath: String
|
let extensionOutputPath: String
|
||||||
@ -92,20 +89,18 @@ struct AnalyticsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
private let staticMembers: Bool?
|
private let staticMembers: Bool?
|
||||||
|
|
||||||
var staticMembersOptions: Bool {
|
var staticMembersOptions: Bool {
|
||||||
if let staticMembers {
|
if let staticMembers = staticMembers {
|
||||||
return staticMembers
|
return staticMembers
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
internal init(
|
internal init(inputFile: String,
|
||||||
inputFile: String,
|
target: String,
|
||||||
target: String,
|
extensionOutputPath: String,
|
||||||
extensionOutputPath: String,
|
extensionName: String?,
|
||||||
extensionName: String?,
|
extensionSuffix: String?,
|
||||||
extensionSuffix: String?,
|
staticMembers: Bool?) {
|
||||||
staticMembers: Bool?
|
|
||||||
) {
|
|
||||||
self.inputFile = inputFile
|
self.inputFile = inputFile
|
||||||
self.target = target
|
self.target = target
|
||||||
self.extensionOutputPath = extensionOutputPath
|
self.extensionOutputPath = extensionOutputPath
|
||||||
@ -127,7 +122,6 @@ struct AnalyticsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
|
struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
|
||||||
|
|
||||||
let inputFile: String
|
let inputFile: String
|
||||||
let style: String
|
let style: String
|
||||||
let xcassetsPath: String
|
let xcassetsPath: String
|
||||||
@ -138,22 +132,20 @@ struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
private let staticMembers: Bool?
|
private let staticMembers: Bool?
|
||||||
|
|
||||||
var staticMembersOptions: Bool {
|
var staticMembersOptions: Bool {
|
||||||
if let staticMembers {
|
if let staticMembers = staticMembers {
|
||||||
return staticMembers
|
return staticMembers
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
internal init(
|
internal init(inputFile: String,
|
||||||
inputFile: String,
|
style: String,
|
||||||
style: String,
|
xcassetsPath: String,
|
||||||
xcassetsPath: String,
|
extensionOutputPath: String,
|
||||||
extensionOutputPath: String,
|
extensionName: String?,
|
||||||
extensionName: String?,
|
extensionNameUIKit: String?,
|
||||||
extensionNameUIKit: String?,
|
extensionSuffix: String?,
|
||||||
extensionSuffix: String?,
|
staticMembers: Bool?) {
|
||||||
staticMembers: Bool?
|
|
||||||
) {
|
|
||||||
self.inputFile = inputFile
|
self.inputFile = inputFile
|
||||||
self.style = style
|
self.style = style
|
||||||
self.xcassetsPath = xcassetsPath
|
self.xcassetsPath = xcassetsPath
|
||||||
@ -179,7 +171,6 @@ struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct FontsConfiguration: Codable, CustomDebugStringConvertible {
|
struct FontsConfiguration: Codable, CustomDebugStringConvertible {
|
||||||
|
|
||||||
let inputFile: String
|
let inputFile: String
|
||||||
let extensionOutputPath: String
|
let extensionOutputPath: String
|
||||||
let extensionName: String?
|
let extensionName: String?
|
||||||
@ -189,21 +180,19 @@ struct FontsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
private let staticMembers: Bool?
|
private let staticMembers: Bool?
|
||||||
|
|
||||||
var staticMembersOptions: Bool {
|
var staticMembersOptions: Bool {
|
||||||
if let staticMembers {
|
if let staticMembers = staticMembers {
|
||||||
return staticMembers
|
return staticMembers
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
internal init(
|
internal init(inputFile: String,
|
||||||
inputFile: String,
|
extensionOutputPath: String,
|
||||||
extensionOutputPath: String,
|
extensionName: String?,
|
||||||
extensionName: String?,
|
extensionNameUIKit: String?,
|
||||||
extensionNameUIKit: String?,
|
extensionSuffix: String?,
|
||||||
extensionSuffix: String?,
|
infoPlistPaths: String?,
|
||||||
infoPlistPaths: String?,
|
staticMembers: Bool?) {
|
||||||
staticMembers: Bool?
|
|
||||||
) {
|
|
||||||
self.inputFile = inputFile
|
self.inputFile = inputFile
|
||||||
self.extensionOutputPath = extensionOutputPath
|
self.extensionOutputPath = extensionOutputPath
|
||||||
self.extensionName = extensionName
|
self.extensionName = extensionName
|
||||||
@ -227,7 +216,6 @@ struct FontsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ImagesConfiguration: Codable, CustomDebugStringConvertible {
|
struct ImagesConfiguration: Codable, CustomDebugStringConvertible {
|
||||||
|
|
||||||
let inputFile: String
|
let inputFile: String
|
||||||
let xcassetsPath: String
|
let xcassetsPath: String
|
||||||
let extensionOutputPath: String
|
let extensionOutputPath: String
|
||||||
@ -237,21 +225,19 @@ struct ImagesConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
private let staticMembers: Bool?
|
private let staticMembers: Bool?
|
||||||
|
|
||||||
var staticMembersOptions: Bool {
|
var staticMembersOptions: Bool {
|
||||||
if let staticMembers {
|
if let staticMembers = staticMembers {
|
||||||
return staticMembers
|
return staticMembers
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
internal init(
|
internal init(inputFile: String,
|
||||||
inputFile: String,
|
xcassetsPath: String,
|
||||||
xcassetsPath: String,
|
extensionOutputPath: String,
|
||||||
extensionOutputPath: String,
|
extensionName: String?,
|
||||||
extensionName: String?,
|
extensionNameUIKit: String?,
|
||||||
extensionNameUIKit: String?,
|
extensionSuffix: String?,
|
||||||
extensionSuffix: String?,
|
staticMembers: Bool?) {
|
||||||
staticMembers: Bool?
|
|
||||||
) {
|
|
||||||
self.inputFile = inputFile
|
self.inputFile = inputFile
|
||||||
self.xcassetsPath = xcassetsPath
|
self.xcassetsPath = xcassetsPath
|
||||||
self.extensionOutputPath = extensionOutputPath
|
self.extensionOutputPath = extensionOutputPath
|
||||||
@ -275,7 +261,6 @@ struct ImagesConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct StringsConfiguration: Codable, CustomDebugStringConvertible {
|
struct StringsConfiguration: Codable, CustomDebugStringConvertible {
|
||||||
|
|
||||||
let inputFile: String
|
let inputFile: String
|
||||||
let outputPath: String
|
let outputPath: String
|
||||||
let langs: String
|
let langs: String
|
||||||
@ -287,30 +272,28 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
private let xcStrings: Bool?
|
private let xcStrings: Bool?
|
||||||
|
|
||||||
var staticMembersOptions: Bool {
|
var staticMembersOptions: Bool {
|
||||||
if let staticMembers {
|
if let staticMembers = staticMembers {
|
||||||
return staticMembers
|
return staticMembers
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var xcStringsOptions: Bool {
|
var xcStringsOptions: Bool {
|
||||||
if let xcStrings {
|
if let xcStrings = xcStrings {
|
||||||
return xcStrings
|
return xcStrings
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
internal init(
|
internal init(inputFile: String,
|
||||||
inputFile: String,
|
outputPath: String,
|
||||||
outputPath: String,
|
langs: String,
|
||||||
langs: String,
|
defaultLang: String,
|
||||||
defaultLang: String,
|
extensionOutputPath: String,
|
||||||
extensionOutputPath: String,
|
extensionName: String?,
|
||||||
extensionName: String?,
|
extensionSuffix: String?,
|
||||||
extensionSuffix: String?,
|
staticMembers: Bool?,
|
||||||
staticMembers: Bool?,
|
xcStrings: Bool?) {
|
||||||
xcStrings: Bool?
|
|
||||||
) {
|
|
||||||
self.inputFile = inputFile
|
self.inputFile = inputFile
|
||||||
self.outputPath = outputPath
|
self.outputPath = outputPath
|
||||||
self.langs = langs
|
self.langs = langs
|
||||||
@ -337,7 +320,6 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct TagsConfiguration: Codable, CustomDebugStringConvertible {
|
struct TagsConfiguration: Codable, CustomDebugStringConvertible {
|
||||||
|
|
||||||
let inputFile: String
|
let inputFile: String
|
||||||
let lang: String
|
let lang: String
|
||||||
let extensionOutputPath: String
|
let extensionOutputPath: String
|
||||||
@ -346,20 +328,18 @@ struct TagsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
private let staticMembers: Bool?
|
private let staticMembers: Bool?
|
||||||
|
|
||||||
var staticMembersOptions: Bool {
|
var staticMembersOptions: Bool {
|
||||||
if let staticMembers {
|
if let staticMembers = staticMembers {
|
||||||
return staticMembers
|
return staticMembers
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
internal init(
|
internal init(inputFile: String,
|
||||||
inputFile: String,
|
lang: String,
|
||||||
lang: String,
|
extensionOutputPath: String,
|
||||||
extensionOutputPath: String,
|
extensionName: String?,
|
||||||
extensionName: String?,
|
extensionSuffix: String?,
|
||||||
extensionSuffix: String?,
|
staticMembers: Bool?) {
|
||||||
staticMembers: Bool?
|
|
||||||
) {
|
|
||||||
self.inputFile = inputFile
|
self.inputFile = inputFile
|
||||||
self.lang = lang
|
self.lang = lang
|
||||||
self.extensionOutputPath = extensionOutputPath
|
self.extensionOutputPath = extensionOutputPath
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import Yams
|
import Yams
|
||||||
|
|
||||||
enum ConfigurationFileParser {
|
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)
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension AnalyticsConfiguration: Runnable {
|
extension AnalyticsConfiguration: Runnable {
|
||||||
|
|
||||||
func run(projectDirectory: String, force: Bool) {
|
func run(projectDirectory: String, force: Bool) {
|
||||||
var args = [String]()
|
var args = [String]()
|
||||||
|
|
||||||
@ -26,13 +25,13 @@ extension AnalyticsConfiguration: Runnable {
|
|||||||
"\(staticMembersOptions)"
|
"\(staticMembersOptions)"
|
||||||
]
|
]
|
||||||
|
|
||||||
if let extensionName {
|
if let extensionName = extensionName {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name",
|
"--extension-name",
|
||||||
extensionName
|
extensionName
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if let extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
args += [
|
args += [
|
||||||
"--extension-suffix",
|
"--extension-suffix",
|
||||||
extensionSuffix
|
extensionSuffix
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension ColorsConfiguration: Runnable {
|
extension ColorsConfiguration: Runnable {
|
||||||
|
|
||||||
func run(projectDirectory: String, force: Bool) {
|
func run(projectDirectory: String, force: Bool) {
|
||||||
let args = getArguments(projectDirectory: projectDirectory, force: force)
|
let args = getArguments(projectDirectory: projectDirectory, force: force)
|
||||||
Colors.main(args)
|
Colors.main(args)
|
||||||
@ -33,19 +32,19 @@ extension ColorsConfiguration: Runnable {
|
|||||||
"\(staticMembersOptions)"
|
"\(staticMembersOptions)"
|
||||||
]
|
]
|
||||||
|
|
||||||
if let extensionName {
|
if let extensionName = extensionName {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name",
|
"--extension-name",
|
||||||
extensionName
|
extensionName
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if let extensionNameUIKit {
|
if let extensionNameUIKit = extensionNameUIKit {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name-ui-kit",
|
"--extension-name-ui-kit",
|
||||||
extensionNameUIKit
|
extensionNameUIKit
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if let extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
args += [
|
args += [
|
||||||
"--extension-suffix",
|
"--extension-suffix",
|
||||||
extensionSuffix
|
extensionSuffix
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension FontsConfiguration: Runnable {
|
extension FontsConfiguration: Runnable {
|
||||||
|
|
||||||
func run(projectDirectory: String, force: Bool) {
|
func run(projectDirectory: String, force: Bool) {
|
||||||
let args = getArguments(projectDirectory: projectDirectory, force: force)
|
let args = getArguments(projectDirectory: projectDirectory, force: force)
|
||||||
Fonts.main(args)
|
Fonts.main(args)
|
||||||
@ -29,27 +28,27 @@ extension FontsConfiguration: Runnable {
|
|||||||
"\(staticMembersOptions)"
|
"\(staticMembersOptions)"
|
||||||
]
|
]
|
||||||
|
|
||||||
if let extensionName {
|
if let extensionName = extensionName {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name",
|
"--extension-name",
|
||||||
extensionName
|
extensionName
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if let extensionNameUIKit {
|
if let extensionNameUIKit = extensionNameUIKit {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name-ui-kit",
|
"--extension-name-ui-kit",
|
||||||
extensionNameUIKit
|
extensionNameUIKit
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
if let extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
args += [
|
args += [
|
||||||
"--extension-suffix",
|
"--extension-suffix",
|
||||||
extensionSuffix
|
extensionSuffix
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
if let infoPlistPaths {
|
if let infoPlistPaths = infoPlistPaths {
|
||||||
let adjustedPlistPaths = infoPlistPaths
|
let adjustedPlistPaths = infoPlistPaths
|
||||||
.split(separator: " ")
|
.split(separator: " ")
|
||||||
.map { String($0).prependIfRelativePath(projectDirectory) }
|
.map { String($0).prependIfRelativePath(projectDirectory) }
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension ImagesConfiguration: Runnable {
|
extension ImagesConfiguration: Runnable {
|
||||||
|
|
||||||
func run(projectDirectory: String, force: Bool) {
|
func run(projectDirectory: String, force: Bool) {
|
||||||
let args = getArguments(projectDirectory: projectDirectory, force: force)
|
let args = getArguments(projectDirectory: projectDirectory, force: force)
|
||||||
Images.main(args)
|
Images.main(args)
|
||||||
@ -31,21 +30,19 @@ extension ImagesConfiguration: Runnable {
|
|||||||
"\(staticMembersOptions)"
|
"\(staticMembersOptions)"
|
||||||
]
|
]
|
||||||
|
|
||||||
if let extensionName {
|
if let extensionName = extensionName {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name",
|
"--extension-name",
|
||||||
extensionName
|
extensionName
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
if let extensionNameUIKit = extensionNameUIKit {
|
||||||
if let extensionNameUIKit {
|
|
||||||
args += [
|
args += [
|
||||||
"--extension-name-ui-kit",
|
"--extension-name-ui-kit",
|
||||||
extensionNameUIKit
|
extensionNameUIKit
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
if let extensionSuffix = extensionSuffix {
|
||||||
if let extensionSuffix {
|
|
||||||
args += [
|
args += [
|
||||||
"--extension-suffix",
|
"--extension-suffix",
|
||||||
extensionSuffix
|
extensionSuffix
|
||||||
|
@ -8,6 +8,5 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol Runnable {
|
protocol Runnable {
|
||||||
|
|
||||||
func run(projectDirectory: String, force: Bool)
|
func run(projectDirectory: String, force: Bool)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension StringsConfiguration: Runnable {
|
extension StringsConfiguration: Runnable {
|
||||||
|
|
||||||
func run(projectDirectory: String, force: Bool) {
|
func run(projectDirectory: String, force: Bool) {
|
||||||
var args = [String]()
|
var args = [String]()
|
||||||
|
|
||||||
@ -32,14 +31,14 @@ extension StringsConfiguration: Runnable {
|
|||||||
"\(xcStringsOptions)"
|
"\(xcStringsOptions)"
|
||||||
]
|
]
|
||||||
|
|
||||||
if let extensionName {
|
if let extensionName = extensionName {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name",
|
"--extension-name",
|
||||||
extensionName
|
extensionName
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
if let extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
args += [
|
args += [
|
||||||
"--extension-suffix",
|
"--extension-suffix",
|
||||||
extensionSuffix
|
extensionSuffix
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension TagsConfiguration: Runnable {
|
extension TagsConfiguration: Runnable {
|
||||||
|
|
||||||
func run(projectDirectory: String, force: Bool) {
|
func run(projectDirectory: String, force: Bool) {
|
||||||
var args = [String]()
|
var args = [String]()
|
||||||
|
|
||||||
@ -26,13 +25,13 @@ extension TagsConfiguration: Runnable {
|
|||||||
"\(staticMembersOptions)"
|
"\(staticMembersOptions)"
|
||||||
]
|
]
|
||||||
|
|
||||||
if let extensionName {
|
if let extensionName = extensionName {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name",
|
"--extension-name",
|
||||||
extensionName
|
extensionName
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if let extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
args += [
|
args += [
|
||||||
"--extension-suffix",
|
"--extension-suffix",
|
||||||
extensionSuffix
|
extensionSuffix
|
||||||
|
@ -7,10 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
// swiftlint:disable force_unwrapping
|
|
||||||
|
|
||||||
extension FileManager {
|
extension FileManager {
|
||||||
|
|
||||||
func getAllRegularFileIn(directory: String) -> [String] {
|
func getAllRegularFileIn(directory: String) -> [String] {
|
||||||
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 {
|
||||||
|
@ -5,48 +5,42 @@
|
|||||||
// Created by Thibaut Schmitt on 14/02/2022.
|
// Created by Thibaut Schmitt on 14/02/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
|
||||||
enum ImageExtensionGenerator {
|
class ImageExtensionGenerator {
|
||||||
|
|
||||||
// MARK: - UIKit
|
// MARK: - UIKit
|
||||||
|
|
||||||
static func generateExtensionFile(
|
static func generateExtensionFile(images: [ParsedImage],
|
||||||
images: [ParsedImage],
|
staticVar: Bool,
|
||||||
staticVar: Bool,
|
inputFilename: String,
|
||||||
inputFilename: String,
|
extensionName: String,
|
||||||
extensionName: String,
|
extensionFilePath: String,
|
||||||
extensionFilePath: String,
|
isSwiftUI: Bool) {
|
||||||
isSwiftUI: Bool
|
|
||||||
) {
|
|
||||||
// Create extension conten1t
|
// Create extension conten1t
|
||||||
let extensionContent = Self.getExtensionContent(
|
let extensionContent = Self.getExtensionContent(images: images,
|
||||||
images: images,
|
staticVar: staticVar,
|
||||||
staticVar: staticVar,
|
extensionName: extensionName,
|
||||||
extensionName: extensionName,
|
inputFilename: inputFilename,
|
||||||
inputFilename: inputFilename,
|
isSwiftUI: isSwiftUI)
|
||||||
isSwiftUI: isSwiftUI
|
|
||||||
)
|
|
||||||
|
|
||||||
// Write content
|
// Write content
|
||||||
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
||||||
do {
|
do {
|
||||||
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch {
|
} catch let error {
|
||||||
let error = ImagesError.writeFile(extensionFilePath, error.localizedDescription)
|
let error = ImagesError.writeFile(extensionFilePath, error.localizedDescription)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getExtensionContent(
|
static func getExtensionContent(images: [ParsedImage],
|
||||||
images: [ParsedImage],
|
staticVar: Bool,
|
||||||
staticVar: Bool,
|
extensionName: String,
|
||||||
extensionName: String,
|
inputFilename: String,
|
||||||
inputFilename: String,
|
isSwiftUI: Bool) -> String {
|
||||||
isSwiftUI: Bool
|
|
||||||
) -> String {
|
|
||||||
[
|
[
|
||||||
Self.getHeader(inputFilename: inputFilename, extensionClassname: extensionName, isSwiftUI: isSwiftUI),
|
Self.getHeader(inputFilename: inputFilename, extensionClassname: extensionName, isSwiftUI: isSwiftUI),
|
||||||
Self.getProperties(images: images, staticVar: staticVar, isSwiftUI: isSwiftUI),
|
Self.getProperties(images: images, staticVar: staticVar, isSwiftUI: isSwiftUI),
|
||||||
@ -55,11 +49,9 @@ enum ImageExtensionGenerator {
|
|||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getHeader(
|
private static func getHeader(inputFilename: String,
|
||||||
inputFilename: String,
|
extensionClassname: String,
|
||||||
extensionClassname: String,
|
isSwiftUI: Bool) -> String {
|
||||||
isSwiftUI: Bool
|
|
||||||
) -> String {
|
|
||||||
"""
|
"""
|
||||||
// Generated by ResgenSwift.\(Images.toolName) \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.\(Images.toolName) \(ResgenSwiftVersion)
|
||||||
// Images from \(inputFilename)
|
// Images from \(inputFilename)
|
||||||
@ -70,11 +62,7 @@ enum ImageExtensionGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getProperties(
|
private static func getProperties(images: [ParsedImage], staticVar: Bool, isSwiftUI: Bool) -> String {
|
||||||
images: [ParsedImage],
|
|
||||||
staticVar: Bool,
|
|
||||||
isSwiftUI: Bool
|
|
||||||
) -> String {
|
|
||||||
images
|
images
|
||||||
.map { "\n\($0.getImageProperty(isStatic: staticVar, isSwiftUI: isSwiftUI))" }
|
.map { "\n\($0.getImageProperty(isStatic: staticVar, isSwiftUI: isSwiftUI))" }
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
|
@ -9,15 +9,12 @@ import Foundation
|
|||||||
import ToolCore
|
import ToolCore
|
||||||
|
|
||||||
enum OutputImageExtension: String {
|
enum OutputImageExtension: String {
|
||||||
|
|
||||||
case png
|
case png
|
||||||
case svg
|
case svg
|
||||||
}
|
}
|
||||||
|
|
||||||
class XcassetsGenerator {
|
class XcassetsGenerator {
|
||||||
|
|
||||||
// MARK: - Properties
|
|
||||||
|
|
||||||
let forceGeneration: Bool
|
let forceGeneration: Bool
|
||||||
|
|
||||||
// MARK: - Init
|
// MARK: - Init
|
||||||
@ -36,7 +33,7 @@ class XcassetsGenerator {
|
|||||||
var generatedAssetsPaths = [String]()
|
var generatedAssetsPaths = [String]()
|
||||||
|
|
||||||
// Generate new assets
|
// Generate new assets
|
||||||
imagesToGenerate.forEach { parsedImage in // swiftlint:disable:this closure_body_length
|
imagesToGenerate.forEach { parsedImage in
|
||||||
// Get image path
|
// Get image path
|
||||||
let imageData: (path: String, ext: String) = {
|
let imageData: (path: String, ext: String) = {
|
||||||
for subfile in allSubFiles {
|
for subfile in allSubFiles {
|
||||||
@ -86,10 +83,8 @@ class XcassetsGenerator {
|
|||||||
// Create imageset folder
|
// Create imageset folder
|
||||||
if fileManager.fileExists(atPath: imagesetPath) == false {
|
if fileManager.fileExists(atPath: imagesetPath) == false {
|
||||||
do {
|
do {
|
||||||
try fileManager.createDirectory(
|
try fileManager.createDirectory(atPath: imagesetPath,
|
||||||
atPath: imagesetPath,
|
withIntermediateDirectories: true)
|
||||||
withIntermediateDirectories: true
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
let error = ImagesError.createAssetFolder(imagesetPath)
|
let error = ImagesError.createAssetFolder(imagesetPath)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
@ -129,7 +124,9 @@ class XcassetsGenerator {
|
|||||||
Shell.shell(command1x)
|
Shell.shell(command1x)
|
||||||
Shell.shell(command2x)
|
Shell.shell(command2x)
|
||||||
Shell.shell(command3x)
|
Shell.shell(command3x)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
let output = "\(imagesetPath)/\(parsedImage.name).\(OutputImageExtension.svg.rawValue)"
|
let output = "\(imagesetPath)/\(parsedImage.name).\(OutputImageExtension.svg.rawValue)"
|
||||||
let tempURL = URL(fileURLWithPath: output)
|
let tempURL = URL(fileURLWithPath: output)
|
||||||
|
|
||||||
@ -146,33 +143,15 @@ class XcassetsGenerator {
|
|||||||
// convert path/to/image.png -resize 200x300 path/to/output.png
|
// convert path/to/image.png -resize 200x300 path/to/output.png
|
||||||
// convert path/to/image.png -resize 200x path/to/output.png
|
// convert path/to/image.png -resize 200x path/to/output.png
|
||||||
// convert path/to/image.png -resize x300 path/to/output.png
|
// convert path/to/image.png -resize x300 path/to/output.png
|
||||||
Shell.shell(
|
Shell.shell(["convert", "\(imageData.path)",
|
||||||
[
|
"-resize", "\(convertArguments.x1.width ?? "")x\(convertArguments.x1.height ?? "")",
|
||||||
"convert",
|
output1x])
|
||||||
"\(imageData.path)",
|
Shell.shell(["convert", "\(imageData.path)",
|
||||||
"-resize",
|
"-resize", "\(convertArguments.x2.width ?? "")x\(convertArguments.x2.height ?? "")",
|
||||||
"\(convertArguments.x1.width ?? "")x\(convertArguments.x1.height ?? "")",
|
output2x])
|
||||||
output1x
|
Shell.shell(["convert", "\(imageData.path)",
|
||||||
]
|
"-resize", "\(convertArguments.x3.width ?? "")x\(convertArguments.x3.height ?? "")",
|
||||||
)
|
output3x])
|
||||||
Shell.shell(
|
|
||||||
[
|
|
||||||
"convert",
|
|
||||||
"\(imageData.path)",
|
|
||||||
"-resize",
|
|
||||||
"\(convertArguments.x2.width ?? "")x\(convertArguments.x2.height ?? "")",
|
|
||||||
output2x
|
|
||||||
]
|
|
||||||
)
|
|
||||||
Shell.shell(
|
|
||||||
[
|
|
||||||
"convert",
|
|
||||||
"\(imageData.path)",
|
|
||||||
"-resize",
|
|
||||||
"\(convertArguments.x3.width ?? "")x\(convertArguments.x3.height ?? "")",
|
|
||||||
output3x
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write Content.json
|
// Write Content.json
|
||||||
@ -180,11 +159,7 @@ class XcassetsGenerator {
|
|||||||
let contentJsonFilePath = "\(imagesetPath)/Contents.json"
|
let contentJsonFilePath = "\(imagesetPath)/Contents.json"
|
||||||
|
|
||||||
let contentJsonFilePathURL = URL(fileURLWithPath: contentJsonFilePath)
|
let contentJsonFilePathURL = URL(fileURLWithPath: contentJsonFilePath)
|
||||||
try! imagesetContentJson.write( // swiftlint:disable:this force_try
|
try! imagesetContentJson.write(to: contentJsonFilePathURL, atomically: false, encoding: .utf8)
|
||||||
to: contentJsonFilePathURL,
|
|
||||||
atomically: false,
|
|
||||||
encoding: .utf8
|
|
||||||
)
|
|
||||||
|
|
||||||
print("\(parsedImage.name) -> Generated")
|
print("\(parsedImage.name) -> Generated")
|
||||||
}
|
}
|
||||||
@ -202,7 +177,7 @@ class XcassetsGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
imagesetToRemove.forEach { itemToRemove in
|
imagesetToRemove.forEach { itemToRemove in
|
||||||
try! fileManager.removeItem(atPath: "\(xcassetsPath)/\(itemToRemove)") // swiftlint:disable:this force_try
|
try! fileManager.removeItem(atPath: "\(xcassetsPath)/\(itemToRemove)")
|
||||||
}
|
}
|
||||||
print("Removed \(imagesetToRemove.count) images")
|
print("Removed \(imagesetToRemove.count) images")
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
// Created by Thibaut Schmitt on 24/01/2022.
|
// Created by Thibaut Schmitt on 24/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
struct Images: ParsableCommand {
|
struct Images: ParsableCommand {
|
||||||
|
|
||||||
@ -48,30 +48,24 @@ struct Images: ParsableCommand {
|
|||||||
.relativePath
|
.relativePath
|
||||||
|
|
||||||
let xcassetsGenerator = XcassetsGenerator(forceGeneration: options.forceExecutionAndGeneration)
|
let xcassetsGenerator = XcassetsGenerator(forceGeneration: options.forceExecutionAndGeneration)
|
||||||
xcassetsGenerator.generateXcassets(
|
xcassetsGenerator.generateXcassets(inputPath: inputFolder,
|
||||||
inputPath: inputFolder,
|
imagesToGenerate: imagesToGenerate,
|
||||||
imagesToGenerate: imagesToGenerate,
|
xcassetsPath: options.xcassetsPath)
|
||||||
xcassetsPath: options.xcassetsPath
|
|
||||||
)
|
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
ImageExtensionGenerator.generateExtensionFile(
|
ImageExtensionGenerator.generateExtensionFile(images: imagesToGenerate,
|
||||||
images: imagesToGenerate,
|
staticVar: options.staticMembers,
|
||||||
staticVar: options.staticMembers,
|
inputFilename: options.inputFilenameWithoutExt,
|
||||||
inputFilename: options.inputFilenameWithoutExt,
|
extensionName: options.extensionName,
|
||||||
extensionName: options.extensionName,
|
extensionFilePath: options.extensionFilePath,
|
||||||
extensionFilePath: options.extensionFilePath,
|
isSwiftUI: true)
|
||||||
isSwiftUI: true
|
|
||||||
)
|
|
||||||
|
|
||||||
ImageExtensionGenerator.generateExtensionFile(
|
ImageExtensionGenerator.generateExtensionFile(images: imagesToGenerate,
|
||||||
images: imagesToGenerate,
|
staticVar: options.staticMembers,
|
||||||
staticVar: options.staticMembers,
|
inputFilename: options.inputFilenameWithoutExt,
|
||||||
inputFilename: options.inputFilenameWithoutExt,
|
extensionName: options.extensionNameUIKit,
|
||||||
extensionName: options.extensionNameUIKit,
|
extensionFilePath: options.extensionFilePathUIKit,
|
||||||
extensionFilePath: options.extensionFilePathUIKit,
|
isSwiftUI: false)
|
||||||
isSwiftUI: false
|
|
||||||
)
|
|
||||||
|
|
||||||
print("[\(Self.toolName)] Images generated")
|
print("[\(Self.toolName)] Images generated")
|
||||||
}
|
}
|
||||||
@ -89,25 +83,23 @@ struct Images: ParsableCommand {
|
|||||||
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.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RSVG-Converter
|
// RSVG-Converter
|
||||||
_ = Self.getSvgConverterPath()
|
_ = Images.getSvgConverterPath()
|
||||||
|
|
||||||
// Extension for UIKit and SwiftUI should have different name
|
// Extension for UIKit and SwiftUI should have different name
|
||||||
guard options.extensionName != options.extensionNameUIKit else {
|
guard options.extensionName != options.extensionNameUIKit else {
|
||||||
let error = ImagesError.extensionNamesCollision(options.extensionName)
|
let error = ImagesError.extensionNamesCollision(options.extensionName)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if needed to regenerate
|
// Check if needed to regenerate
|
||||||
guard GeneratorChecker.shouldGenerate(
|
guard GeneratorChecker.shouldGenerate(force: options.forceExecution,
|
||||||
force: options.forceExecution,
|
inputFilePath: options.inputFile,
|
||||||
inputFilePath: options.inputFile,
|
extensionFilePath: options.extensionFilePath) else {
|
||||||
extensionFilePath: options.extensionFilePath
|
|
||||||
) else {
|
|
||||||
print("[\(Self.toolName)] Images are already up to date :) ")
|
print("[\(Self.toolName)] Images are already up to date :) ")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -121,11 +113,11 @@ struct Images: ParsableCommand {
|
|||||||
static func getSvgConverterPath() -> String {
|
static func getSvgConverterPath() -> String {
|
||||||
let taskSvgConverter = Shell.shell(["which", "rsvg-convert"])
|
let taskSvgConverter = Shell.shell(["which", "rsvg-convert"])
|
||||||
if taskSvgConverter.terminationStatus == 0 {
|
if taskSvgConverter.terminationStatus == 0 {
|
||||||
return taskSvgConverter.output!.removeCharacters(from: CharacterSet.whitespacesAndNewlines) // swiftlint:disable:this force_unwrapping
|
return taskSvgConverter.output!.removeCharacters(from: CharacterSet.whitespacesAndNewlines)
|
||||||
}
|
}
|
||||||
|
|
||||||
let error = ImagesError.rsvgConvertNotFound
|
let error = ImagesError.rsvgConvertNotFound
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum ImagesError: Error {
|
enum ImagesError: Error {
|
||||||
|
|
||||||
case extensionNamesCollision(String)
|
case extensionNamesCollision(String)
|
||||||
case inputFolderNotFound(String)
|
case inputFolderNotFound(String)
|
||||||
case fileNotExists(String)
|
case fileNotExists(String)
|
||||||
@ -33,13 +32,13 @@ enum ImagesError: Error {
|
|||||||
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 let .getFileAttributed(filename, 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 librsvg')"
|
return "error: [\(Images.toolName)] Can't find rsvg-convert (can be installed with 'brew remove imagemagick && brew install librsvg')"
|
||||||
|
|
||||||
case let .writeFile(subErrorDescription, 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):
|
||||||
|
@ -5,13 +5,10 @@
|
|||||||
// Created by Thibaut Schmitt on 24/01/2022.
|
// Created by Thibaut Schmitt on 24/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
// swiftlint:disable no_grouping_extension
|
|
||||||
|
|
||||||
struct ImagesOptions: ParsableArguments {
|
struct ImagesOptions: ParsableArguments {
|
||||||
|
|
||||||
@Flag(name: .customShort("f"), help: "Should force script execution")
|
@Flag(name: .customShort("f"), help: "Should force script execution")
|
||||||
var forceExecution = false
|
var forceExecution = false
|
||||||
|
|
||||||
@ -47,7 +44,7 @@ extension ImagesOptions {
|
|||||||
// MARK: - SwiftUI
|
// MARK: - SwiftUI
|
||||||
|
|
||||||
var extensionFileName: String {
|
var extensionFileName: String {
|
||||||
if let extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
return "\(extensionName)+\(extensionSuffix).swift"
|
return "\(extensionName)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionName).swift"
|
return "\(extensionName).swift"
|
||||||
@ -60,7 +57,7 @@ extension ImagesOptions {
|
|||||||
// MARK: - UIKit
|
// MARK: - UIKit
|
||||||
|
|
||||||
var extensionFileNameUIKit: String {
|
var extensionFileNameUIKit: String {
|
||||||
if let extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionNameUIKit).swift"
|
return "\(extensionNameUIKit).swift"
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct ConvertArgument {
|
struct ConvertArgument {
|
||||||
|
|
||||||
let width: String?
|
let width: String?
|
||||||
let height: String?
|
let height: String?
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,11 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum TemplateRenderingIntent: String, Codable {
|
enum TemplateRenderingIntent: String, Codable {
|
||||||
|
|
||||||
case template
|
case template
|
||||||
case original
|
case original
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AssetContent: Codable, Equatable {
|
struct AssetContent: Codable, Equatable {
|
||||||
|
|
||||||
let images: [AssetImageDescription]
|
let images: [AssetImageDescription]
|
||||||
let info: AssetInfo
|
let info: AssetInfo
|
||||||
let properties: AssetProperties?
|
let properties: AssetProperties?
|
||||||
@ -29,17 +27,16 @@ struct AssetContent: Codable, Equatable {
|
|||||||
self.properties = properties
|
self.properties = properties
|
||||||
}
|
}
|
||||||
|
|
||||||
static func == (lhs: Self, rhs: Self) -> Bool {
|
static func == (lhs: AssetContent, rhs: AssetContent) -> Bool {
|
||||||
guard lhs.images.count == rhs.images.count else { return false }
|
guard lhs.images.count == rhs.images.count else { return false }
|
||||||
let lhsImages = lhs.images.sorted { $0.filename < $1.filename }
|
let lhsImages = lhs.images.sorted(by: { $0.filename < $1.filename })
|
||||||
let rhsImages = rhs.images.sorted { $0.filename < $1.filename }
|
let rhsImages = rhs.images.sorted(by: { $0.filename < $1.filename })
|
||||||
|
|
||||||
return lhsImages == rhsImages
|
return lhsImages == rhsImages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AssetImageDescription: Codable, Equatable {
|
struct AssetImageDescription: Codable, Equatable {
|
||||||
|
|
||||||
let idiom: String
|
let idiom: String
|
||||||
let scale: String?
|
let scale: String?
|
||||||
let filename: String
|
let filename: String
|
||||||
@ -56,13 +53,11 @@ struct AssetImageDescription: Codable, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct AssetInfo: Codable, Equatable {
|
struct AssetInfo: Codable, Equatable {
|
||||||
|
|
||||||
let version: Int
|
let version: Int
|
||||||
let author: String
|
let author: String
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AssetProperties: Codable, Equatable {
|
struct AssetProperties: Codable, Equatable {
|
||||||
|
|
||||||
let preservesVectorRepresentation: Bool
|
let preservesVectorRepresentation: Bool
|
||||||
let templateRenderingIntent: TemplateRenderingIntent?
|
let templateRenderingIntent: TemplateRenderingIntent?
|
||||||
|
|
||||||
@ -75,7 +70,6 @@ struct AssetProperties: Codable, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
|
|
||||||
case preservesVectorRepresentation = "preserves-vector-representation"
|
case preservesVectorRepresentation = "preserves-vector-representation"
|
||||||
case templateRenderingIntent = "template-rendering-intent"
|
case templateRenderingIntent = "template-rendering-intent"
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,10 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum ImageExtension: String {
|
enum ImageExtension: String {
|
||||||
|
|
||||||
case png
|
case png
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ParsedImage {
|
struct ParsedImage {
|
||||||
|
|
||||||
// MARK: - Properties
|
|
||||||
|
|
||||||
let name: String
|
let name: String
|
||||||
let tags: String
|
let tags: String
|
||||||
let width: Int
|
let width: Int
|
||||||
@ -38,7 +34,7 @@ struct ParsedImage {
|
|||||||
|
|
||||||
// MARK: - Convert
|
// MARK: - Convert
|
||||||
|
|
||||||
var convertArguments: (x1: ConvertArgument, x2: ConvertArgument, x3: ConvertArgument) { // swiftlint:disable:this large_tuple
|
var convertArguments: (x1: ConvertArgument, x2: ConvertArgument, x3: ConvertArgument) {
|
||||||
var width1x = ""
|
var width1x = ""
|
||||||
var height1x = ""
|
var height1x = ""
|
||||||
var width2x = ""
|
var width2x = ""
|
||||||
@ -81,8 +77,9 @@ struct ParsedImage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func generateImageContent(isVector: Bool) -> AssetContent {
|
func generateImageContent(isVector: Bool) -> AssetContent {
|
||||||
|
|
||||||
if !imageExtensions.contains(.png) && isVector {
|
if !imageExtensions.contains(.png) && isVector {
|
||||||
// Generate svg
|
//Generate svg
|
||||||
return AssetContent(
|
return AssetContent(
|
||||||
images: [
|
images: [
|
||||||
AssetImageDescription(
|
AssetImageDescription(
|
||||||
@ -100,7 +97,7 @@ struct ParsedImage {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// Generate png
|
//Generate png
|
||||||
return AssetContent(
|
return AssetContent(
|
||||||
images: [
|
images: [
|
||||||
AssetImageDescription(
|
AssetImageDescription(
|
||||||
@ -132,13 +129,13 @@ struct ParsedImage {
|
|||||||
func getImageProperty(isStatic: Bool, isSwiftUI: Bool) -> String {
|
func getImageProperty(isStatic: Bool, isSwiftUI: Bool) -> String {
|
||||||
if isSwiftUI {
|
if isSwiftUI {
|
||||||
return """
|
return """
|
||||||
\(isStatic ? "static " : "")var \(name): Image {
|
\(isStatic ? "static ": "")var \(name): Image {
|
||||||
Image("\(name)")
|
Image("\(name)")
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
return """
|
return """
|
||||||
\(isStatic ? "static " : "")var \(name): UIImage {
|
\(isStatic ? "static ": "")var \(name): UIImage {
|
||||||
UIImage(named: "\(name)")!
|
UIImage(named: "\(name)")!
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum PlatormTag: String {
|
enum PlatormTag: String {
|
||||||
|
|
||||||
case droid = "d"
|
case droid = "d"
|
||||||
case ios = "i"
|
case ios = "i"
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum ImageFileParser {
|
class ImageFileParser {
|
||||||
|
|
||||||
static func parse(_ inputFile: String, platform: PlatormTag) -> [ParsedImage] {
|
static func parse(_ inputFile: String, platform: PlatormTag) -> [ParsedImage] {
|
||||||
let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8) // swiftlint:disable:this force_try
|
let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8)
|
||||||
let stringsByLines = inputFileContent.components(separatedBy: .newlines)
|
let stringsByLines = inputFileContent.components(separatedBy: .newlines)
|
||||||
|
|
||||||
return Self.parseLines(stringsByLines, platform: platform)
|
return Self.parseLines(stringsByLines, platform: platform)
|
||||||
@ -30,13 +30,13 @@ enum ImageFileParser {
|
|||||||
if splittedLine[2] == "?" {
|
if splittedLine[2] == "?" {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return Int(splittedLine[2])! // swiftlint:disable:this force_unwrapping
|
return Int(splittedLine[2])!
|
||||||
}()
|
}()
|
||||||
let height: Int = {
|
let height: Int = {
|
||||||
if splittedLine[3] == "?" {
|
if splittedLine[3] == "?" {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return Int(splittedLine[3])! // swiftlint:disable:this force_unwrapping
|
return Int(splittedLine[3])!
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var imageExtensions: [ImageExtension] = []
|
var imageExtensions: [ImageExtension] = []
|
||||||
|
@ -8,29 +8,23 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
|
||||||
// swiftlint:disable type_body_length file_length
|
class StringsFileGenerator {
|
||||||
|
|
||||||
enum StringsFileGenerator {
|
|
||||||
|
|
||||||
// MARK: - Strings Files
|
// MARK: - Strings Files
|
||||||
|
|
||||||
static func writeStringsFiles(
|
static func writeStringsFiles(sections: [Section],
|
||||||
sections: [Section],
|
langs: [String],
|
||||||
langs: [String],
|
defaultLang: String,
|
||||||
defaultLang: String,
|
tags: [String],
|
||||||
tags: [String],
|
outputPath: String,
|
||||||
outputPath: String,
|
inputFilenameWithoutExt: String) {
|
||||||
inputFilenameWithoutExt: String
|
|
||||||
) {
|
|
||||||
|
|
||||||
var stringsFilesContent = [String: String]()
|
var stringsFilesContent = [String: String]()
|
||||||
for lang in langs {
|
for lang in langs {
|
||||||
stringsFilesContent[lang] = Self.generateStringsFileContent(
|
stringsFilesContent[lang] = Self.generateStringsFileContent(lang: lang,
|
||||||
lang: lang,
|
defaultLang: defaultLang,
|
||||||
defaultLang: defaultLang,
|
tags: tags,
|
||||||
tags: tags,
|
sections: sections)
|
||||||
sections: sections
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write strings file content
|
// Write strings file content
|
||||||
@ -41,7 +35,7 @@ enum StringsFileGenerator {
|
|||||||
let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath)
|
let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath)
|
||||||
do {
|
do {
|
||||||
try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8)
|
try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch {
|
} catch let error {
|
||||||
let error = StringiumError.writeFile(error.localizedDescription, stringsFilePath)
|
let error = StringiumError.writeFile(error.localizedDescription, stringsFilePath)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
@ -49,14 +43,12 @@ enum StringsFileGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func writeXcStringsFiles(
|
static func writeXcStringsFiles(sections: [Section],
|
||||||
sections: [Section],
|
langs: [String],
|
||||||
langs: [String],
|
defaultLang: String,
|
||||||
defaultLang: String,
|
tags: [String],
|
||||||
tags: [String],
|
outputPath: String,
|
||||||
outputPath: String,
|
inputFilenameWithoutExt: String) {
|
||||||
inputFilenameWithoutExt: String
|
|
||||||
) {
|
|
||||||
|
|
||||||
let fileContent: String = Self.generateXcStringsFileContent(
|
let fileContent: String = Self.generateXcStringsFileContent(
|
||||||
langs: langs,
|
langs: langs,
|
||||||
@ -69,19 +61,17 @@ enum StringsFileGenerator {
|
|||||||
let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath)
|
let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath)
|
||||||
do {
|
do {
|
||||||
try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8)
|
try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch {
|
} catch let error {
|
||||||
let error = StringiumError.writeFile(error.localizedDescription, stringsFilePath)
|
let error = StringiumError.writeFile(error.localizedDescription, stringsFilePath)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func generateStringsFileContent(
|
static func generateStringsFileContent(lang: String,
|
||||||
lang: String,
|
defaultLang: String,
|
||||||
defaultLang: String,
|
tags inputTags: [String],
|
||||||
tags inputTags: [String],
|
sections: [Section]) -> String {
|
||||||
sections: [Section]
|
|
||||||
) -> String {
|
|
||||||
var stringsFileContent = """
|
var stringsFileContent = """
|
||||||
/**
|
/**
|
||||||
* Apple Strings File
|
* Apple Strings File
|
||||||
@ -130,18 +120,11 @@ enum StringsFileGenerator {
|
|||||||
|
|
||||||
// MARK: - XcStrings Generation
|
// MARK: - XcStrings Generation
|
||||||
|
|
||||||
static func generateXcStringsFileContent(
|
static func generateXcStringsFileContent(langs: [String],
|
||||||
langs: [String],
|
defaultLang: String,
|
||||||
defaultLang: String,
|
tags inputTags: [String],
|
||||||
tags inputTags: [String],
|
sections: [Section]) -> String {
|
||||||
sections: [Section]
|
let rootObject = generateRootObject(langs: langs, defaultLang: defaultLang, tags: inputTags, sections: sections)
|
||||||
) -> String {
|
|
||||||
let rootObject = generateRootObject(
|
|
||||||
langs: langs,
|
|
||||||
defaultLang: defaultLang,
|
|
||||||
tags: inputTags,
|
|
||||||
sections: sections
|
|
||||||
)
|
|
||||||
let file = generateXcStringsFileContentFromRootObject(rootObject: rootObject)
|
let file = generateXcStringsFileContentFromRootObject(rootObject: rootObject)
|
||||||
|
|
||||||
return file
|
return file
|
||||||
@ -155,6 +138,7 @@ enum StringsFileGenerator {
|
|||||||
let json = try encoder.encode(rootObject)
|
let json = try encoder.encode(rootObject)
|
||||||
|
|
||||||
return String(decoding: json, as: UTF8.self)
|
return String(decoding: json, as: UTF8.self)
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
debugPrint("Failed to encode: \(error)")
|
debugPrint("Failed to encode: \(error)")
|
||||||
}
|
}
|
||||||
@ -162,22 +146,20 @@ enum StringsFileGenerator {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
static func generateRootObject(
|
static func generateRootObject(langs: [String],
|
||||||
langs: [String],
|
defaultLang: String,
|
||||||
defaultLang: String,
|
tags inputTags: [String],
|
||||||
tags inputTags: [String],
|
sections: [Section]) -> Root {
|
||||||
sections: [Section]
|
|
||||||
) -> Root {
|
|
||||||
|
|
||||||
var xcStringDefinitionTab: [XCStringDefinition] = []
|
var xcStringDefinitionTab: [XCStringDefinition] = []
|
||||||
|
|
||||||
sections.forEach { section in // swiftlint:disable:this closure_body_length
|
sections.forEach { section in
|
||||||
// Check that at least one string will be generated
|
// Check that at least one string will be generated
|
||||||
guard section.hasOneOrMoreMatchingTags(tags: inputTags) else {
|
guard section.hasOneOrMoreMatchingTags(tags: inputTags) else {
|
||||||
return // Go to next section
|
return // Go to next section
|
||||||
}
|
}
|
||||||
|
|
||||||
section.definitions.forEach { definition in // swiftlint:disable:this closure_body_length
|
section.definitions.forEach { definition in
|
||||||
var skipDefinition = false
|
var skipDefinition = false
|
||||||
var isNoTranslation = false
|
var isNoTranslation = false
|
||||||
|
|
||||||
@ -208,6 +190,7 @@ enum StringsFileGenerator {
|
|||||||
} else {
|
} else {
|
||||||
// Search for langs in twine
|
// Search for langs in twine
|
||||||
for (lang, value) in definition.translations where !value.isEmpty {
|
for (lang, value) in definition.translations where !value.isEmpty {
|
||||||
|
|
||||||
let localization = XCStringLocalization(
|
let localization = XCStringLocalization(
|
||||||
lang: lang,
|
lang: lang,
|
||||||
content: XCStringLocalizationLangContent(
|
content: XCStringLocalizationLangContent(
|
||||||
@ -246,32 +229,28 @@ enum StringsFileGenerator {
|
|||||||
|
|
||||||
// MARK: - Extension file
|
// MARK: - Extension file
|
||||||
|
|
||||||
static func writeExtensionFiles(
|
static func writeExtensionFiles(sections: [Section],
|
||||||
sections: [Section],
|
defaultLang lang: String,
|
||||||
defaultLang lang: String,
|
tags: [String],
|
||||||
tags: [String],
|
staticVar: Bool,
|
||||||
staticVar: Bool,
|
inputFilename: String,
|
||||||
inputFilename: String,
|
extensionName: String,
|
||||||
extensionName: String,
|
extensionFilePath: String,
|
||||||
extensionFilePath: String,
|
extensionSuffix: String) {
|
||||||
extensionSuffix: String
|
|
||||||
) {
|
|
||||||
// Get extension content
|
// Get extension content
|
||||||
let extensionFileContent = Self.getExtensionContent(
|
let extensionFileContent = Self.getExtensionContent(sections: sections,
|
||||||
sections: sections,
|
defaultLang: lang,
|
||||||
defaultLang: lang,
|
tags: tags,
|
||||||
tags: tags,
|
staticVar: staticVar,
|
||||||
staticVar: staticVar,
|
inputFilename: inputFilename,
|
||||||
inputFilename: inputFilename,
|
extensionName: extensionName,
|
||||||
extensionName: extensionName,
|
extensionSuffix: extensionSuffix)
|
||||||
extensionSuffix: extensionSuffix
|
|
||||||
)
|
|
||||||
|
|
||||||
// Write content
|
// Write content
|
||||||
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
||||||
do {
|
do {
|
||||||
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch {
|
} catch let error {
|
||||||
let error = StringiumError.writeFile(extensionFilePath, error.localizedDescription)
|
let error = StringiumError.writeFile(extensionFilePath, error.localizedDescription)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
@ -280,32 +259,17 @@ enum StringsFileGenerator {
|
|||||||
|
|
||||||
// MARK: - Extension content
|
// MARK: - Extension content
|
||||||
|
|
||||||
static func getExtensionContent(
|
static func getExtensionContent(sections: [Section],
|
||||||
sections: [Section],
|
defaultLang lang: String,
|
||||||
defaultLang lang: String,
|
tags: [String],
|
||||||
tags: [String],
|
staticVar: Bool,
|
||||||
staticVar: Bool,
|
inputFilename: String,
|
||||||
inputFilename: String,
|
extensionName: String,
|
||||||
extensionName: String,
|
extensionSuffix: String) -> String {
|
||||||
extensionSuffix: String
|
|
||||||
) -> String {
|
|
||||||
[
|
[
|
||||||
Self.getHeader(
|
Self.getHeader(stringsFilename: inputFilename, extensionClassname: extensionName),
|
||||||
stringsFilename: inputFilename,
|
Self.getEnumKey(sections: sections, tags: tags, extensionClassname: extensionName, extensionSuffix: extensionSuffix),
|
||||||
extensionClassname: extensionName
|
Self.getProperties(sections: sections, defaultLang: lang, tags: tags, staticVar: staticVar),
|
||||||
),
|
|
||||||
Self.getEnumKey(
|
|
||||||
sections: sections,
|
|
||||||
tags: tags,
|
|
||||||
extensionClassname: extensionName,
|
|
||||||
extensionSuffix: extensionSuffix
|
|
||||||
),
|
|
||||||
Self.getProperties(
|
|
||||||
sections: sections,
|
|
||||||
defaultLang: lang,
|
|
||||||
tags: tags,
|
|
||||||
staticVar: staticVar
|
|
||||||
),
|
|
||||||
Self.getFooter()
|
Self.getFooter()
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
@ -325,12 +289,7 @@ enum StringsFileGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getEnumKey(
|
private static func getEnumKey(sections: [Section], tags: [String], extensionClassname: String, extensionSuffix: String) -> String {
|
||||||
sections: [Section],
|
|
||||||
tags: [String],
|
|
||||||
extensionClassname: String,
|
|
||||||
extensionSuffix: String
|
|
||||||
) -> String {
|
|
||||||
var enumDefinition = "\n enum Key\(extensionSuffix.uppercasedFirst()): String {\n"
|
var enumDefinition = "\n enum Key\(extensionSuffix.uppercasedFirst()): String {\n"
|
||||||
|
|
||||||
// Enum
|
// Enum
|
||||||
|
@ -5,34 +5,24 @@
|
|||||||
// Created by Thibaut Schmitt on 10/01/2022.
|
// Created by Thibaut Schmitt on 10/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CoreVideo
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import CoreVideo
|
||||||
|
|
||||||
enum TagsGenerator {
|
class TagsGenerator {
|
||||||
|
static func writeExtensionFiles(sections: [Section], lang: String, tags: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) {
|
||||||
static func writeExtensionFiles(
|
|
||||||
sections: [Section],
|
|
||||||
lang: String,
|
|
||||||
tags: [String],
|
|
||||||
staticVar: Bool,
|
|
||||||
extensionName: String,
|
|
||||||
extensionFilePath: String
|
|
||||||
) {
|
|
||||||
// Get extension content
|
// Get extension content
|
||||||
let extensionFileContent = Self.getExtensionContent(
|
let extensionFileContent = Self.getExtensionContent(sections: sections,
|
||||||
sections: sections,
|
lang: lang,
|
||||||
lang: lang,
|
tags: tags,
|
||||||
tags: tags,
|
staticVar: staticVar,
|
||||||
staticVar: staticVar,
|
extensionName: extensionName)
|
||||||
extensionName: extensionName
|
|
||||||
)
|
|
||||||
|
|
||||||
// Write content
|
// Write content
|
||||||
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
||||||
do {
|
do {
|
||||||
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch {
|
} catch let error {
|
||||||
let error = StringiumError.writeFile(extensionFilePath, error.localizedDescription)
|
let error = StringiumError.writeFile(extensionFilePath, error.localizedDescription)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
@ -41,24 +31,10 @@ enum TagsGenerator {
|
|||||||
|
|
||||||
// MARK: - Extension content
|
// MARK: - Extension content
|
||||||
|
|
||||||
static func getExtensionContent(
|
static func getExtensionContent(sections: [Section], lang: String, tags: [String], staticVar: Bool, extensionName: String) -> String {
|
||||||
sections: [Section],
|
|
||||||
lang: String,
|
|
||||||
tags: [String],
|
|
||||||
staticVar: Bool,
|
|
||||||
extensionName: String
|
|
||||||
) -> String {
|
|
||||||
[
|
[
|
||||||
Self.getHeader(
|
Self.getHeader(extensionClassname: extensionName, staticVar: staticVar),
|
||||||
extensionClassname: extensionName,
|
Self.getProperties(sections: sections, lang: lang, tags: tags, staticVar: staticVar),
|
||||||
staticVar: staticVar
|
|
||||||
),
|
|
||||||
Self.getProperties(
|
|
||||||
sections: sections,
|
|
||||||
lang: lang,
|
|
||||||
tags: tags,
|
|
||||||
staticVar: staticVar
|
|
||||||
),
|
|
||||||
Self.getFooter()
|
Self.getFooter()
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
@ -76,17 +52,12 @@ enum TagsGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getProperties(
|
private static func getProperties(sections: [Section], lang: String, tags: [String], staticVar: Bool) -> String {
|
||||||
sections: [Section],
|
|
||||||
lang: String,
|
|
||||||
tags: [String],
|
|
||||||
staticVar: Bool
|
|
||||||
) -> String {
|
|
||||||
sections
|
sections
|
||||||
.compactMap { section in
|
.compactMap { section in
|
||||||
// Check that at least one string will be generated
|
// Check that at least one string will be generated
|
||||||
guard section.hasOneOrMoreMatchingTags(tags: tags) else {
|
guard section.hasOneOrMoreMatchingTags(tags: tags) else {
|
||||||
return nil // Go to next section
|
return nil// Go to next section
|
||||||
}
|
}
|
||||||
|
|
||||||
var res = "\n // MARK: - \(section.name)"
|
var res = "\n // MARK: - \(section.name)"
|
||||||
|
@ -7,12 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
// swiftlint:disable force_unwrapping
|
|
||||||
|
|
||||||
class Definition {
|
class Definition {
|
||||||
|
|
||||||
// MARK: - Properties
|
|
||||||
|
|
||||||
let name: String
|
let name: String
|
||||||
var tags = [String]()
|
var tags = [String]()
|
||||||
var comment: String?
|
var comment: String?
|
||||||
@ -53,31 +48,21 @@ class Definition {
|
|||||||
private func getStringParameters(input: String) -> (inputParameters: [String], translationArguments: [String])? {
|
private func getStringParameters(input: String) -> (inputParameters: [String], translationArguments: [String])? {
|
||||||
var methodsParameters = [String]()
|
var methodsParameters = [String]()
|
||||||
|
|
||||||
let printfPlaceholderRegex = try! NSRegularExpression( // swiftlint:disable:this force_try
|
let printfPlaceholderRegex = try! NSRegularExpression(pattern: "%(?:\\d+\\$)?[+-]?(?:[ 0]|'.{1})?-?\\d*(?:\\.\\d+)?[blcdeEufFgGosxX@]*")
|
||||||
pattern: "%(?:\\d+\\$)?[+-]?(?:[ 0]|'.{1})?-?\\d*(?:\\.\\d+)?[blcdeEufFgGosxX@]*"
|
printfPlaceholderRegex.enumerateMatches(in: input, options: [], range: NSRange(location: 0, length: input.count)) { match, _, stop in
|
||||||
)
|
guard let match = match else { return }
|
||||||
printfPlaceholderRegex.enumerateMatches(
|
|
||||||
in: input,
|
|
||||||
options: [],
|
|
||||||
range: NSRange(location: 0, length: input.count)
|
|
||||||
) { match, _, stop in // swiftlint:disable:this unused_closure_parameter
|
|
||||||
guard let match else { return }
|
|
||||||
|
|
||||||
if let range = Range(match.range, in: input), let last = input[range].last {
|
if let range = Range(match.range, in: input), let last = input[range].last {
|
||||||
switch last {
|
switch last {
|
||||||
case "d", "u":
|
case "d", "u":
|
||||||
methodsParameters.append("Int")
|
methodsParameters.append("Int")
|
||||||
|
|
||||||
case "f", "F":
|
case "f", "F":
|
||||||
methodsParameters.append("Double")
|
methodsParameters.append("Double")
|
||||||
|
|
||||||
case "@", "s", "c":
|
case "@", "s", "c":
|
||||||
methodsParameters.append("String")
|
methodsParameters.append("String")
|
||||||
|
|
||||||
case "%":
|
case "%":
|
||||||
// if you need to print %, you have to add %%
|
// if you need to print %, you have to add %%
|
||||||
break
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -106,20 +91,15 @@ class Definition {
|
|||||||
///
|
///
|
||||||
/// Comment :
|
/// Comment :
|
||||||
/// \(comment?.isEmpty == false ? comment! : "No comment")
|
/// \(comment?.isEmpty == false ? comment! : "No comment")
|
||||||
\(isStatic ? "static " : "")var \(name): String {
|
\(isStatic ? "static ": "")var \(name): String {
|
||||||
NSLocalizedString("\(name)", tableName: kStringsFileName, bundle: Bundle.main, value: "\(translation)", comment: "\(comment ?? "")")
|
NSLocalizedString("\(name)", tableName: kStringsFileName, bundle: Bundle.main, value: "\(translation)", comment: "\(comment ?? "")")
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getBaseMethod(
|
private func getBaseMethod(lang: String, translation: String, isStatic: Bool, inputParameters: [String], translationArguments: [String], comment: String?) -> String {
|
||||||
lang: String,
|
|
||||||
translation: String,
|
|
||||||
isStatic: Bool,
|
|
||||||
inputParameters: [String],
|
|
||||||
translationArguments: [String],
|
|
||||||
comment: String?
|
|
||||||
) -> String {
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
/// Translation in \(lang) :
|
/// Translation in \(lang) :
|
||||||
@ -127,7 +107,7 @@ class Definition {
|
|||||||
///
|
///
|
||||||
/// Comment :
|
/// Comment :
|
||||||
/// \(comment?.isEmpty == false ? comment! : "No comment")
|
/// \(comment?.isEmpty == false ? comment! : "No comment")
|
||||||
\(isStatic ? "static " : "")func \(name)(\(inputParameters.joined(separator: ", "))) -> String {
|
\(isStatic ? "static ": "")func \(name)(\(inputParameters.joined(separator: ", "))) -> String {
|
||||||
String(format: \(isStatic ? "Self" : "self").\(name), \(translationArguments.joined(separator: ", ")))
|
String(format: \(isStatic ? "Self" : "self").\(name), \(translationArguments.joined(separator: ", ")))
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@ -151,14 +131,12 @@ class Definition {
|
|||||||
// Generate method
|
// Generate method
|
||||||
var method = ""
|
var method = ""
|
||||||
if let parameters = self.getStringParameters(input: translation) {
|
if let parameters = self.getStringParameters(input: translation) {
|
||||||
method = getBaseMethod(
|
method = getBaseMethod(lang: lang,
|
||||||
lang: lang,
|
translation: translation,
|
||||||
translation: translation,
|
isStatic: false,
|
||||||
isStatic: false,
|
inputParameters: parameters.inputParameters,
|
||||||
inputParameters: parameters.inputParameters,
|
translationArguments: parameters.translationArguments,
|
||||||
translationArguments: parameters.translationArguments,
|
comment: self.comment)
|
||||||
comment: self.comment
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return property + method
|
return property + method
|
||||||
@ -182,14 +160,12 @@ class Definition {
|
|||||||
// Generate method
|
// Generate method
|
||||||
var method = ""
|
var method = ""
|
||||||
if let parameters = self.getStringParameters(input: translation) {
|
if let parameters = self.getStringParameters(input: translation) {
|
||||||
method = getBaseMethod(
|
method = getBaseMethod(lang: lang,
|
||||||
lang: lang,
|
translation: translation,
|
||||||
translation: translation,
|
isStatic: true,
|
||||||
isStatic: true,
|
inputParameters: parameters.inputParameters,
|
||||||
inputParameters: parameters.inputParameters,
|
translationArguments: parameters.translationArguments,
|
||||||
translationArguments: parameters.translationArguments,
|
comment: self.comment)
|
||||||
comment: self.comment
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return property + method
|
return property + method
|
||||||
|
@ -8,20 +8,13 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class Section {
|
class Section {
|
||||||
|
|
||||||
// MARK: - Properties
|
|
||||||
|
|
||||||
let name: String // OnBoarding
|
let name: String // OnBoarding
|
||||||
var definitions = [Definition]()
|
var definitions = [Definition]()
|
||||||
|
|
||||||
// MARK: - Init
|
|
||||||
|
|
||||||
init(name: String) {
|
init(name: String) {
|
||||||
self.name = name
|
self.name = name
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Methods
|
|
||||||
|
|
||||||
static func match(_ line: String) -> Section? {
|
static func match(_ line: String) -> Section? {
|
||||||
guard line.range(of: "\\[\\[(.*?)]]$", options: .regularExpression, range: nil, locale: nil) != nil else {
|
guard line.range(of: "\\[\\[(.*?)]]$", options: .regularExpression, range: nil, locale: nil) != nil else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -8,30 +8,25 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct DynamicKey: CodingKey {
|
struct DynamicKey: CodingKey {
|
||||||
|
|
||||||
var intValue: Int?
|
var intValue: Int?
|
||||||
|
|
||||||
init?(intValue: Int) {
|
init?(intValue: Int) {
|
||||||
self.intValue = intValue
|
self.intValue = intValue
|
||||||
self.stringValue = "\(intValue)"
|
self.stringValue = "\(intValue)"
|
||||||
}
|
}
|
||||||
|
|
||||||
var stringValue: String
|
var stringValue: String
|
||||||
|
|
||||||
init?(stringValue: String) {
|
init?(stringValue: String) {
|
||||||
self.stringValue = stringValue
|
self.stringValue = stringValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Root: Codable, Equatable {
|
struct Root: Codable, Equatable {
|
||||||
|
|
||||||
let sourceLanguage: String
|
let sourceLanguage: String
|
||||||
let strings: XCStringDefinitionContainer
|
let strings: XCStringDefinitionContainer
|
||||||
let version: String
|
let version: String
|
||||||
}
|
}
|
||||||
|
|
||||||
struct XCStringDefinitionContainer: Codable, Equatable {
|
struct XCStringDefinitionContainer: Codable, Equatable {
|
||||||
|
|
||||||
let strings: [XCStringDefinition]
|
let strings: [XCStringDefinition]
|
||||||
|
|
||||||
func encode(to encoder: Encoder) throws {
|
func encode(to encoder: Encoder) throws {
|
||||||
@ -44,19 +39,19 @@ struct XCStringDefinitionContainer: Codable, Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func == (lhs: Self, rhs: Self) -> Bool {
|
static func == (lhs: XCStringDefinitionContainer, rhs: XCStringDefinitionContainer) -> Bool {
|
||||||
lhs.strings.sorted { $0.title < $1.title } == rhs.strings.sorted { $0.title < $1.title }
|
return lhs.strings.sorted(by: {
|
||||||
|
$0.title < $1.title
|
||||||
|
}) == rhs.strings.sorted(by: { $0.title < $1.title })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct XCStringDefinition: Codable, Equatable {
|
struct XCStringDefinition: Codable, Equatable {
|
||||||
|
|
||||||
let title: String // json key -> custom encoding methods
|
let title: String // json key -> custom encoding methods
|
||||||
let content: XCStringDefinitionContent
|
let content: XCStringDefinitionContent
|
||||||
}
|
}
|
||||||
|
|
||||||
struct XCStringDefinitionContent: Codable, Equatable {
|
struct XCStringDefinitionContent: Codable, Equatable {
|
||||||
|
|
||||||
let comment: String?
|
let comment: String?
|
||||||
let extractionState: String
|
let extractionState: String
|
||||||
var localizations: XCStringLocalizationContainer
|
var localizations: XCStringLocalizationContainer
|
||||||
@ -69,7 +64,6 @@ struct XCStringDefinitionContent: Codable, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct XCStringLocalizationContainer: Codable, Equatable {
|
struct XCStringLocalizationContainer: Codable, Equatable {
|
||||||
|
|
||||||
let localizations: [XCStringLocalization]
|
let localizations: [XCStringLocalization]
|
||||||
|
|
||||||
func encode(to encoder: Encoder) throws {
|
func encode(to encoder: Encoder) throws {
|
||||||
@ -82,39 +76,34 @@ struct XCStringLocalizationContainer: Codable, Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func == (lhs: Self, rhs: Self) -> Bool {
|
static func == (lhs: XCStringLocalizationContainer, rhs: XCStringLocalizationContainer) -> Bool {
|
||||||
lhs.localizations.count == rhs.localizations.count
|
return lhs.localizations.count == rhs.localizations.count && lhs.localizations.sorted(by: { $0.lang < $1.lang }) == rhs.localizations.sorted(by: { $0.lang < $1.lang })
|
||||||
&& lhs.localizations.sorted { $0.lang < $1.lang } == rhs.localizations.sorted { $0.lang < $1.lang }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct XCStringLocalization: Codable, Equatable {
|
struct XCStringLocalization: Codable, Equatable {
|
||||||
|
|
||||||
let lang: String // json key -> custom encoding method
|
let lang: String // json key -> custom encoding method
|
||||||
let content: XCStringLocalizationLangContent
|
let content: XCStringLocalizationLangContent
|
||||||
}
|
}
|
||||||
|
|
||||||
struct XCStringLocalizationLangContent: Codable, Equatable {
|
struct XCStringLocalizationLangContent: Codable, Equatable {
|
||||||
|
|
||||||
let stringUnit: DefaultStringUnit
|
let stringUnit: DefaultStringUnit
|
||||||
}
|
}
|
||||||
|
|
||||||
// enum VarationOrStringUnit: Encodable
|
//enum VarationOrStringUnit: Encodable {
|
||||||
|
// case variations([Varation])
|
||||||
|
// case stringUnit: (DefaultStringUnit)
|
||||||
//
|
//
|
||||||
// case variations([Varation])
|
// func encode(to encoder: any Encoder) throws {
|
||||||
// case stringUnit: (DefaultStringUnit)
|
// if let varations {
|
||||||
//
|
//
|
||||||
// func encode(to encoder: any Encoder) throws {
|
// } else if let {
|
||||||
// if let varations {
|
|
||||||
//
|
//
|
||||||
// } else if let {
|
// }
|
||||||
//
|
// }
|
||||||
// }
|
//}
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
struct DefaultStringUnit: Codable, Equatable {
|
struct DefaultStringUnit: Codable, Equatable {
|
||||||
|
|
||||||
let state: String
|
let state: String
|
||||||
let value: String
|
let value: String
|
||||||
}
|
}
|
||||||
|
@ -7,18 +7,15 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
// swiftlint:disable function_body_length
|
class TwineFileParser {
|
||||||
|
|
||||||
enum TwineFileParser {
|
|
||||||
|
|
||||||
static func parse(_ inputFile: String) -> [Section] {
|
static func parse(_ inputFile: String) -> [Section] {
|
||||||
let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8) // swiftlint:disable:this force_try
|
let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8)
|
||||||
let stringsByLines = inputFileContent.components(separatedBy: .newlines)
|
let stringsByLines = inputFileContent.components(separatedBy: .newlines)
|
||||||
|
|
||||||
var sections = [Section]()
|
var sections = [Section]()
|
||||||
|
|
||||||
// Parse file
|
// Parse file
|
||||||
stringsByLines.forEach { // swiftlint:disable:this closure_body_length
|
stringsByLines.forEach {
|
||||||
// Section
|
// Section
|
||||||
if let section = Section.match($0) {
|
if let section = Section.match($0) {
|
||||||
sections.append(section)
|
sections.append(section)
|
||||||
@ -40,8 +37,8 @@ enum TwineFileParser {
|
|||||||
|
|
||||||
guard let lastDefinition = sections.last?.definitions.last,
|
guard let lastDefinition = sections.last?.definitions.last,
|
||||||
let leftElement = splitLine.first else {
|
let leftElement = splitLine.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let rightElement: String = splitLine.dropFirst().joined(separator: "=")
|
let rightElement: String = splitLine.dropFirst().joined(separator: "=")
|
||||||
|
|
||||||
@ -65,6 +62,11 @@ enum TwineFileParser {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
lastDefinition.translations[leftHand] = rightHand.escapeDoubleQuote()
|
lastDefinition.translations[leftHand] = rightHand.escapeDoubleQuote()
|
||||||
|
// Is a plurals strings (fr:one = Test)
|
||||||
|
// Will be handle later
|
||||||
|
//if leftHand.split(separator: ":").count > 1 {
|
||||||
|
// lastDefinition.isPlurals = true
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +83,7 @@ enum TwineFileParser {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if invalidDefinitionNames.isEmpty == false {
|
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: ", "))")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
// Created by Thibaut Schmitt on 10/01/2022.
|
// Created by Thibaut Schmitt on 10/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
struct Stringium: ParsableCommand {
|
struct Stringium: ParsableCommand {
|
||||||
|
|
||||||
@ -47,37 +47,31 @@ struct Stringium: ParsableCommand {
|
|||||||
if !options.xcStrings {
|
if !options.xcStrings {
|
||||||
print("[\(Self.toolName)] Will generate strings")
|
print("[\(Self.toolName)] Will generate strings")
|
||||||
|
|
||||||
StringsFileGenerator.writeStringsFiles(
|
StringsFileGenerator.writeStringsFiles(sections: sections,
|
||||||
sections: sections,
|
langs: options.langs,
|
||||||
langs: options.langs,
|
defaultLang: options.defaultLang,
|
||||||
defaultLang: options.defaultLang,
|
tags: options.tags,
|
||||||
tags: options.tags,
|
outputPath: options.stringsFileOutputPath,
|
||||||
outputPath: options.stringsFileOutputPath,
|
inputFilenameWithoutExt: options.inputFilenameWithoutExt)
|
||||||
inputFilenameWithoutExt: options.inputFilenameWithoutExt
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
print("[\(Self.toolName)] Will generate xcStrings")
|
print("[\(Self.toolName)] Will generate xcStrings")
|
||||||
StringsFileGenerator.writeXcStringsFiles(
|
StringsFileGenerator.writeXcStringsFiles(sections: sections,
|
||||||
sections: sections,
|
langs: options.langs,
|
||||||
langs: options.langs,
|
defaultLang: options.defaultLang,
|
||||||
defaultLang: options.defaultLang,
|
tags: options.tags,
|
||||||
tags: options.tags,
|
outputPath: options.stringsFileOutputPath,
|
||||||
outputPath: options.stringsFileOutputPath,
|
inputFilenameWithoutExt: options.inputFilenameWithoutExt)
|
||||||
inputFilenameWithoutExt: options.inputFilenameWithoutExt
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
StringsFileGenerator.writeExtensionFiles(
|
StringsFileGenerator.writeExtensionFiles(sections: sections,
|
||||||
sections: sections,
|
defaultLang: options.defaultLang,
|
||||||
defaultLang: options.defaultLang,
|
tags: options.tags,
|
||||||
tags: options.tags,
|
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)
|
||||||
extensionSuffix: options.extensionSuffix
|
|
||||||
)
|
|
||||||
|
|
||||||
print("[\(Self.toolName)] Strings generated")
|
print("[\(Self.toolName)] Strings generated")
|
||||||
}
|
}
|
||||||
@ -91,28 +85,26 @@ struct Stringium: ParsableCommand {
|
|||||||
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.description)
|
print(error.description)
|
||||||
Self.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.description)
|
print(error.description)
|
||||||
Self.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.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if needed to regenerate
|
// Check if needed to regenerate
|
||||||
guard GeneratorChecker.shouldGenerate(
|
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration,
|
||||||
force: options.forceGeneration,
|
inputFilePath: options.inputFile,
|
||||||
inputFilePath: options.inputFile,
|
extensionFilePath: options.extensionFilePath) else {
|
||||||
extensionFilePath: options.extensionFilePath
|
|
||||||
) else {
|
|
||||||
print("[\(Self.toolName)] Strings are already up to date :) ")
|
print("[\(Self.toolName)] Strings are already up to date :) ")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum StringiumError: Error {
|
enum StringiumError: Error {
|
||||||
|
|
||||||
case fileNotExists(String)
|
case fileNotExists(String)
|
||||||
case langsListEmpty
|
case langsListEmpty
|
||||||
case defaultLangsNotInLangs
|
case defaultLangsNotInLangs
|
||||||
@ -26,10 +25,10 @@ enum StringiumError: Error {
|
|||||||
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 let .writeFile(subErrorDescription, 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 let .langNotDefined(lang, definitionName, isReference):
|
case .langNotDefined(let lang, let definitionName, let isReference):
|
||||||
if isReference {
|
if isReference {
|
||||||
return "error: [\(Stringium.toolName)] Reference are handled only by Twine. 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."
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,10 @@
|
|||||||
// Created by Thibaut Schmitt on 10/01/2022.
|
// Created by Thibaut Schmitt on 10/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
// swiftlint:disable no_grouping_extension
|
|
||||||
|
|
||||||
struct StringiumOptions: ParsableArguments {
|
struct StringiumOptions: ParsableArguments {
|
||||||
|
|
||||||
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
||||||
var forceGeneration = false
|
var forceGeneration = false
|
||||||
|
|
||||||
@ -49,7 +46,6 @@ struct StringiumOptions: ParsableArguments {
|
|||||||
// MARK: - Private var getter
|
// MARK: - Private var getter
|
||||||
|
|
||||||
extension StringiumOptions {
|
extension StringiumOptions {
|
||||||
|
|
||||||
var stringsFileOutputPath: String {
|
var stringsFileOutputPath: String {
|
||||||
var outputPath = outputPathRaw
|
var outputPath = outputPathRaw
|
||||||
if outputPath.last == "/" {
|
if outputPath.last == "/" {
|
||||||
@ -74,7 +70,6 @@ extension StringiumOptions {
|
|||||||
// MARK: - Computed var
|
// MARK: - Computed var
|
||||||
|
|
||||||
extension StringiumOptions {
|
extension StringiumOptions {
|
||||||
|
|
||||||
var extensionFileName: String {
|
var extensionFileName: String {
|
||||||
"\(extensionName)+\(extensionSuffix).swift"
|
"\(extensionName)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
// Created by Thibaut Schmitt on 10/01/2022.
|
// Created by Thibaut Schmitt on 10/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
struct Strings: ParsableCommand {
|
struct Strings: ParsableCommand {
|
||||||
|
|
||||||
@ -22,8 +22,8 @@ struct Strings: ParsableCommand {
|
|||||||
|
|
||||||
// A default subcommand, when provided, is automatically selected if a
|
// A default subcommand, when provided, is automatically selected if a
|
||||||
// subcommand is not given on the command line.
|
// subcommand is not given on the command line.
|
||||||
// defaultSubcommand: Twine.self
|
//defaultSubcommand: Twine.self
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strings.main()
|
//Strings.main()
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
// Created by Thibaut Schmitt on 10/01/2022.
|
// Created by Thibaut Schmitt on 10/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
struct Tags: ParsableCommand {
|
struct Tags: ParsableCommand {
|
||||||
|
|
||||||
@ -43,14 +43,12 @@ struct Tags: ParsableCommand {
|
|||||||
let sections = TwineFileParser.parse(options.inputFile)
|
let sections = TwineFileParser.parse(options.inputFile)
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
TagsGenerator.writeExtensionFiles(
|
TagsGenerator.writeExtensionFiles(sections: sections,
|
||||||
sections: sections,
|
lang: options.lang,
|
||||||
lang: options.lang,
|
tags: ["ios", "iosonly", Self.noTranslationTag],
|
||||||
tags: ["ios", "iosonly", Self.noTranslationTag],
|
staticVar: options.staticMembers,
|
||||||
staticVar: options.staticMembers,
|
extensionName: options.extensionName,
|
||||||
extensionName: options.extensionName,
|
extensionFilePath: options.extensionFilePath)
|
||||||
extensionFilePath: options.extensionFilePath
|
|
||||||
)
|
|
||||||
|
|
||||||
print("[\(Self.toolName)] Tags generated")
|
print("[\(Self.toolName)] Tags generated")
|
||||||
}
|
}
|
||||||
@ -68,11 +66,9 @@ struct Tags: ParsableCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if needed to regenerate
|
// Check if needed to regenerate
|
||||||
guard GeneratorChecker.shouldGenerate(
|
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration,
|
||||||
force: options.forceGeneration,
|
inputFilePath: options.inputFile,
|
||||||
inputFilePath: options.inputFile,
|
extensionFilePath: options.extensionFilePath) else {
|
||||||
extensionFilePath: options.extensionFilePath
|
|
||||||
) else {
|
|
||||||
print("[\(Self.toolName)] Tags are already up to date :) ")
|
print("[\(Self.toolName)] Tags are already up to date :) ")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,10 @@
|
|||||||
// Created by Thibaut Schmitt on 10/01/2022.
|
// Created by Thibaut Schmitt on 10/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
// swiftlint:disable no_grouping_extension
|
|
||||||
|
|
||||||
struct TagsOptions: ParsableArguments {
|
struct TagsOptions: ParsableArguments {
|
||||||
|
|
||||||
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
||||||
var forceGeneration = false
|
var forceGeneration = false
|
||||||
|
|
||||||
@ -37,9 +34,8 @@ struct TagsOptions: ParsableArguments {
|
|||||||
// MARK: - Computed var
|
// MARK: - Computed var
|
||||||
|
|
||||||
extension TagsOptions {
|
extension TagsOptions {
|
||||||
|
|
||||||
var extensionFileName: String {
|
var extensionFileName: String {
|
||||||
if let extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
return "\(extensionName)+\(extensionSuffix).swift"
|
return "\(extensionName)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionName).swift"
|
return "\(extensionName).swift"
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
// Created by Thibaut Schmitt on 10/01/2022.
|
// Created by Thibaut Schmitt on 10/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
struct Twine: ParsableCommand {
|
struct Twine: ParsableCommand {
|
||||||
|
|
||||||
@ -22,13 +22,7 @@ struct Twine: ParsableCommand {
|
|||||||
|
|
||||||
static let toolName = "Twine"
|
static let toolName = "Twine"
|
||||||
static let defaultExtensionName = "String"
|
static let defaultExtensionName = "String"
|
||||||
static let twineExecutable: String = {
|
static let twineExecutable = "\(FileManager.default.homeDirectoryForCurrentUser.relativePath)/scripts/twine/twine"
|
||||||
#if os(macOS)
|
|
||||||
"\(FileManager.default.homeDirectoryForCurrentUser.relativePath)/scripts/twine/twine"
|
|
||||||
#else
|
|
||||||
fatalError("This command should run on Mac only")
|
|
||||||
#endif
|
|
||||||
}()
|
|
||||||
|
|
||||||
// MARK: - Command Options
|
// MARK: - Command Options
|
||||||
|
|
||||||
@ -46,33 +40,20 @@ struct Twine: ParsableCommand {
|
|||||||
|
|
||||||
// Generate strings files (lproj files)
|
// Generate strings files (lproj files)
|
||||||
for lang in options.langs {
|
for lang in options.langs {
|
||||||
Shell.shell(
|
Shell.shell([Self.twineExecutable,
|
||||||
[
|
"generate-localization-file", options.inputFile,
|
||||||
Self.twineExecutable,
|
"--lang", "\(lang)",
|
||||||
"generate-localization-file",
|
"\(options.outputPath)/\(lang).lproj/\(options.inputFilenameWithoutExt).strings",
|
||||||
options.inputFile,
|
"--tags=ios,iosonly,iosOnly"])
|
||||||
"--lang",
|
|
||||||
"\(lang)",
|
|
||||||
"\(options.outputPath)/\(lang).lproj/\(options.inputFilenameWithoutExt).strings",
|
|
||||||
"--tags=ios,iosonly,iosOnly"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
Shell.shell(
|
Shell.shell([Self.twineExecutable,
|
||||||
[
|
"generate-localization-file", options.inputFile,
|
||||||
Self.twineExecutable,
|
"--format", "apple-swift",
|
||||||
"generate-localization-file",
|
"--lang", "\(options.defaultLang)",
|
||||||
options.inputFile,
|
options.extensionFilePath,
|
||||||
"--format",
|
"--tags=ios,iosonly,iosOnly"])
|
||||||
"apple-swift",
|
|
||||||
"--lang",
|
|
||||||
"\(options.defaultLang)",
|
|
||||||
options.extensionFilePath,
|
|
||||||
"--tags=ios,iosonly,iosOnly"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
print("[\(Self.toolName)] Strings generated")
|
print("[\(Self.toolName)] Strings generated")
|
||||||
}
|
}
|
||||||
@ -86,28 +67,26 @@ struct Twine: ParsableCommand {
|
|||||||
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.description)
|
print(error.description)
|
||||||
Self.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.description)
|
print(error.description)
|
||||||
Self.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.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Twine.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if needed to regenerate
|
// Check if needed to regenerate
|
||||||
guard GeneratorChecker.shouldGenerate(
|
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration,
|
||||||
force: options.forceGeneration,
|
inputFilePath: options.inputFile,
|
||||||
inputFilePath: options.inputFile,
|
extensionFilePath: options.extensionFilePathGenerated) else {
|
||||||
extensionFilePath: options.extensionFilePathGenerated
|
|
||||||
) else {
|
|
||||||
print("[\(Self.toolName)] Strings are already up to date :) ")
|
print("[\(Self.toolName)] Strings are already up to date :) ")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum TwineError: Error {
|
enum TwineError: Error {
|
||||||
|
|
||||||
case fileNotExists(String)
|
case fileNotExists(String)
|
||||||
case langsListEmpty
|
case langsListEmpty
|
||||||
case defaultLangsNotInLangs
|
case defaultLangsNotInLangs
|
||||||
|
@ -5,13 +5,10 @@
|
|||||||
// Created by Thibaut Schmitt on 10/01/2022.
|
// Created by Thibaut Schmitt on 10/01/2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
// swiftlint:disable no_grouping_extension
|
|
||||||
|
|
||||||
struct TwineOptions: ParsableArguments {
|
struct TwineOptions: ParsableArguments {
|
||||||
|
|
||||||
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
||||||
var forceGeneration = false
|
var forceGeneration = false
|
||||||
|
|
||||||
@ -34,7 +31,6 @@ struct TwineOptions: ParsableArguments {
|
|||||||
// MARK: - Private var getter
|
// MARK: - Private var getter
|
||||||
|
|
||||||
extension TwineOptions {
|
extension TwineOptions {
|
||||||
|
|
||||||
var langs: [String] {
|
var langs: [String] {
|
||||||
langsRaw
|
langsRaw
|
||||||
.split(separator: " ")
|
.split(separator: " ")
|
||||||
@ -45,7 +41,6 @@ extension TwineOptions {
|
|||||||
// MARK: - Computed var
|
// MARK: - Computed var
|
||||||
|
|
||||||
extension TwineOptions {
|
extension TwineOptions {
|
||||||
|
|
||||||
var inputFilenameWithoutExt: String {
|
var inputFilenameWithoutExt: String {
|
||||||
URL(fileURLWithPath: inputFile)
|
URL(fileURLWithPath: inputFile)
|
||||||
.deletingPathExtension()
|
.deletingPathExtension()
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
// Created by Thibaut Schmitt on 13/12/2021.
|
// Created by Thibaut Schmitt on 13/12/2021.
|
||||||
//
|
//
|
||||||
|
|
||||||
import ArgumentParser
|
|
||||||
import Foundation
|
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
struct ResgenSwift: ParsableCommand {
|
struct ResgenSwift: ParsableCommand {
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ struct ResgenSwift: ParsableCommand {
|
|||||||
|
|
||||||
// A default subcommand, when provided, is automatically selected if a
|
// A default subcommand, when provided, is automatically selected if a
|
||||||
// subcommand is not given on the command line.
|
// subcommand is not given on the command line.
|
||||||
// defaultSubcommand: Twine.self
|
//defaultSubcommand: Twine.self
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public enum GeneratorChecker {
|
public class GeneratorChecker {
|
||||||
|
|
||||||
/// Return `true` if inputFile is newer than extensionFile, otherwise `false`
|
/// Return `true` if inputFile is newer than extensionFile, otherwise `false`
|
||||||
public static func shouldGenerate(force: Bool, inputFilePath: String, extensionFilePath: String) -> Bool {
|
public static func shouldGenerate(force: Bool, inputFilePath: String, extensionFilePath: String) -> Bool {
|
||||||
@ -39,4 +39,5 @@ public enum GeneratorChecker {
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,8 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension Sequence where Iterator.Element: Hashable {
|
public extension Sequence where Iterator.Element: Hashable {
|
||||||
|
func unique() -> [Iterator.Element] {
|
||||||
public func unique() -> [Iterator.Element] {
|
|
||||||
var seen: [Iterator.Element: Bool] = [:]
|
var seen: [Iterator.Element: Bool] = [:]
|
||||||
return self.filter { seen.updateValue(true, forKey: $0) == nil }
|
return self.filter { seen.updateValue(true, forKey: $0) == nil }
|
||||||
}
|
}
|
||||||
|
@ -7,18 +7,40 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public enum Shell {
|
public class Shell {
|
||||||
|
|
||||||
public static var environment: [String: String] {
|
public static var environment: [String: String] {
|
||||||
ProcessInfo.processInfo.environment
|
ProcessInfo.processInfo.environment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @discardableResult
|
||||||
|
// public static func shell(launchPath: String = "/usr/bin/env", _ args: String...) -> (terminationStatus: Int32, output: String?) {
|
||||||
|
// let task = Process()
|
||||||
|
// task.launchPath = launchPath
|
||||||
|
// task.arguments = args
|
||||||
|
//
|
||||||
|
// var currentEnv = ProcessInfo.processInfo.environment
|
||||||
|
// for (key, value) in environment {
|
||||||
|
// currentEnv[key] = value
|
||||||
|
// }
|
||||||
|
// task.environment = currentEnv
|
||||||
|
//
|
||||||
|
// let pipe = Pipe()
|
||||||
|
// task.standardOutput = pipe
|
||||||
|
// try? task.run()
|
||||||
|
// task.waitUntilExit()
|
||||||
|
//
|
||||||
|
// let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||||
|
//
|
||||||
|
// guard let output: String = String(data: data, encoding: .utf8) else {
|
||||||
|
// return (terminationStatus: task.terminationStatus, output: nil)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return (terminationStatus: task.terminationStatus, output: output)
|
||||||
|
// }
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public static func shell(
|
public static func shell(launchPath: String = "/usr/bin/env", _ args: [String]) -> (terminationStatus: Int32, output: String?) {
|
||||||
launchPath: String = "/usr/bin/env",
|
|
||||||
_ args: [String]
|
|
||||||
) -> (terminationStatus: Int32, output: String?) {
|
|
||||||
#if os(macOS)
|
|
||||||
let task = Process()
|
let task = Process()
|
||||||
task.launchPath = launchPath
|
task.launchPath = launchPath
|
||||||
task.arguments = args
|
task.arguments = args
|
||||||
@ -36,13 +58,10 @@ public enum Shell {
|
|||||||
|
|
||||||
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||||
|
|
||||||
guard let output = String(data: data, encoding: .utf8) else {
|
guard let output: String = String(data: data, encoding: .utf8) else {
|
||||||
return (terminationStatus: task.terminationStatus, output: nil)
|
return (terminationStatus: task.terminationStatus, output: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (terminationStatus: task.terminationStatus, output: output)
|
return (terminationStatus: task.terminationStatus, output: output)
|
||||||
#else
|
|
||||||
fatalError("Shell is only available on Mac")
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,26 +7,25 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension String {
|
public extension String {
|
||||||
|
func removeCharacters(from forbiddenChars: CharacterSet) -> String {
|
||||||
public func removeCharacters(from forbiddenChars: CharacterSet) -> String {
|
|
||||||
let passed = self.unicodeScalars.filter { !forbiddenChars.contains($0) }
|
let passed = self.unicodeScalars.filter { !forbiddenChars.contains($0) }
|
||||||
return String(String.UnicodeScalarView(passed))
|
return String(String.UnicodeScalarView(passed))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeCharacters(from: String) -> String {
|
func removeCharacters(from: String) -> String {
|
||||||
removeCharacters(from: CharacterSet(charactersIn: from))
|
return removeCharacters(from: CharacterSet(charactersIn: from))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func replacingOccurrences(of: [String], with: String) -> Self {
|
func replacingOccurrences(of: [String], with: String) -> Self {
|
||||||
var tmp = self
|
var tmp = self
|
||||||
for ofValue in of {
|
for e in of {
|
||||||
tmp = tmp.replacingOccurrences(of: ofValue, with: with)
|
tmp = tmp.replacingOccurrences(of: e, with: with)
|
||||||
}
|
}
|
||||||
return tmp
|
return tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeTrailingWhitespace() -> Self {
|
func removeTrailingWhitespace() -> Self {
|
||||||
var newString = self
|
var newString = self
|
||||||
|
|
||||||
while newString.last?.isWhitespace == true {
|
while newString.last?.isWhitespace == true {
|
||||||
@ -36,7 +35,7 @@ extension String {
|
|||||||
return newString
|
return newString
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeLeadingWhitespace() -> Self {
|
func removeLeadingWhitespace() -> Self {
|
||||||
var newString = self
|
var newString = self
|
||||||
|
|
||||||
while newString.first?.isWhitespace == true {
|
while newString.first?.isWhitespace == true {
|
||||||
@ -46,7 +45,7 @@ extension String {
|
|||||||
return newString
|
return newString
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeLeadingTrailingWhitespace() -> Self {
|
func removeLeadingTrailingWhitespace() -> Self {
|
||||||
var newString = self
|
var newString = self
|
||||||
|
|
||||||
newString = newString.removeLeadingWhitespace()
|
newString = newString.removeLeadingWhitespace()
|
||||||
@ -55,28 +54,24 @@ extension String {
|
|||||||
return newString
|
return newString
|
||||||
}
|
}
|
||||||
|
|
||||||
public func escapeDoubleQuote() -> Self {
|
func escapeDoubleQuote() -> Self {
|
||||||
replacingOccurrences(of: "\"", with: "\\\"")
|
replacingOccurrences(of: "\"", with: "\\\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func replaceTiltWithHomeDirectoryPath() -> Self {
|
func replaceTiltWithHomeDirectoryPath() -> Self {
|
||||||
// See NSString.expandingTildeInPath
|
// See NSString.expandingTildeInPath
|
||||||
#if os(macOS)
|
|
||||||
replacingOccurrences(of: "~", with: "\(FileManager.default.homeDirectoryForCurrentUser.relativePath)")
|
replacingOccurrences(of: "~", with: "\(FileManager.default.homeDirectoryForCurrentUser.relativePath)")
|
||||||
#else
|
|
||||||
fatalError("This command should run on Mac only")
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func colorComponent() -> (alpha: String, red: String, green: String, blue: String) { // swiftlint:disable:this large_tuple
|
func colorComponent() -> (alpha: String, red: String, green: String, blue: String) {
|
||||||
var alpha: String = "FF"
|
var alpha: String = "FF"
|
||||||
var red: String
|
var red: String
|
||||||
var green: String
|
var green: String
|
||||||
var blue: String
|
var blue: String
|
||||||
|
|
||||||
var colorClean = self
|
var colorClean = self
|
||||||
.replacingOccurrences(of: "#", with: "")
|
.replacingOccurrences(of: "#", with: "")
|
||||||
.replacingOccurrences(of: "0x", with: "")
|
.replacingOccurrences(of: "0x", with: "")
|
||||||
|
|
||||||
if colorClean.count == 8 {
|
if colorClean.count == 8 {
|
||||||
alpha = String(colorClean.prefix(2))
|
alpha = String(colorClean.prefix(2))
|
||||||
@ -91,11 +86,11 @@ extension String {
|
|||||||
return (alpha: alpha, red: red, green: green, blue: blue)
|
return (alpha: alpha, red: red, green: green, blue: blue)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func uppercasedFirst() -> String {
|
func uppercasedFirst() -> String {
|
||||||
prefix(1).uppercased() + dropFirst()
|
prefix(1).uppercased() + dropFirst()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func replacingFirstOccurrence(of: String, with: String) -> Self {
|
func replacingFirstOccurrence(of: String, with: String) -> Self {
|
||||||
if let range = self.range(of: of) {
|
if let range = self.range(of: of) {
|
||||||
let tmp = self.replacingOccurrences(
|
let tmp = self.replacingOccurrences(
|
||||||
of: of,
|
of: of,
|
||||||
|
@ -7,6 +7,4 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
// swiftlint:disable prefixed_toplevel_constant identifier_name
|
public let ResgenSwiftVersion = "1.2"
|
||||||
|
|
||||||
public let ResgenSwiftVersion = "2.1.0"
|
|
||||||
|
@ -84,7 +84,7 @@ final class AnalyticsDefinitionTests: XCTestCase {
|
|||||||
name: "Ecran un",
|
name: "Ecran un",
|
||||||
action: "",
|
action: "",
|
||||||
category: "",
|
category: "",
|
||||||
params: [:]
|
params: []
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@ -127,7 +127,7 @@ final class AnalyticsDefinitionTests: XCTestCase {
|
|||||||
name: "Ecran un",
|
name: "Ecran un",
|
||||||
action: "",
|
action: "",
|
||||||
category: "",
|
category: "",
|
||||||
params: [:]
|
params: []
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
@ -51,24 +51,20 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
]
|
]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let extensionContent = AnalyticsGenerator.getExtensionContent(
|
AnalyticsGenerator.targets = [TrackerType.firebase]
|
||||||
targets: [TrackerType.firebase],
|
let extensionContent = AnalyticsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree],
|
||||||
sections: [sectionOne, sectionTwo, sectionThree],
|
tags: ["ios", "iosonly"],
|
||||||
tags: ["ios", "iosonly"],
|
staticVar: false,
|
||||||
staticVar: false,
|
extensionName: "GenAnalytics")
|
||||||
extensionName: "GenAnalytics"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Expect Analytics
|
// Expect Analytics
|
||||||
let expect = """
|
let expect = """
|
||||||
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.Analytics 1.2
|
||||||
|
|
||||||
import FirebaseAnalytics
|
import Firebase
|
||||||
|
|
||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
|
|
||||||
func logScreen(name: String, path: String)
|
func logScreen(name: String, path: String)
|
||||||
func logEvent(
|
func logEvent(
|
||||||
name: String,
|
name: String,
|
||||||
@ -81,10 +77,9 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
// MARK: - Firebase
|
// MARK: - Firebase
|
||||||
|
|
||||||
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||||
|
|
||||||
func logScreen(name: String, path: String) {
|
func logScreen(name: String, path: String) {
|
||||||
var parameters = [
|
var parameters = [
|
||||||
AnalyticsParameterScreenName: name as NSObject
|
AnalyticsParameterScreenName: name
|
||||||
]
|
]
|
||||||
|
|
||||||
Analytics.logEvent(
|
Analytics.logEvent(
|
||||||
@ -99,25 +94,19 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
var parameters: [String:NSObject] = [
|
var parameters: [String:Any] = [
|
||||||
"action": action as NSObject,
|
"action": action,
|
||||||
"category": category as NSObject,
|
"category": category,
|
||||||
]
|
]
|
||||||
|
|
||||||
if let supplementaryParameters = params {
|
if let supplementaryParameters = params {
|
||||||
for (newKey, newValue) in supplementaryParameters {
|
parameters.merge(supplementaryParameters) { (origin, new) -> Any in
|
||||||
if parameters.contains(where: { (key: String, value: NSObject) in
|
return origin
|
||||||
key == newKey
|
|
||||||
}) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
parameters[newKey] = newValue as? NSObject
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Analytics.logEvent(
|
Analytics.logEvent(
|
||||||
name.replacingOccurrences(of: [" "], with: "_"),
|
name,
|
||||||
parameters: parameters
|
parameters: parameters
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -126,7 +115,6 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
|
|
||||||
class AnalyticsManager {
|
class AnalyticsManager {
|
||||||
|
|
||||||
static var shared = AnalyticsManager()
|
static var shared = AnalyticsManager()
|
||||||
|
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
@ -185,7 +173,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
name: "s1 def two",
|
name: "s1 def two",
|
||||||
action: "",
|
action: "",
|
||||||
category: "",
|
category: "",
|
||||||
params: [:]
|
params: []
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,23 +216,20 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
]
|
]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let extensionContent = AnalyticsGenerator.getExtensionContent(
|
AnalyticsGenerator.targets = [TrackerType.matomo]
|
||||||
targets: [TrackerType.matomo],
|
let extensionContent = AnalyticsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree],
|
||||||
sections: [sectionOne, sectionTwo, sectionThree],
|
tags: ["ios", "iosonly"],
|
||||||
tags: ["ios", "iosonly"],
|
staticVar: false,
|
||||||
staticVar: false,
|
extensionName: "GenAnalytics")
|
||||||
extensionName: "GenAnalytics"
|
|
||||||
)
|
|
||||||
// Expect Analytics
|
// Expect Analytics
|
||||||
let expect = """
|
let expect = """
|
||||||
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.Analytics 1.2
|
||||||
|
|
||||||
import MatomoTracker
|
import MatomoTracker
|
||||||
|
|
||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
|
|
||||||
func logScreen(name: String, path: String)
|
func logScreen(name: String, path: String)
|
||||||
func logEvent(
|
func logEvent(
|
||||||
name: String,
|
name: String,
|
||||||
@ -318,7 +303,6 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
|
|
||||||
class AnalyticsManager {
|
class AnalyticsManager {
|
||||||
|
|
||||||
static var shared = AnalyticsManager()
|
static var shared = AnalyticsManager()
|
||||||
|
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
@ -382,7 +366,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
name: "s1 def two",
|
name: "s1 def two",
|
||||||
action: "test",
|
action: "test",
|
||||||
category: "test",
|
category: "test",
|
||||||
params: [:]
|
params: []
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,25 +409,21 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
]
|
]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let extensionContent = AnalyticsGenerator.getExtensionContent(
|
AnalyticsGenerator.targets = [TrackerType.matomo, TrackerType.firebase]
|
||||||
targets: [TrackerType.matomo, TrackerType.firebase],
|
let extensionContent = AnalyticsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree],
|
||||||
sections: [sectionOne, sectionTwo, sectionThree],
|
tags: ["ios", "iosonly"],
|
||||||
tags: ["ios", "iosonly"],
|
staticVar: false,
|
||||||
staticVar: false,
|
extensionName: "GenAnalytics")
|
||||||
extensionName: "GenAnalytics"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Expect Analytics
|
// Expect Analytics
|
||||||
let expect = """
|
let expect = """
|
||||||
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.Analytics 1.2
|
||||||
|
|
||||||
import MatomoTracker
|
import MatomoTracker
|
||||||
import FirebaseAnalytics
|
import Firebase
|
||||||
|
|
||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
|
|
||||||
func logScreen(name: String, path: String)
|
func logScreen(name: String, path: String)
|
||||||
func logEvent(
|
func logEvent(
|
||||||
name: String,
|
name: String,
|
||||||
@ -519,7 +499,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||||
func logScreen(name: String, path: String) {
|
func logScreen(name: String, path: String) {
|
||||||
var parameters = [
|
var parameters = [
|
||||||
AnalyticsParameterScreenName: name as NSObject
|
AnalyticsParameterScreenName: name
|
||||||
]
|
]
|
||||||
|
|
||||||
Analytics.logEvent(
|
Analytics.logEvent(
|
||||||
@ -534,25 +514,19 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
var parameters: [String:NSObject] = [
|
var parameters: [String:Any] = [
|
||||||
"action": action as NSObject,
|
"action": action,
|
||||||
"category": category as NSObject,
|
"category": category,
|
||||||
]
|
]
|
||||||
|
|
||||||
if let supplementaryParameters = params {
|
if let supplementaryParameters = params {
|
||||||
for (newKey, newValue) in supplementaryParameters {
|
parameters.merge(supplementaryParameters) { (origin, new) -> Any in
|
||||||
if parameters.contains(where: { (key: String, value: NSObject) in
|
return origin
|
||||||
key == newKey
|
|
||||||
}) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
parameters[newKey] = newValue as? NSObject
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Analytics.logEvent(
|
Analytics.logEvent(
|
||||||
name.replacingOccurrences(of: [" "], with: "_"),
|
name,
|
||||||
parameters: parameters
|
parameters: parameters
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -561,7 +535,6 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
|
|
||||||
class AnalyticsManager {
|
class AnalyticsManager {
|
||||||
|
|
||||||
static var shared = AnalyticsManager()
|
static var shared = AnalyticsManager()
|
||||||
|
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
@ -626,7 +599,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
name: "s1 def two",
|
name: "s1 def two",
|
||||||
action: "test",
|
action: "test",
|
||||||
category: "test",
|
category: "test",
|
||||||
params: [:]
|
params: []
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ final class FontExtensionGeneratorTests: XCTestCase {
|
|||||||
func test_uiKit_GeneratedExtensionContent() {
|
func test_uiKit_GeneratedExtensionContent() {
|
||||||
// Given
|
// Given
|
||||||
let fontNames: [FontName] = [
|
let fontNames: [FontName] = [
|
||||||
FontName(postscriptName: "CircularStd-Regular", filename: "CircularStd-Regular", fileExtension: "ttf"),
|
"CircularStd-Regular",
|
||||||
FontName(postscriptName: "CircularStd-Bold", filename: "CircularStd-Bold", fileExtension: "ttf")
|
"CircularStd-Bold"
|
||||||
]
|
]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
@ -59,8 +59,8 @@ final class FontExtensionGeneratorTests: XCTestCase {
|
|||||||
func test_swiftUI_GeneratedExtensionContent() {
|
func test_swiftUI_GeneratedExtensionContent() {
|
||||||
// Given
|
// Given
|
||||||
let fontNames: [FontName] = [
|
let fontNames: [FontName] = [
|
||||||
FontName(postscriptName: "CircularStd-Regular", filename: "CircularStd-Regular", fileExtension: "ttf"),
|
"CircularStd-Regular",
|
||||||
FontName(postscriptName: "CircularStd-Bold", filename: "CircularStd-Bold", fileExtension: "ttf")
|
"CircularStd-Bold"
|
||||||
]
|
]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
|
@ -14,11 +14,7 @@ final class FontNameTests: XCTestCase {
|
|||||||
|
|
||||||
func test_uiKit_GeneratedProperty_noForbiddenCharacter() {
|
func test_uiKit_GeneratedProperty_noForbiddenCharacter() {
|
||||||
// Given
|
// Given
|
||||||
let fontName = FontName(
|
let fontName: FontName = "CircularStdBold"
|
||||||
postscriptName: "CircularStdBold",
|
|
||||||
filename: "CircularStd-Bold",
|
|
||||||
fileExtension: "ttf"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let property = fontName.getProperty(isStatic: true, isSwiftUI: false)
|
let property = fontName.getProperty(isStatic: true, isSwiftUI: false)
|
||||||
@ -35,11 +31,7 @@ final class FontNameTests: XCTestCase {
|
|||||||
|
|
||||||
func test_uiKit_GeneratedProperty_withForbiddenCharacter() {
|
func test_uiKit_GeneratedProperty_withForbiddenCharacter() {
|
||||||
// Given
|
// Given
|
||||||
let fontName = FontName(
|
let fontName: FontName = "[Circular_Std+Bold-Underline]"
|
||||||
postscriptName: "[Circular_Std+Bold-Underline]",
|
|
||||||
filename: "Circular_Std+Bold-Underline",
|
|
||||||
fileExtension: "ttf"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let property = fontName.getProperty(isStatic: true, isSwiftUI: false)
|
let property = fontName.getProperty(isStatic: true, isSwiftUI: false)
|
||||||
@ -56,11 +48,7 @@ final class FontNameTests: XCTestCase {
|
|||||||
|
|
||||||
func test_uiKit_GeneratedMethod_noForbiddenCharacter() {
|
func test_uiKit_GeneratedMethod_noForbiddenCharacter() {
|
||||||
// Given
|
// Given
|
||||||
let fontName = FontName(
|
let fontName: FontName = "CircularStdBold"
|
||||||
postscriptName: "CircularStdBold",
|
|
||||||
filename: "CircularStd-Bold",
|
|
||||||
fileExtension: "ttf"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let property = fontName.getProperty(isStatic: false, isSwiftUI: false)
|
let property = fontName.getProperty(isStatic: false, isSwiftUI: false)
|
||||||
@ -77,11 +65,7 @@ final class FontNameTests: XCTestCase {
|
|||||||
|
|
||||||
func test_uiKit_GeneratedMethod_withForbiddenCharacter() {
|
func test_uiKit_GeneratedMethod_withForbiddenCharacter() {
|
||||||
// Given
|
// Given
|
||||||
let fontName = FontName(
|
let fontName: FontName = "[Circular_Std+Bold-Underline]"
|
||||||
postscriptName: "[Circular_Std+Bold-Underline]",
|
|
||||||
filename: "Circular_Std+Bold-Underline",
|
|
||||||
fileExtension: "ttf"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let property = fontName.getProperty(isStatic: false, isSwiftUI: false)
|
let property = fontName.getProperty(isStatic: false, isSwiftUI: false)
|
||||||
@ -98,11 +82,7 @@ final class FontNameTests: XCTestCase {
|
|||||||
|
|
||||||
func test_swiftUI_GeneratedProperty_noForbiddenCharacter() {
|
func test_swiftUI_GeneratedProperty_noForbiddenCharacter() {
|
||||||
// Given
|
// Given
|
||||||
let fontName = FontName(
|
let fontName: FontName = "CircularStdBold"
|
||||||
postscriptName: "CircularStdBold",
|
|
||||||
filename: "CircularStd-Bold",
|
|
||||||
fileExtension: "ttf"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let property = fontName.getProperty(isStatic: true, isSwiftUI: true)
|
let property = fontName.getProperty(isStatic: true, isSwiftUI: true)
|
||||||
@ -119,11 +99,7 @@ final class FontNameTests: XCTestCase {
|
|||||||
|
|
||||||
func test_swiftUI_GeneratedProperty_withForbiddenCharacter() {
|
func test_swiftUI_GeneratedProperty_withForbiddenCharacter() {
|
||||||
// Given
|
// Given
|
||||||
let fontName = FontName(
|
let fontName: FontName = "[Circular_Std+Bold-Underline]"
|
||||||
postscriptName: "[Circular_Std+Bold-Underline]",
|
|
||||||
filename: "Circular_Std+Bold-Underline",
|
|
||||||
fileExtension: "ttf"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let property = fontName.getProperty(isStatic: true, isSwiftUI: true)
|
let property = fontName.getProperty(isStatic: true, isSwiftUI: true)
|
||||||
@ -140,11 +116,7 @@ final class FontNameTests: XCTestCase {
|
|||||||
|
|
||||||
func test_swiftUI_GeneratedMethod_noForbiddenCharacter() {
|
func test_swiftUI_GeneratedMethod_noForbiddenCharacter() {
|
||||||
// Given
|
// Given
|
||||||
let fontName = FontName(
|
let fontName: FontName = "CircularStdBold"
|
||||||
postscriptName: "CircularStdBold",
|
|
||||||
filename: "CircularStd-Bold",
|
|
||||||
fileExtension: "ttf"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let property = fontName.getProperty(isStatic: false, isSwiftUI: true)
|
let property = fontName.getProperty(isStatic: false, isSwiftUI: true)
|
||||||
@ -161,11 +133,7 @@ final class FontNameTests: XCTestCase {
|
|||||||
|
|
||||||
func test_swiftUI_GeneratedMethod_withForbiddenCharacter() {
|
func test_swiftUI_GeneratedMethod_withForbiddenCharacter() {
|
||||||
// Given
|
// Given
|
||||||
let fontName = FontName(
|
let fontName: FontName = "[Circular_Std+Bold-Underline]"
|
||||||
postscriptName: "[Circular_Std+Bold-Underline]",
|
|
||||||
filename: "Circular_Std+Bold-Underline",
|
|
||||||
fileExtension: "ttf"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let property = fontName.getProperty(isStatic: false, isSwiftUI: true)
|
let property = fontName.getProperty(isStatic: false, isSwiftUI: true)
|
||||||
|
@ -14,8 +14,8 @@ final class FontPlistGeneratorTests: XCTestCase {
|
|||||||
func testGeneratedPlist() {
|
func testGeneratedPlist() {
|
||||||
// Given
|
// Given
|
||||||
let fontNames: [FontName] = [
|
let fontNames: [FontName] = [
|
||||||
FontName(postscriptName: "CircularStd-Regular", filename: "CircularStd-Regular", fileExtension: "ttf"),
|
"CircularStd-Regular",
|
||||||
FontName(postscriptName: "CircularStd-Bold", filename: "CircularStd-Bold", fileExtension: "ttf")
|
"CircularStd-Bold"
|
||||||
]
|
]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
@ -25,8 +25,8 @@ final class FontPlistGeneratorTests: XCTestCase {
|
|||||||
let expect = """
|
let expect = """
|
||||||
<key>UIAppFonts</key>
|
<key>UIAppFonts</key>
|
||||||
<array>
|
<array>
|
||||||
<string>CircularStd-Regular.ttf</string>
|
<string>CircularStd-Regular</string>
|
||||||
<string>CircularStd-Bold.ttf</string>
|
<string>CircularStd-Bold</string>
|
||||||
</array>
|
</array>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -14,8 +14,9 @@ final class ResgenCLITests: XCTestCase {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process available on Mac only
|
// Mac Catalyst won't have `Process`, but it is supported for executables.
|
||||||
#if os(macOS)
|
#if !targetEnvironment(macCatalyst)
|
||||||
|
|
||||||
let fooBinary = productsDirectory.appendingPathComponent("ResgenSwift")
|
let fooBinary = productsDirectory.appendingPathComponent("ResgenSwift")
|
||||||
|
|
||||||
let process = Process()
|
let process = Process()
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
//
|
|
||||||
// StringsFileGenerator+OldStringsFile.swift
|
|
||||||
// ResgenSwift
|
|
||||||
//
|
|
||||||
// Created by Thibaut Schmitt on 30/04/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
import ToolCore
|
|
||||||
|
|
||||||
extension StringsFileGeneratorTests {
|
|
||||||
|
|
||||||
static let appleStringsFileExpectationFr = """
|
|
||||||
/**
|
|
||||||
* Apple Strings File
|
|
||||||
* Generated by ResgenSwift \(ResgenSwiftVersion)
|
|
||||||
* Language: fr
|
|
||||||
*/
|
|
||||||
|
|
||||||
/********** section_one **********/
|
|
||||||
|
|
||||||
"s1_def_one" = "Section Un - Definition Un";
|
|
||||||
|
|
||||||
"s1_def_two" = "Section Un - Definition Deux";
|
|
||||||
|
|
||||||
/********** section_two **********/
|
|
||||||
|
|
||||||
"s2_def_one" = "Section Deux - Definition Un";
|
|
||||||
|
|
||||||
"s2_def_two" = "Section Deux - Definition Deux";
|
|
||||||
"""
|
|
||||||
|
|
||||||
static let appleStringsFileExpectationEn = """
|
|
||||||
/**
|
|
||||||
* Apple Strings File
|
|
||||||
* Generated by ResgenSwift \(ResgenSwiftVersion)
|
|
||||||
* Language: en
|
|
||||||
*/
|
|
||||||
|
|
||||||
/********** section_one **********/
|
|
||||||
|
|
||||||
"s1_def_one" = "Section One - Definition One";
|
|
||||||
|
|
||||||
"s1_def_two" = "Section One - Definition Two";
|
|
||||||
|
|
||||||
/********** section_two **********/
|
|
||||||
|
|
||||||
"s2_def_one" = "Section Two - Definition One";
|
|
||||||
|
|
||||||
"s2_def_two" = "Section Deux - Definition Deux";
|
|
||||||
"""
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
//
|
|
||||||
// StringsFileGenerator+R2ExtensionsExpectation.swift
|
|
||||||
// ResgenSwift
|
|
||||||
//
|
|
||||||
// Created by Thibaut Schmitt on 30/04/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
@testable import ResgenSwift
|
|
||||||
import ToolCore
|
|
||||||
|
|
||||||
extension StringsFileGeneratorTests {
|
|
||||||
|
|
||||||
static func getExtensionContentExpectation(
|
|
||||||
staticVar: Bool,
|
|
||||||
s1DefOneFr: String = "Section Un - Definition Un",
|
|
||||||
s1DefOneComment: String = "",
|
|
||||||
s1DefTwoFr: String = "Section Un - Definition Deux",
|
|
||||||
s1DefTwoComment: String = "",
|
|
||||||
s2DefOneFr: String = "Section Deux - Definition Un",
|
|
||||||
s2DefOneComment: String = "",
|
|
||||||
s2DefTwoFr: String = "Section Deux - Definition Deux",
|
|
||||||
s2DefTwoComment: String = "",
|
|
||||||
) -> String {
|
|
||||||
"""
|
|
||||||
// Generated by ResgenSwift.Strings.Stringium \(ResgenSwiftVersion)
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
fileprivate let kStringsFileName = "myInputFilename"
|
|
||||||
|
|
||||||
extension GenStrings {
|
|
||||||
|
|
||||||
enum KeyStrings: String {
|
|
||||||
case s1_def_one = "s1_def_one"
|
|
||||||
case s1_def_two = "s1_def_two"
|
|
||||||
case s2_def_one = "s2_def_one"
|
|
||||||
case s2_def_two = "s2_def_two"
|
|
||||||
|
|
||||||
var keyPath: KeyPath<GenStrings, String> {
|
|
||||||
switch self {
|
|
||||||
case .s1_def_one: return \\GenStrings.s1_def_one
|
|
||||||
case .s1_def_two: return \\GenStrings.s1_def_two
|
|
||||||
case .s2_def_one: return \\GenStrings.s2_def_one
|
|
||||||
case .s2_def_two: return \\GenStrings.s2_def_two
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - section_one
|
|
||||||
|
|
||||||
/// Translation in fr :
|
|
||||||
/// \(s1DefOneFr)
|
|
||||||
///
|
|
||||||
/// Comment :
|
|
||||||
/// \(s1DefOneComment.isEmpty ? "No comment" : s1DefOneComment)
|
|
||||||
\(staticVar ? "static " : "")var s1_def_one: String {
|
|
||||||
NSLocalizedString("s1_def_one", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Un - Definition Un", comment: "\(s1DefOneComment)")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Translation in fr :
|
|
||||||
/// \(s1DefTwoFr)
|
|
||||||
///
|
|
||||||
/// Comment :
|
|
||||||
/// \(s1DefTwoComment.isEmpty ? "No comment" : s1DefTwoComment)
|
|
||||||
\(staticVar ? "static " : "")var s1_def_two: String {
|
|
||||||
NSLocalizedString("s1_def_two", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Un - Definition Deux", comment: "\(s1DefTwoComment)")
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - section_two
|
|
||||||
|
|
||||||
/// Translation in fr :
|
|
||||||
/// \(s2DefOneFr)
|
|
||||||
///
|
|
||||||
/// Comment :
|
|
||||||
/// \(s2DefOneComment.isEmpty ? "No comment" : s2DefOneComment)
|
|
||||||
\(staticVar ? "static " : "")var s2_def_one: String {
|
|
||||||
NSLocalizedString("s2_def_one", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Deux - Definition Un", comment: "\(s2DefOneComment)")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Translation in fr :
|
|
||||||
/// \(s2DefTwoFr)
|
|
||||||
///
|
|
||||||
/// Comment :
|
|
||||||
/// \(s2DefTwoComment.isEmpty ? "No comment" : s2DefTwoComment)
|
|
||||||
\(staticVar ? "static " : "")var s2_def_two: String {
|
|
||||||
NSLocalizedString("s2_def_two", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Deux - Definition Deux", comment: "\(s2DefTwoComment)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,129 +0,0 @@
|
|||||||
//
|
|
||||||
// StringsFileGenerator+XCStringsExpectation.swift
|
|
||||||
// ResgenSwift
|
|
||||||
//
|
|
||||||
// Created by Thibaut Schmitt on 30/04/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
@testable import ResgenSwift
|
|
||||||
|
|
||||||
extension XCStringDefinition {
|
|
||||||
|
|
||||||
enum Mock {
|
|
||||||
|
|
||||||
static func getDefinitionSectionOne(
|
|
||||||
defOneFr: String = "Section Un - Definition Un",
|
|
||||||
defOneEn: String = "Section One - Definition One",
|
|
||||||
defOneComment: String? = nil,
|
|
||||||
defTwoFr: String = "Section Un - Definition Deux",
|
|
||||||
defTwoEn: String = "Section One - Definition Two",
|
|
||||||
defTwoComment: String? = nil
|
|
||||||
) -> [XCStringDefinition] {
|
|
||||||
[
|
|
||||||
XCStringDefinition(
|
|
||||||
title: "s1_def_one",
|
|
||||||
content: XCStringDefinitionContent(
|
|
||||||
comment: defOneComment,
|
|
||||||
extractionState: "manual",
|
|
||||||
localizations: XCStringLocalizationContainer(
|
|
||||||
localizations: getXCStringLocalization(
|
|
||||||
defFr: defOneFr,
|
|
||||||
defEn: defOneEn
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
XCStringDefinition(
|
|
||||||
title: "s1_def_two",
|
|
||||||
content: XCStringDefinitionContent(
|
|
||||||
comment: defTwoComment,
|
|
||||||
extractionState: "manual",
|
|
||||||
localizations: XCStringLocalizationContainer(
|
|
||||||
localizations: getXCStringLocalization(
|
|
||||||
defFr: defTwoFr,
|
|
||||||
defEn: defTwoEn
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getDefinitionSectionTwo(
|
|
||||||
defOneFr: String = "Section Deux - Definition Un",
|
|
||||||
defOneEn: String = "Section Two - Definition One",
|
|
||||||
defOneComment: String? = nil,
|
|
||||||
defTwoFr: String = "Section Deux - Definition Deux",
|
|
||||||
defTwoEn: String? = nil,
|
|
||||||
defTwoComment: String? = nil
|
|
||||||
) -> [XCStringDefinition] {
|
|
||||||
[
|
|
||||||
XCStringDefinition(
|
|
||||||
title: "s2_def_one",
|
|
||||||
content: XCStringDefinitionContent(
|
|
||||||
comment: defOneComment,
|
|
||||||
extractionState: "manual",
|
|
||||||
localizations: XCStringLocalizationContainer(
|
|
||||||
localizations: getXCStringLocalization(
|
|
||||||
defFr: defOneFr,
|
|
||||||
defEn: defOneEn
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
XCStringDefinition(
|
|
||||||
title: "s2_def_two",
|
|
||||||
content: XCStringDefinitionContent(
|
|
||||||
comment: defTwoComment,
|
|
||||||
extractionState: "manual",
|
|
||||||
localizations: XCStringLocalizationContainer(
|
|
||||||
localizations: getXCStringLocalization(
|
|
||||||
defFr: defTwoFr,
|
|
||||||
defEn: defTwoEn ?? ""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Private methods
|
|
||||||
|
|
||||||
private static func getXCStringLocalization(
|
|
||||||
defFr: String,
|
|
||||||
defEn: String
|
|
||||||
) -> [XCStringLocalization] {
|
|
||||||
var localizations = [XCStringLocalization]()
|
|
||||||
|
|
||||||
if defFr.isEmpty == false {
|
|
||||||
localizations.append(
|
|
||||||
XCStringLocalization(
|
|
||||||
lang: "fr",
|
|
||||||
content: XCStringLocalizationLangContent(
|
|
||||||
stringUnit: DefaultStringUnit(
|
|
||||||
state: "translated",
|
|
||||||
value: defFr
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if defEn.isEmpty == false {
|
|
||||||
localizations.append(
|
|
||||||
XCStringLocalization(
|
|
||||||
lang: "en",
|
|
||||||
content: XCStringLocalizationLangContent(
|
|
||||||
stringUnit: DefaultStringUnit(
|
|
||||||
state: "translated",
|
|
||||||
value: defEn
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return localizations
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
//
|
|
||||||
// Section+Mock.swift
|
|
||||||
// ResgenSwift
|
|
||||||
//
|
|
||||||
// Created by Thibaut Schmitt on 30/04/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
@testable import ResgenSwift
|
|
||||||
|
|
||||||
extension Section {
|
|
||||||
|
|
||||||
enum Mock {
|
|
||||||
|
|
||||||
static func getSectionOne(
|
|
||||||
defOneFr: String = "Section Un - Definition Un",
|
|
||||||
defOneEn: String = "Section One - Definition One",
|
|
||||||
defOneComment: String? = nil,
|
|
||||||
defOneTag: [String] = ["ios","iosonly"],
|
|
||||||
defTwoFr: String = "Section Un - Definition Deux",
|
|
||||||
defTwoEn: String = "Section One - Definition Two",
|
|
||||||
defTwoComment: String? = nil,
|
|
||||||
defTwoTag: [String] = ["ios","iosonly"]
|
|
||||||
) -> Section {
|
|
||||||
let section = Section(name: "section_one")
|
|
||||||
section.definitions = [
|
|
||||||
Self.getDefinition(
|
|
||||||
name: "s1_def_one",
|
|
||||||
translations: ["fr": defOneFr,
|
|
||||||
"en": defOneEn],
|
|
||||||
tags: defOneTag,
|
|
||||||
comment: defOneComment
|
|
||||||
),
|
|
||||||
Self.getDefinition(
|
|
||||||
name: "s1_def_two",
|
|
||||||
translations: ["fr": defTwoFr,
|
|
||||||
"en": defTwoEn],
|
|
||||||
tags: defTwoTag,
|
|
||||||
comment: defTwoComment
|
|
||||||
)
|
|
||||||
]
|
|
||||||
return section
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getSectionTwo(
|
|
||||||
defOneFr: String = "Section Deux - Definition Un",
|
|
||||||
defOneEn: String = "Section Two - Definition One",
|
|
||||||
defOneComment: String? = nil,
|
|
||||||
defOneTag: [String] = ["ios","iosonly"],
|
|
||||||
defTwoFr: String = "Section Deux - Definition Deux",
|
|
||||||
defTwoEn: String? = nil,
|
|
||||||
defTwoComment: String? = nil,
|
|
||||||
defTwoTag: [String] = ["notranslation"]
|
|
||||||
) -> Section {
|
|
||||||
let section = Section(name: "section_two")
|
|
||||||
let defTwoTranslations: [String: String] = {
|
|
||||||
var translations = ["fr": "Section Deux - Definition Deux"]
|
|
||||||
if let defTwoEn {
|
|
||||||
translations["en"] = defTwoEn
|
|
||||||
}
|
|
||||||
return translations
|
|
||||||
}()
|
|
||||||
section.definitions = [
|
|
||||||
Self.getDefinition(
|
|
||||||
name: "s2_def_one",
|
|
||||||
translations: ["fr": defOneFr,
|
|
||||||
"en": defOneEn],
|
|
||||||
tags: defOneTag,
|
|
||||||
comment: defOneComment
|
|
||||||
),
|
|
||||||
Self.getDefinition(
|
|
||||||
name: "s2_def_two",
|
|
||||||
translations: defTwoTranslations,
|
|
||||||
tags: defTwoTag,
|
|
||||||
comment: defTwoComment
|
|
||||||
)
|
|
||||||
]
|
|
||||||
return section
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Private methods
|
|
||||||
|
|
||||||
private static func getDefinition(
|
|
||||||
name: String,
|
|
||||||
translations: [String: String],
|
|
||||||
tags: [String],
|
|
||||||
comment: String? = nil
|
|
||||||
) -> Definition {
|
|
||||||
let definition = Definition(name: name)
|
|
||||||
definition.tags = tags
|
|
||||||
definition.translations = translations
|
|
||||||
definition.comment = comment
|
|
||||||
return definition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,489 +0,0 @@
|
|||||||
//
|
|
||||||
// StringsFileGeneratorTests.swift
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Created by Thibaut Schmitt on 06/09/2022.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import XCTest
|
|
||||||
import ToolCore
|
|
||||||
|
|
||||||
@testable import ResgenSwift
|
|
||||||
|
|
||||||
final class StringsFileGeneratorTests: XCTestCase {
|
|
||||||
|
|
||||||
// MARK: - Strings File Content
|
|
||||||
|
|
||||||
func testGenerateStringsFileContent() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = Section.Mock.getSectionOne()
|
|
||||||
let sectionTwo = Section.Mock.getSectionTwo()
|
|
||||||
|
|
||||||
// When
|
|
||||||
let stringsFileContentFr = StringsFileGenerator.generateStringsFileContent(
|
|
||||||
lang: "fr",
|
|
||||||
defaultLang: "fr",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
sections: [sectionOne, sectionTwo]
|
|
||||||
)
|
|
||||||
let stringsFileContentEn = StringsFileGenerator.generateStringsFileContent(
|
|
||||||
lang: "en",
|
|
||||||
defaultLang: "fr",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
sections: [sectionOne, sectionTwo]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
XCTAssertEqual(
|
|
||||||
stringsFileContentFr.adaptForXCTest(),
|
|
||||||
Self.appleStringsFileExpectationFr.adaptForXCTest()
|
|
||||||
)
|
|
||||||
XCTAssertEqual(
|
|
||||||
stringsFileContentEn.adaptForXCTest(),
|
|
||||||
Self.appleStringsFileExpectationEn.adaptForXCTest()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGenerateStringsFileContentWithComment() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = Section.Mock.getSectionOne(
|
|
||||||
defOneComment: "This is a comment",
|
|
||||||
defTwoComment: "This is a comment"
|
|
||||||
)
|
|
||||||
let sectionTwo = Section.Mock.getSectionTwo(
|
|
||||||
defOneComment: "This is a comment",
|
|
||||||
defTwoComment: "This is a comment"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
|
||||||
let stringsFileContentFr = StringsFileGenerator.generateStringsFileContent(
|
|
||||||
lang: "fr",
|
|
||||||
defaultLang: "fr",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
sections: [sectionOne, sectionTwo]
|
|
||||||
)
|
|
||||||
let stringsFileContentEn = StringsFileGenerator.generateStringsFileContent(
|
|
||||||
lang: "en",
|
|
||||||
defaultLang: "fr",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
sections: [sectionOne, sectionTwo]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
XCTAssertEqual(
|
|
||||||
stringsFileContentFr.adaptForXCTest(),
|
|
||||||
Self.appleStringsFileExpectationFr.adaptForXCTest()
|
|
||||||
)
|
|
||||||
XCTAssertEqual(
|
|
||||||
stringsFileContentEn.adaptForXCTest(),
|
|
||||||
Self.appleStringsFileExpectationEn.adaptForXCTest()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - XcString File Content
|
|
||||||
|
|
||||||
func testGenerateXcStringsRootObject() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = Section.Mock.getSectionOne()
|
|
||||||
let sectionTwo = Section.Mock.getSectionTwo(
|
|
||||||
defTwoEn: "Section Two - Definition Two"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
|
||||||
let rootObject = StringsFileGenerator.generateRootObject(
|
|
||||||
langs: ["fr", "en"],
|
|
||||||
defaultLang: "en",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
sections: [sectionOne, sectionTwo]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
let expect =
|
|
||||||
Root(
|
|
||||||
sourceLanguage: "en",
|
|
||||||
strings: XCStringDefinitionContainer(
|
|
||||||
strings: [
|
|
||||||
XCStringDefinition(
|
|
||||||
title: "s1_def_one",
|
|
||||||
content: XCStringDefinitionContent(
|
|
||||||
extractionState: "manual",
|
|
||||||
localizations: XCStringLocalizationContainer(
|
|
||||||
localizations: [
|
|
||||||
XCStringLocalization(
|
|
||||||
lang: "en",
|
|
||||||
content: XCStringLocalizationLangContent(
|
|
||||||
stringUnit: DefaultStringUnit(
|
|
||||||
state: "translated",
|
|
||||||
value: "Section One - Definition One"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
XCStringLocalization(
|
|
||||||
lang: "fr",
|
|
||||||
content: XCStringLocalizationLangContent(
|
|
||||||
stringUnit: DefaultStringUnit(
|
|
||||||
state: "translated",
|
|
||||||
value: "Section Un - Definition Un"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
XCStringDefinition(
|
|
||||||
title: "s1_def_two",
|
|
||||||
content: XCStringDefinitionContent(
|
|
||||||
extractionState: "manual",
|
|
||||||
localizations: XCStringLocalizationContainer(
|
|
||||||
localizations: [
|
|
||||||
XCStringLocalization(
|
|
||||||
lang: "en",
|
|
||||||
content: XCStringLocalizationLangContent(
|
|
||||||
stringUnit: DefaultStringUnit(
|
|
||||||
state: "translated",
|
|
||||||
value: "Section One - Definition Two"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
XCStringLocalization(
|
|
||||||
lang: "fr",
|
|
||||||
content: XCStringLocalizationLangContent(
|
|
||||||
stringUnit: DefaultStringUnit(
|
|
||||||
state: "translated",
|
|
||||||
value: "Section Un - Definition Deux"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
XCStringDefinition(
|
|
||||||
title: "s2_def_one",
|
|
||||||
content: XCStringDefinitionContent(
|
|
||||||
extractionState: "manual",
|
|
||||||
localizations: XCStringLocalizationContainer(
|
|
||||||
localizations: [
|
|
||||||
XCStringLocalization(
|
|
||||||
lang: "en",
|
|
||||||
content: XCStringLocalizationLangContent(
|
|
||||||
stringUnit: DefaultStringUnit(
|
|
||||||
state: "translated",
|
|
||||||
value: "Section Two - Definition One"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
XCStringLocalization(
|
|
||||||
lang: "fr",
|
|
||||||
content: XCStringLocalizationLangContent(
|
|
||||||
stringUnit: DefaultStringUnit(
|
|
||||||
state: "translated",
|
|
||||||
value: "Section Deux - Definition Un"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
XCStringDefinition(
|
|
||||||
title: "s2_def_two",
|
|
||||||
content: XCStringDefinitionContent(
|
|
||||||
extractionState: "manual",
|
|
||||||
localizations: XCStringLocalizationContainer(
|
|
||||||
localizations: [
|
|
||||||
XCStringLocalization(
|
|
||||||
lang: "en",
|
|
||||||
content: XCStringLocalizationLangContent(
|
|
||||||
stringUnit: DefaultStringUnit(
|
|
||||||
state: "translated",
|
|
||||||
value: "Section Two - Definition Two"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
XCStringLocalization(
|
|
||||||
lang: "fr",
|
|
||||||
content: XCStringLocalizationLangContent(
|
|
||||||
stringUnit: DefaultStringUnit(
|
|
||||||
state: "translated",
|
|
||||||
value: "Section Two - Definition Two"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
version: "1.0"
|
|
||||||
)
|
|
||||||
|
|
||||||
XCTAssertEqual(rootObject, expect)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGenerateXcStringsRootObjectWithEmptyTranslations() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = Section.Mock.getSectionOne(
|
|
||||||
defOneFr: "",
|
|
||||||
defTwoFr: ""
|
|
||||||
)
|
|
||||||
let sectionTwo = Section.Mock.getSectionTwo(
|
|
||||||
defOneFr: "",
|
|
||||||
defTwoFr: "",
|
|
||||||
defTwoEn: "Section Two - Definition Two"
|
|
||||||
)
|
|
||||||
// By default Section2.s2_def_two has a fr value => remove it
|
|
||||||
sectionTwo.definitions
|
|
||||||
.first { def in
|
|
||||||
def.name == "s2_def_two"
|
|
||||||
}?
|
|
||||||
.translations.removeValue(forKey: "fr")
|
|
||||||
|
|
||||||
// When
|
|
||||||
let rootObject = StringsFileGenerator.generateRootObject(
|
|
||||||
langs: ["fr", "en"],
|
|
||||||
defaultLang: "en",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
sections: [sectionOne, sectionTwo]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
let expect =
|
|
||||||
Root(
|
|
||||||
sourceLanguage: "en",
|
|
||||||
strings: XCStringDefinitionContainer(
|
|
||||||
strings: [
|
|
||||||
XCStringDefinition.Mock.getDefinitionSectionOne(
|
|
||||||
defOneFr: "",
|
|
||||||
defTwoFr: "",
|
|
||||||
),
|
|
||||||
XCStringDefinition.Mock.getDefinitionSectionTwo(
|
|
||||||
defOneFr: "",
|
|
||||||
defTwoFr: "Section Two - Definition Two",
|
|
||||||
defTwoEn: "Section Two - Definition Two",
|
|
||||||
)
|
|
||||||
]
|
|
||||||
.flatMap { $0 }
|
|
||||||
),
|
|
||||||
version: "1.0"
|
|
||||||
)
|
|
||||||
|
|
||||||
XCTAssertEqual(rootObject, expect)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGenerateXcStringsRootObjectWithNoTranslations() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = Section.Mock.getSectionOne(
|
|
||||||
defOneFr: "",
|
|
||||||
defOneEn: "",
|
|
||||||
defTwoFr: "",
|
|
||||||
defTwoEn : ""
|
|
||||||
)
|
|
||||||
let sectionTwo = Section.Mock.getSectionTwo(
|
|
||||||
defOneFr: "",
|
|
||||||
defOneEn: "",
|
|
||||||
defTwoFr: "",
|
|
||||||
defTwoEn : ""
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
|
||||||
let rootObject = StringsFileGenerator.generateRootObject(
|
|
||||||
langs: ["fr", "en"],
|
|
||||||
defaultLang: "en",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
sections: [sectionOne, sectionTwo]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
let expect =
|
|
||||||
Root(
|
|
||||||
sourceLanguage: "en",
|
|
||||||
strings: XCStringDefinitionContainer(
|
|
||||||
strings: [
|
|
||||||
XCStringDefinition.Mock.getDefinitionSectionOne(
|
|
||||||
defOneFr: "",
|
|
||||||
defOneEn: "",
|
|
||||||
defTwoFr: "",
|
|
||||||
defTwoEn : ""
|
|
||||||
),
|
|
||||||
XCStringDefinition.Mock.getDefinitionSectionTwo(
|
|
||||||
defOneFr: "",
|
|
||||||
defOneEn: "",
|
|
||||||
defTwoFr: "",
|
|
||||||
defTwoEn : ""
|
|
||||||
)
|
|
||||||
]
|
|
||||||
.flatMap { $0 }
|
|
||||||
),
|
|
||||||
version: "1.0"
|
|
||||||
)
|
|
||||||
|
|
||||||
XCTAssertEqual(rootObject, expect)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGenerateXcStringsRootObjectWithComments() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = Section.Mock.getSectionOne(
|
|
||||||
defOneComment: "Comment 1",
|
|
||||||
defTwoComment: "Comment 2"
|
|
||||||
)
|
|
||||||
let sectionTwo = Section.Mock.getSectionTwo()
|
|
||||||
|
|
||||||
// When
|
|
||||||
let rootObject = StringsFileGenerator.generateRootObject(
|
|
||||||
langs: ["fr", "en"],
|
|
||||||
defaultLang: "fr",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
sections: [sectionOne, sectionTwo]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
let expect =
|
|
||||||
Root(
|
|
||||||
sourceLanguage: "fr",
|
|
||||||
strings: XCStringDefinitionContainer(
|
|
||||||
strings: [
|
|
||||||
XCStringDefinition.Mock.getDefinitionSectionOne(
|
|
||||||
defOneComment: "Comment 1",
|
|
||||||
defTwoComment: "Comment 2"
|
|
||||||
),
|
|
||||||
XCStringDefinition.Mock.getDefinitionSectionTwo(
|
|
||||||
// SourceLanguage is frn en definition should the same as fr
|
|
||||||
defTwoEn: "Section Deux - Definition Deux"
|
|
||||||
)
|
|
||||||
]
|
|
||||||
.flatMap { $0 }
|
|
||||||
),
|
|
||||||
version: "1.0"
|
|
||||||
)
|
|
||||||
|
|
||||||
XCTAssertEqual(rootObject, expect)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Extension Content
|
|
||||||
|
|
||||||
func testGeneratedExtensionContent() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = Section.Mock.getSectionOne()
|
|
||||||
let sectionTwo = Section.Mock.getSectionTwo()
|
|
||||||
|
|
||||||
// When
|
|
||||||
let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo],
|
|
||||||
defaultLang: "fr",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
staticVar: false,
|
|
||||||
inputFilename: "myInputFilename",
|
|
||||||
extensionName: "GenStrings",
|
|
||||||
extensionSuffix: "strings")
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
let expect = Self.getExtensionContentExpectation(
|
|
||||||
staticVar: false
|
|
||||||
)
|
|
||||||
|
|
||||||
if extensionContent != expect {
|
|
||||||
print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
|
|
||||||
}
|
|
||||||
XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGeneratedExtensionContentWithComment() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = Section.Mock.getSectionOne(
|
|
||||||
defOneComment: "This is a comment",
|
|
||||||
defTwoComment: "This is a comment"
|
|
||||||
)
|
|
||||||
let sectionTwo = Section.Mock.getSectionTwo(
|
|
||||||
defOneComment: "This is a comment",
|
|
||||||
defTwoComment: "This is a comment"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
|
||||||
let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo],
|
|
||||||
defaultLang: "fr",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
staticVar: false,
|
|
||||||
inputFilename: "myInputFilename",
|
|
||||||
extensionName: "GenStrings",
|
|
||||||
extensionSuffix: "strings")
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
let expect = Self.getExtensionContentExpectation(
|
|
||||||
staticVar: false,
|
|
||||||
s1DefOneComment: "This is a comment",
|
|
||||||
s1DefTwoComment: "This is a comment",
|
|
||||||
s2DefOneComment: "This is a comment",
|
|
||||||
s2DefTwoComment: "This is a comment",
|
|
||||||
)
|
|
||||||
|
|
||||||
if extensionContent != expect {
|
|
||||||
print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
|
|
||||||
}
|
|
||||||
XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Extension Content Static
|
|
||||||
func testGeneratedExtensionContentWithStaticVar() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = Section.Mock.getSectionOne()
|
|
||||||
let sectionTwo = Section.Mock.getSectionTwo()
|
|
||||||
|
|
||||||
// When
|
|
||||||
let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo],
|
|
||||||
defaultLang: "fr",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
staticVar: true,
|
|
||||||
inputFilename: "myInputFilename",
|
|
||||||
extensionName: "GenStrings",
|
|
||||||
extensionSuffix: "strings")
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
let expect = Self.getExtensionContentExpectation(
|
|
||||||
staticVar: true
|
|
||||||
)
|
|
||||||
|
|
||||||
if extensionContent != expect {
|
|
||||||
print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
|
|
||||||
}
|
|
||||||
XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGeneratedExtensionContentWithStaticVarWithComment() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = Section.Mock.getSectionOne(
|
|
||||||
defOneComment: "This is a comment",
|
|
||||||
defTwoComment: "This is a comment"
|
|
||||||
)
|
|
||||||
let sectionTwo = Section.Mock.getSectionTwo(
|
|
||||||
defOneComment: "This is a comment",
|
|
||||||
defTwoComment: "This is a comment"
|
|
||||||
)
|
|
||||||
|
|
||||||
// When
|
|
||||||
let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo],
|
|
||||||
defaultLang: "fr",
|
|
||||||
tags: ["ios", "iosonly", "notranslation"],
|
|
||||||
staticVar: true,
|
|
||||||
inputFilename: "myInputFilename",
|
|
||||||
extensionName: "GenStrings",
|
|
||||||
extensionSuffix: "strings")
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
let expect = Self.getExtensionContentExpectation(
|
|
||||||
staticVar: true,
|
|
||||||
s1DefOneComment: "This is a comment",
|
|
||||||
s1DefTwoComment: "This is a comment",
|
|
||||||
s2DefOneComment: "This is a comment",
|
|
||||||
s2DefTwoComment: "This is a comment",
|
|
||||||
)
|
|
||||||
|
|
||||||
if extensionContent != expect {
|
|
||||||
print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
|
|
||||||
}
|
|
||||||
XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
1348
Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift
Normal file
1348
Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift
Normal file
File diff suppressed because it is too large
Load Diff
@ -57,18 +57,12 @@ final class TagsGeneratorTests: XCTestCase {
|
|||||||
|
|
||||||
/// Translation in ium :
|
/// Translation in ium :
|
||||||
/// Some translation
|
/// Some translation
|
||||||
///
|
|
||||||
/// Comment :
|
|
||||||
/// No comment
|
|
||||||
var s1_def_one: String {
|
var s1_def_one: String {
|
||||||
"Some translation"
|
"Some translation"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translation in ium :
|
/// Translation in ium :
|
||||||
/// Some translation
|
/// Some translation
|
||||||
///
|
|
||||||
/// Comment :
|
|
||||||
/// No comment
|
|
||||||
var s1_def_two: String {
|
var s1_def_two: String {
|
||||||
"Some translation"
|
"Some translation"
|
||||||
}
|
}
|
||||||
@ -77,9 +71,6 @@ final class TagsGeneratorTests: XCTestCase {
|
|||||||
|
|
||||||
/// Translation in ium :
|
/// Translation in ium :
|
||||||
/// Some translation
|
/// Some translation
|
||||||
///
|
|
||||||
/// Comment :
|
|
||||||
/// No comment
|
|
||||||
var s2_def_one: String {
|
var s2_def_one: String {
|
||||||
"Some translation"
|
"Some translation"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user