diff --git a/.codecov.yml b/.codecov.yml deleted file mode 100644 index 3c9edbf..0000000 --- a/.codecov.yml +++ /dev/null @@ -1,20 +0,0 @@ -coverage: - precision: 2 - round: down - range: "70...100" - - status: - project: - default: - threshold: 1.0% - changes: - default: - threshold: 1.0% - patch: off - -comment: - layout: "flags, files" - behavior: new - -ignore: - - Tests/**/* diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 77f1fe7..3ec7d47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,21 +15,21 @@ env: jobs: BuildAndTests: name: Build & Tests - runs-on: macOS-12 + runs-on: macOS-15 env: - DEVELOPER_DIR: /Applications/Xcode_14.0.1.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_16.4.app XCODE_PROJECT: URLQueryCoder.xcodeproj IOS_SCHEME: URLQueryCoder iOS - IOS_DESTINATION: OS=16.0,name=iPhone 14 + IOS_DESTINATION: OS=18.5,name=iPhone 16 IOS_RESULT_PATH: xcodebuild-ios.xcresult MACOS_SCHEME: URLQueryCoder macOS MACOS_DESTINATION: platform=macOS MACOS_RESULT_PATH: xcodebuild-macos.xcresult TVOS_SCHEME: URLQueryCoder tvOS - TVOS_DESTINATION: OS=16.0,name=Apple TV + TVOS_DESTINATION: OS=18.5,name=Apple TV TVOS_RESULT_PATH: xcodebuild-tvos.xcresult WATCHOS_SCHEME: URLQueryCoder watchOS - WATCHOS_DESTINATION: OS=9.0,name=Apple Watch Series 8 (45mm) + WATCHOS_DESTINATION: OS=11.5,name=Apple Watch Series 10 (42mm) WATCHOS_RESULT_PATH: xcodebuild-watchos.xcresult SKIP_SWIFTLINT: YES DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }} @@ -83,7 +83,9 @@ jobs: Cocoapods: name: Cocoapods - runs-on: macOS-latest + runs-on: macOS-15 + env: + DEVELOPER_DIR: /Applications/Xcode_16.4.app steps: - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 @@ -96,7 +98,9 @@ jobs: SPM: name: Swift Package Manager - runs-on: macOS-latest + runs-on: macOS-15 + env: + DEVELOPER_DIR: /Applications/Xcode_16.4.app steps: - uses: actions/checkout@v3 - name: Build diff --git a/.gitignore b/.gitignore index 7615629..9f177a0 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,7 @@ fastlane/report.xml fastlane/Preview.html fastlane/screenshots/**/*.png fastlane/test_output + +# JetBrains IDE +.idea/ +*.iml \ No newline at end of file diff --git a/.swift-version b/.swift-version index 9ad974f..95ee81a 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -5.5 +5.9 diff --git a/.swiftlint.yml b/.swiftlint.yml index 2df45f6..41dcde9 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,11 +1,22 @@ included: + - Example - Sources - Tests -whitelist_rules: - - anyobject_protocol +excluded: + - "*/Pods" + +analyzer_rules: + - capture_variable + - typesafe_array_init + - unused_declaration + - unused_import + +only_rules: + - anonymous_argument_in_multiline_closure - array_init - - attributes + # - attributes + - blanket_disable_command - block_based_kvo - class_delegate_protocol - closing_brace @@ -16,7 +27,10 @@ whitelist_rules: - collection_alignment - colon - comma + - comma_inheritance + - comment_spacing - compiler_protocol_init + - computed_accessors_order - conditional_returns_on_newline - contains_over_filter_count - contains_over_filter_is_empty @@ -26,12 +40,17 @@ whitelist_rules: - convenience_type - custom_rules - cyclomatic_complexity + - direct_return - discarded_notification_center_observer + - discouraged_assert - discouraged_direct_init - discouraged_object_literal + - duplicate_conditions - duplicate_enum_cases - duplicate_imports + - duplicated_key_in_dictionary_literal - dynamic_inline + - empty_collection_literal - empty_count - empty_enum_arguments - empty_parameters @@ -39,21 +58,30 @@ whitelist_rules: - empty_string - empty_xctest_method - enum_case_associated_values_count + - explicit_acl - explicit_init - - extension_access_modifier + - explicit_top_level_acl + - fatal_error_message - file_header - file_length - file_name + - file_types_order - first_where - flatmap_over_map_reduce - for_where - force_try - function_body_length + - function_parameter_count - generic_type_name + - ibinspectable_in_extension - identical_operands - identifier_name - implicit_getter - - inert_defer + - implicit_return + - implicitly_unwrapped_optional + - inclusive_language + - indentation_width + - invalid_swiftlint_command - is_disjoint - joined_default_parameter - large_tuple @@ -69,54 +97,69 @@ whitelist_rules: - let_var_whitespace - line_length - literal_expression_end_indentation + - local_doc_comment - lower_acl_than_parent - mark - modifier_order - multiline_arguments - multiline_arguments_brackets + - multiline_function_chains - multiline_literal_brackets - multiline_parameters - multiline_parameters_brackets - multiple_closures_with_trailing_closure - nesting + - no_extension_access_modifier + - no_fallthrough_only - no_space_in_method_call + - non_overridable_class_declaration + - ns_number_init_as_function_reference - nsobject_prefer_isequal - number_separator - opening_brace - - operator_usage_whitespace - operator_whitespace + - operator_usage_whitespace - optional_enum_case_matching - orphaned_doc_comment - overridden_super_call - override_in_extension - pattern_matching_keywords + - period_spacing + - prefer_self_in_static_references - prefer_self_type_over_type_of_self + - prefer_zero_over_explicit_init - private_action - private_outlet - private_over_fileprivate + - private_subject + # - private_swiftui_state_property - private_unit_test + - prohibited_interface_builder - prohibited_super_call - protocol_property_accessors_order - - quick_discouraged_call - - quick_discouraged_focused_test - - quick_discouraged_pending_test - raw_value_for_camel_cased_codable_enum - reduce_boolean + - reduce_into - redundant_discardable_let - redundant_nil_coalescing - redundant_objc_attribute - redundant_optional_initialization + - redundant_self_in_closure - redundant_set_access_control - redundant_string_enum_value - redundant_type_annotation - redundant_void_return - return_arrow_whitespace + - self_binding + - self_in_property_initialization - shorthand_operator + - shorthand_optional_binding - single_test_class - sorted_first_last - statement_position - static_operator - superfluous_disable_command + - superfluous_else - switch_case_alignment - switch_case_on_newline - syntactic_sugar @@ -130,15 +173,17 @@ whitelist_rules: - type_body_length - type_contents_order - type_name + - unavailable_condition - unavailable_function + - unhandled_throwing_task - unneeded_break_in_switch + - unneeded_override + - unneeded_parentheses_in_closure_argument + - unneeded_synthesized_initializer - untyped_error_in_catch - - unused_capture_list - unused_closure_parameter - unused_control_flow_label - - unused_declaration - unused_enumerated - - unused_import - unused_optional_binding - unused_setter_value - valid_ibinspectable @@ -147,44 +192,58 @@ whitelist_rules: - vertical_whitespace - vertical_whitespace_between_cases - vertical_whitespace_closing_braces + - void_function_in_ternary - void_return - weak_delegate - - xct_specific_matcher - xctfail_message + - xct_specific_matcher - yoda_condition -attributes: - always_on_same_line: - - '@IBAction' - - '@IBOutlet' - - '@IBDesignable' - - '@IBInspectable' - - '@GKInspectable' - - '@NSCopying' - - '@NSManaged' - - '@dynamic' - - '@nonobjc' - - '@objc' - - '@objcMembers' - - '@testable' - always_on_line_above: - - '@UIApplicationMain' - - '@NSApplicationMain' - - '@dynamicMemberLookup' - - '@dynamicCallable' - - '@propertyWrapper' - - '@convention' - - '@frozen' - - '@available' - - '@discardableResult' - - '@inlinable' - - '@usableFromInline' - - '@warn_unqualified_access' - - '@requires_stored_property_inits' +# attributes: +# attributes_with_arguments_always_on_line_above: true +# always_on_same_line: +# - '@dynamic' +# - '@GKInspectable' +# - '@IBAction' +# - '@IBDesignable' +# - '@IBInspectable' +# - '@IBOutlet' +# - '@nonobjc' +# - '@NSCopying' +# - '@NSManaged' +# - '@objc' +# - '@objcMembers' +# - '@testable' +# always_on_line_above: +# - '@available' +# - '@convention' +# - '@discardableResult' +# - '@dynamicCallable' +# - '@dynamicMemberLookup' +# - '@frozen' +# - '@inlinable' +# - '@MainActor' +# - '@NSApplicationMain' +# - '@Published' +# - '@propertyWrapper' +# - '@requires_stored_property_inits' +# - '@UIApplicationMain' +# - '@usableFromInline' +# - '@warn_unqualified_access' + +blanket_disable_command: + allowed_rules: [] + always_blanket_disable: + - file_header + - file_length + - file_name + - file_name_no_space + - file_types_order + - single_test_class closure_body_length: - warning: 20 - error: 200 + warning: 30 + error: 300 collection_alignment: align_colons: false @@ -203,14 +262,18 @@ cyclomatic_complexity: discouraged_direct_init: types: + - AVAudioSession - Bundle + - NSError - UIDevice - - AVAudioSession discouraged_object_literal: image_literal: true color_literal: true +duplicate_conditions: + severity: warning + duplicate_enum_cases: severity: warning @@ -219,32 +282,54 @@ dynamic_inline: empty_count: severity: warning + only_after_dot: false + +empty_xctest_method: + test_parent_classes: + - XCTestCase + - QuickSpec enum_case_associated_values_count: - warning: 4 - error: 40 + warning: 6 + error: 60 + +explicit_init: + include_bare_init: true file_header: forbidden_pattern: ".?" file_length: - warning: 400 - error: 4000 + warning: 500 + error: 5000 ignore_comment_only_lines: true file_name: excluded: - main.swift prefix_pattern: '' - suffix_pattern: '[+][A-z][A-z]+' - nested_type_separator: '' + suffix_pattern: '([+][A-z][A-z]+)+' + nested_type_separator: '.' + +file_types_order: + order: + - supporting_type + - main_type + - extension + - preview_provider + - library_content_provider force_try: severity: warning function_body_length: - warning: 40 - error: 400 + warning: 50 + error: 500 + +function_parameter_count: + warning: 6 + error: 60 + ignores_default_parameters: false generic_type_name: min_length: @@ -253,20 +338,20 @@ generic_type_name: max_length: warning: 20 error: 200 - validates_start_with_lowercase: true excluded: - T - U - V + allowed_symbols: [] + validates_start_with_lowercase: warning identifier_name: min_length: warning: 2 - error: 1 + error: 0 max_length: - warning: 40 - error: 400 - validates_start_with_lowercase: true + warning: 50 + error: 500 excluded: - a - r @@ -278,15 +363,34 @@ identifier_name: - y - z - w + allowed_symbols: [_] + validates_start_with_lowercase: warning + +implicit_return: + included: + - closure + - function + - getter + - initializer + - subscript + +implicitly_unwrapped_optional: + mode: all_except_iboutlets + +indentation_width: + indentation_width: 4 + include_comments: true + include_compiler_directives: true + include_multiline_strings: false large_tuple: warning: 3 - error: 8 + error: 30 line_length: warning: 120 error: 1200 - ignores_urls: false + ignores_urls: true ignores_function_declarations: false ignores_comments: false ignores_interpolated_strings: false @@ -295,10 +399,10 @@ modifier_order: preferred_modifier_order: - acl - setterACL + - final - override - owned - mutators - - final - typeMethods - required - convenience @@ -313,15 +417,33 @@ nesting: type_level: warning: 1 error: 10 - statement_level: - warning: 4 - error: 40 + function_level: + warning: 2 + error: 20 + check_nesting_in_closures_and_statements: true + always_allow_one_type_in_functions: false + +no_extension_access_modifier: + severity: warning + +non_overridable_class_declaration: + final_class_modifier: final class number_separator: minimum_length: 5 minimum_fraction_length: 5 exclude_ranges: [] +opening_brace: + allow_multiline_func: false + +operator_usage_whitespace: + lines_look_around: 2 + skip_aligned_constants: false + allowed_no_space_operators: + - '...' + - '..<' + overridden_super_call: included: - '*' @@ -338,9 +460,17 @@ prohibited_super_call: - '*' excluded: [] +self_binding: + bind_identifier: self + shorthand_operator: severity: warning +single_test_class: + test_parent_classes: + - XCTestCase + - QuickSpec + statement_position: statement_mode: default @@ -357,6 +487,10 @@ trailing_whitespace: ignores_empty_lines: false ignores_comments: false +type_body_length: + warning: 450 + error: 4500 + type_contents_order: order: - associated_type @@ -369,15 +503,12 @@ type_contents_order: - ib_inspectable - instance_property - initializer + - deinitializer - ib_action - other_method - view_life_cycle_method - subscript -type_body_length: - warning: 400 - error: 4000 - type_name: min_length: warning: 3 @@ -385,16 +516,33 @@ type_name: max_length: warning: 50 error: 500 - validates_start_with_lowercase: true - -unused_optional_binding: - ignore_optional_try: false + excluded: + - ID + allowed_symbols: [] + validates_start_with_lowercase: warning + validate_protocols: true unused_declaration: severity: warning include_public_and_open: false +unused_import: + require_explicit_imports: false + allowed_transitive_imports: [] + always_keep_imports: [] + +unused_optional_binding: + ignore_optional_try: false + vertical_whitespace: max_empty_lines: 1 +vertical_whitespace_closing_braces: + only_enforce_before_trivial_lines: false + +xct_specific_matcher: + matchers: + - one-argument-asserts + - two-argument-asserts + warning_threshold: 100 diff --git a/.system-version b/.system-version new file mode 100644 index 0000000..b5a3208 --- /dev/null +++ b/.system-version @@ -0,0 +1 @@ +15.7 diff --git a/.xcode-runtime-version b/.xcode-runtime-version new file mode 100644 index 0000000..0034b65 --- /dev/null +++ b/.xcode-runtime-version @@ -0,0 +1 @@ +18.0 diff --git a/.xcode-version b/.xcode-version index 9dc0691..0d68f8a 100644 --- a/.xcode-version +++ b/.xcode-version @@ -1 +1 @@ -14.1 +16.0 diff --git a/Gemfile.lock b/Gemfile.lock index f05174a..c57ce84 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,52 +1,64 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.5) - rexml - activesupport (6.1.7) - concurrent-ruby (~> 1.0, >= 1.0.2) + CFPropertyList (3.0.9) + abbrev (0.1.2) + activesupport (7.2.3) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - tzinfo (~> 2.0) - zeitwerk (~> 2.3) - addressable (2.8.1) - public_suffix (>= 2.0.2, < 6.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + addressable (2.8.8) + public_suffix (>= 2.0.2, < 8.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) - artifactory (3.0.15) + artifactory (3.0.17) atomos (0.1.3) - aws-eventstream (1.2.0) - aws-partitions (1.655.0) - aws-sdk-core (3.166.0) - aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.5) + aws-eventstream (1.4.0) + aws-partitions (1.1199.0) + aws-sdk-core (3.240.0) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.992.0) + aws-sigv4 (~> 1.9) + base64 + bigdecimal jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.59.0) - aws-sdk-core (~> 3, >= 3.165.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.117.1) - aws-sdk-core (~> 3, >= 3.165.0) + logger + aws-sdk-kms (1.118.0) + aws-sdk-core (~> 3, >= 3.239.1) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.209.0) + aws-sdk-core (~> 3, >= 3.234.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.2) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.12.1) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) + base64 (0.2.0) + benchmark (0.5.0) + bigdecimal (4.0.1) claide (1.1.0) claide-plugins (0.9.2) cork nap open4 (~> 1.3) - cocoapods (1.11.3) + cocoapods (1.16.2) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.11.3) + cocoapods-core (= 1.16.2) cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.4.0, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.4.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) cocoapods-try (>= 1.1.0, < 2.0) colored2 (~> 3.1) escape (~> 0.0.4) @@ -54,10 +66,10 @@ GEM gh_inspector (~> 1.0) molinillo (~> 0.8.0) nap (~> 1.0) - ruby-macho (>= 1.0, < 3.0) - xcodeproj (>= 1.21.0, < 2.0) - cocoapods-core (1.11.3) - activesupport (>= 5.0, < 7) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.27.0, < 2.0) + cocoapods-core (1.16.2) + activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) concurrent-ruby (~> 1.1) @@ -67,7 +79,7 @@ GEM public_suffix (~> 4.0) typhoeus (~> 1.0) cocoapods-deintegrate (1.0.5) - cocoapods-downloader (1.6.3) + cocoapods-downloader (2.1) cocoapods-plugins (1.0.0) nap cocoapods-search (1.0.1) @@ -79,43 +91,46 @@ GEM colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) - concurrent-ruby (1.1.10) + concurrent-ruby (1.3.6) + connection_pool (2.5.5) cork (0.3.0) colored2 (~> 3.1) - danger (9.0.0) + csv (3.3.5) + danger (9.5.3) + base64 (~> 0.2) claide (~> 1.0) claide-plugins (>= 0.9.2) - colored2 (~> 3.1) + colored2 (>= 3.1, < 5) cork (~> 0.1) - faraday (>= 0.9.0, < 2.0) + faraday (>= 0.9.0, < 3.0) faraday-http-cache (~> 2.0) - git (~> 1.7) - kramdown (~> 2.3) + git (>= 1.13, < 3.0) + kramdown (>= 2.5.1, < 3.0) kramdown-parser-gfm (~> 1.0) - no_proxy_fix - octokit (~> 5.0) - terminal-table (>= 1, < 4) + octokit (>= 4.0) + pstore (~> 0.1) + terminal-table (>= 1, < 5) danger-plugin-api (1.0.0) danger (> 2.0) - danger-swiftlint (0.30.2) + danger-swiftlint (0.37.4) danger rake (> 10) - thor (~> 0.19) - danger-xcode_summary (1.2.0) + thor (~> 1.4) + danger-xcode_summary (1.5.0) danger-plugin-api (~> 1.0) - xcresult (~> 0.2) + xcresult (~> 0.2.2) declarative (0.0.20) - digest-crc (0.6.4) + digest-crc (0.7.0) rake (>= 12.0.0, < 14.0.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) + domain_name (0.6.20240107) dotenv (2.8.1) + drb (2.2.3) emoji_regex (3.2.3) escape (0.0.4) ethon (0.15.0) ffi (>= 1.15.0) - excon (0.93.1) - faraday (1.10.2) + excon (0.112.0) + faraday (1.10.4) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -127,34 +142,37 @@ GEM faraday-rack (~> 1.0) faraday-retry (~> 1.0) ruby2_keywords (>= 0.0.4) - faraday-cookie_jar (0.0.7) + faraday-cookie_jar (0.0.8) faraday (>= 0.8.0) - http-cookie (~> 1.0.0) + http-cookie (>= 1.0.0) faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) + faraday-em_synchrony (1.0.1) faraday-excon (1.1.0) - faraday-http-cache (2.4.1) + faraday-http-cache (2.5.1) faraday (>= 0.8) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) - faraday-net_http (1.0.1) + faraday-multipart (1.2.0) + multipart-post (~> 2.0) + faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) faraday-retry (1.0.3) - faraday_middleware (1.2.0) + faraday_middleware (1.2.1) faraday (~> 1.0) - fastimage (2.2.6) - fastlane (2.210.1) + fastimage (2.4.0) + fastlane (2.230.0) CFPropertyList (>= 2.3, < 4.0.0) + abbrev (~> 0.1.2) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) aws-sdk-s3 (~> 1.0) babosa (>= 1.0.3, < 2.0.0) + base64 (~> 0.2.0) bundler (>= 1.12.0, < 3.0.0) - colored + colored (~> 1.2) commander (~> 4.6) + csv (~> 3.3) dotenv (>= 2.1.1, < 3.0.0) emoji_regex (>= 0.1, < 4.0) excon (>= 0.71.0, < 1.0.0) @@ -162,39 +180,49 @@ GEM faraday-cookie_jar (~> 0.0.6) faraday_middleware (~> 1.0) fastimage (>= 2.1.0, < 3.0.0) + fastlane-sirp (>= 1.0.0) gh_inspector (>= 1.1.2, < 2.0.0) google-apis-androidpublisher_v3 (~> 0.3) google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-env (>= 1.6.0, < 2.0.0) google-cloud-storage (~> 1.31) highline (~> 2.0) + http-cookie (~> 1.0.5) json (< 3.0.0) jwt (>= 2.1.0, < 3) + logger (>= 1.6, < 2.0) mini_magick (>= 4.9.4, < 5.0.0) - multipart-post (~> 2.0.0) + multipart-post (>= 2.0.0, < 3.0.0) + mutex_m (~> 0.3.0) naturally (~> 2.2) - optparse (~> 0.1.1) + nkf (~> 0.2.0) + optparse (>= 0.1.1, < 1.0.0) plist (>= 3.1.0, < 4.0.0) rubyzip (>= 2.0.0, < 3.0.0) - security (= 0.1.3) + security (= 0.1.5) simctl (~> 1.6.3) terminal-notifier (>= 2.0.0, < 3.0.0) - terminal-table (>= 1.4.5, < 2.0.0) + terminal-table (~> 3) tty-screen (>= 0.6.3, < 1.0.0) tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) - xcpretty (~> 0.3.0) - xcpretty-travis-formatter (>= 0.0.3) - ffi (1.15.5) + xcpretty (~> 0.4.1) + xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) + fastlane-sirp (1.0.0) + sysrandom (~> 1.0) + ffi (1.17.2) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - git (1.12.0) + git (2.3.3) + activesupport (>= 5.0) addressable (~> 2.8) + process_executer (~> 1.1) rchardet (~> 1.8) - google-apis-androidpublisher_v3 (0.30.0) - google-apis-core (>= 0.9.1, < 2.a) - google-apis-core (0.9.1) + google-apis-androidpublisher_v3 (0.54.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-core (0.11.3) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -202,129 +230,129 @@ GEM representable (~> 3.0) retriable (>= 2.0, < 4.a) rexml - webrick - google-apis-iamcredentials_v1 (0.16.0) - google-apis-core (>= 0.9.1, < 2.a) - google-apis-playcustomapp_v1 (0.12.0) - google-apis-core (>= 0.9.1, < 2.a) - google-apis-storage_v1 (0.19.0) - google-apis-core (>= 0.9.0, < 2.a) - google-cloud-core (1.6.0) - google-cloud-env (~> 1.0) + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-playcustomapp_v1 (0.13.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-storage_v1 (0.31.0) + google-apis-core (>= 0.11.0, < 2.a) + google-cloud-core (1.8.0) + google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.3.0) - google-cloud-storage (1.44.0) + google-cloud-errors (1.5.0) + google-cloud-storage (1.47.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.19.0) + google-apis-storage_v1 (~> 0.31.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.3.0) + googleauth (1.8.1) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) - memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.5) + http-cookie (1.0.8) domain_name (~> 0.5) - httpclient (2.8.3) - i18n (1.12.0) + httpclient (2.9.0) + mutex_m + i18n (1.14.8) concurrent-ruby (~> 1.0) - jmespath (1.6.1) - json (2.6.2) - jwt (2.5.0) - kramdown (2.4.0) - rexml + jmespath (1.6.2) + json (2.18.0) + jwt (2.10.2) + base64 + kramdown (2.5.1) + rexml (>= 3.3.9) kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) - memoist (0.16.2) - mini_magick (4.11.0) - mini_mime (1.1.2) - minitest (5.16.3) + logger (1.7.0) + mini_magick (4.13.2) + mini_mime (1.1.5) + minitest (5.27.0) molinillo (0.8.0) - multi_json (1.15.0) - multipart-post (2.0.0) - nanaimo (0.3.0) + multi_json (1.19.1) + multipart-post (2.4.1) + mutex_m (0.3.0) + nanaimo (0.4.0) nap (1.1.0) - naturally (2.2.1) + naturally (2.3.0) netrc (0.11.0) - no_proxy_fix (0.1.2) - octokit (5.6.1) + nkf (0.2.0) + octokit (10.0.0) faraday (>= 1, < 3) sawyer (~> 0.9) open4 (1.3.4) - optparse (0.1.1) + optparse (0.8.1) os (1.1.4) - plist (3.6.0) + plist (3.7.2) + process_executer (1.3.0) + pstore (0.2.0) public_suffix (4.0.7) - rake (13.0.6) - rchardet (1.8.0) + rake (13.3.1) + rchardet (1.10.0) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.5) - rouge (2.0.7) + rexml (3.4.4) + rouge (3.28.0) ruby-macho (2.5.1) ruby2_keywords (0.0.5) - rubyzip (2.3.2) - sawyer (0.9.2) + rubyzip (2.4.1) + sawyer (0.9.3) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) - security (0.1.3) - signet (0.17.0) + securerandom (0.4.1) + security (0.1.5) + signet (0.21.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) - jwt (>= 1.5, < 3.0) + jwt (>= 1.5, < 4.0) multi_json (~> 1.10) - simctl (1.6.8) + simctl (1.6.10) CFPropertyList naturally + sysrandom (1.0.5) terminal-notifier (2.0.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - thor (0.20.3) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + thor (1.4.0) trailblazer-option (0.1.2) tty-cursor (0.7.1) - tty-screen (0.8.1) + tty-screen (0.8.2) tty-spinner (0.9.3) tty-cursor (~> 0.7) - typhoeus (1.4.0) - ethon (>= 0.9.0) - tzinfo (2.0.5) + typhoeus (1.5.0) + ethon (>= 0.9.0, < 0.16.0) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) - unicode-display_width (1.8.0) - webrick (1.7.0) + unicode-display_width (2.6.0) word_wrap (1.0.0) xcode-install (2.8.1) claide (>= 0.9.1) fastlane (>= 2.1.0, < 3.0.0) - xcodeproj (1.22.0) + xcodeproj (1.27.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) - nanaimo (~> 0.3.0) - rexml (~> 3.2.4) - xcpretty (0.3.0) - rouge (~> 2.0.7) + nanaimo (~> 0.4.0) + rexml (>= 3.3.6, < 4.0) + xcpretty (0.4.1) + rouge (~> 3.28.0) xcpretty-json-formatter (0.1.1) xcpretty (~> 0.2, >= 0.0.7) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) - xcresult (0.2.1) - zeitwerk (2.6.4) + xcresult (0.2.4) PLATFORMS ruby @@ -339,4 +367,4 @@ DEPENDENCIES xcpretty-json-formatter BUNDLED WITH - 2.3.21 + 2.5.5 diff --git a/Mintfile b/Mintfile index 089790b..5167180 100644 --- a/Mintfile +++ b/Mintfile @@ -1 +1 @@ -realm/SwiftLint@0.49.1 +realm/SwiftLint@0.54.0 diff --git a/Package.swift b/Package.swift index 2d64384..5542c1a 100644 --- a/Package.swift +++ b/Package.swift @@ -1,24 +1,37 @@ -// swift-tools-version:5.5 +// swift-tools-version:6.0 import PackageDescription let package = Package( name: "URLQueryCoder", + platforms: [ + .macOS(.v12), + .iOS(.v13), + .tvOS(.v13), + .watchOS(.v6) + ], products: [ .library( name: "URLQueryCoder", targets: ["URLQueryCoder"] + ), + .library( + name: "URLQueryCoderDynamic", + type: .dynamic, + targets: ["URLQueryCoder"] ) ], targets: [ .target( name: "URLQueryCoder", - path: "Sources" + path: "Sources", + exclude: ["Info.plist"] ), .testTarget( name: "URLQueryCoderTests", dependencies: ["URLQueryCoder"], - path: "Tests" + path: "Tests", + exclude: ["Info.plist"] ) ], - swiftLanguageVersions: [.v5] + swiftLanguageModes: [.v6] ) diff --git a/Package@swift-5.9.swift b/Package@swift-5.9.swift new file mode 100644 index 0000000..e640bc2 --- /dev/null +++ b/Package@swift-5.9.swift @@ -0,0 +1,37 @@ +// swift-tools-version:5.9 +import PackageDescription + +let package = Package( + name: "URLQueryCoder", + platforms: [ + .macOS(.v12), + .iOS(.v13), + .tvOS(.v13), + .watchOS(.v6) + ], + products: [ + .library( + name: "URLQueryCoder", + targets: ["URLQueryCoder"] + ), + .library( + name: "URLQueryCoderDynamic", + type: .dynamic, + targets: ["URLQueryCoder"] + ) + ], + targets: [ + .target( + name: "URLQueryCoder", + path: "Sources", + exclude: ["Info.plist"] + ), + .testTarget( + name: "URLQueryCoderTests", + dependencies: ["URLQueryCoder"], + path: "Tests", + exclude: ["Info.plist"] + ) + ], + swiftLanguageVersions: [.v5] +) diff --git a/README.md b/README.md index 40b4d63..4740acf 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,14 @@ [![Carthage compatible](https://img.shields.io/badge/Carthage-Compatible-brightgreen.svg?style=flat)](https://github.com/Carthage/Carthage) [![SPM compatible](https://img.shields.io/badge/SPM-Compatible-brightgreen.svg?style=flat)](https://swift.org/package-manager/) [![Platforms](https://img.shields.io/cocoapods/p/URLQueryCoder)](https://developer.apple.com/discover/) -[![Xcode](https://img.shields.io/badge/Xcode-13-blue)](https://developer.apple.com/xcode) -[![Swift](https://img.shields.io/badge/Swift-5.5-orange)](https://swift.org) +[![Xcode](https://img.shields.io/badge/Xcode-16-blue)](https://developer.apple.com/xcode) +[![Swift](https://img.shields.io/badge/Swift-5.9-orange)](https://swift.org) [![License](https://img.shields.io/github/license/almazrafi/URLQueryCoder)](https://opensource.org/licenses/MIT) ## Requirements -- iOS 12.0+ / macOS 10.14+ / watchOS 5.0+ / tvOS 12.0+ -- Xcode 13.0+ -- Swift 5.5+ +- iOS 13.0+ / macOS 11.5+ / watchOS 6.0+ / tvOS 13.0+ +- Xcode 16.4+ +- Swift 5.9+ ## Usage ```swift @@ -31,41 +31,6 @@ let user = try URLQueryDecoder().decode(User.self, from: query) ``` ## Installation -### CocoaPods -[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: -``` bash -$ gem install cocoapods -``` - -To integrate URLQueryCoder into your Xcode project using [CocoaPods](http://cocoapods.org), specify it in your `Podfile`: -``` ruby -platform :ios, '12.0' -use_frameworks! - -target '' do - pod 'URLQueryCoder' -end -``` - -Finally run the following command: -``` bash -$ pod install -``` - -### Carthage -[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. You can install Carthage with Homebrew using the following command: -``` bash -$ brew update -$ brew install carthage -``` - -To integrate URLQueryCoder into your Xcode project using Carthage, specify it in your `Cartfile`: -``` ogdl -github "almazrafi/URLQueryCoder" ~> 1.1.0 -``` - -Finally run `carthage update` to build the framework and drag the built `URLQueryCoder.framework` into your Xcode project. - ### Swift Package Manager The [Swift Package Manager](https://swift.org/package-manager/) is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies. @@ -78,7 +43,7 @@ and then specify `"URLQueryCoder"` as a dependency of the Target in which you wi Here's an example `Package.swift`: ``` swift -// swift-tools-version:5.5 +// swift-tools-version:5.9 import PackageDescription let package = Package( @@ -95,6 +60,41 @@ let package = Package( ) ``` +### Carthage +[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. You can install Carthage with Homebrew using the following command: +``` bash +$ brew update +$ brew install carthage +``` + +To integrate URLQueryCoder into your Xcode project using Carthage, specify it in your `Cartfile`: +``` ogdl +github "almazrafi/URLQueryCoder" ~> 1.1.0 +``` + +Finally run `carthage update` to build the framework and drag the built `URLQueryCoder.framework` into your Xcode project. + +### CocoaPods +[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: +``` bash +$ gem install cocoapods +``` + +To integrate URLQueryCoder into your Xcode project using [CocoaPods](http://cocoapods.org), specify it in your `Podfile`: +``` ruby +platform :ios, '13.0' +use_frameworks! + +target '' do + pod 'URLQueryCoder' +end +``` + +Finally run the following command: +``` bash +$ pod install +``` + ## Communication - If you need help, open an issue. - If you found a bug, open an issue. diff --git a/Scripts/Bootstrap/aria2.sh b/Scripts/Bootstrap/aria2.sh new file mode 100755 index 0000000..ffab97c --- /dev/null +++ b/Scripts/Bootstrap/aria2.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +readonly arguments=$@ +readonly script_path="$( cd "$( dirname "$0" )" && pwd )" + +source "${script_path}/common.sh" + +echo "Checking ${xcode_style}aria2${default_style} installation:" + +brew_install_if_needed aria2 "$arguments" + +echo "" diff --git a/Scripts/Bootstrap/common.sh b/Scripts/Bootstrap/common.sh index e463e9e..45f6522 100755 --- a/Scripts/Bootstrap/common.sh +++ b/Scripts/Bootstrap/common.sh @@ -18,9 +18,7 @@ readonly homebrew_style='\033[38;5;208m' readonly rbenv_style='\033[38;5;43m' readonly ruby_style='\033[38;5;89m' readonly bundler_style='\033[38;5;45m' -readonly swiftenv_style='\033[38;5;226m' readonly swift_style='\033[38;5;208m' -readonly spm_style='\033[38;5;202m' readonly mint_style='\033[0;38;5;77m' readonly congratulations_style='\033[38;5;48m' diff --git a/Scripts/Bootstrap/gemfile.sh b/Scripts/Bootstrap/gemfile.sh index 6e6be8f..4187c70 100755 --- a/Scripts/Bootstrap/gemfile.sh +++ b/Scripts/Bootstrap/gemfile.sh @@ -5,6 +5,25 @@ readonly script_path="$( cd "$( dirname "$0" )" && pwd )" source "${script_path}/common.sh" +readonly shell_all_local_line="export LC_ALL=en_US.UTF-8" +readonly shell_default_local_line="export LANG=en_US.UTF-8" + +setup_shell() { + local shell_profile_path=$1 + + if [[ ! -f "${shell_profile_path}" ]]; then + > "${shell_profile_path}" + fi + + if [[ $(grep -L "^${shell_all_local_line}" "${shell_profile_path}") ]]; then + echo "${shell_all_local_line}" >> "${shell_profile_path}" + fi + + if [[ $(grep -L "^${shell_default_local_line}" "${shell_profile_path}") ]]; then + echo "${shell_default_local_line}" >> "${shell_profile_path}" + fi +} + if [[ "$(uname -m)" == "arm64" ]]; then eval "$(/opt/homebrew/bin/brew shellenv)" fi @@ -21,4 +40,6 @@ else assert_failure '(cd "${root_path}" && bundle install)' fi +setup_shell "${HOME}/.zshrc" + echo "" diff --git a/Scripts/Bootstrap/homebrew.sh b/Scripts/Bootstrap/homebrew.sh index 0f26f6c..e2f6b67 100755 --- a/Scripts/Bootstrap/homebrew.sh +++ b/Scripts/Bootstrap/homebrew.sh @@ -14,7 +14,7 @@ setup_shell() { > "${shell_profile_path}" fi - if [[ $(grep -L "${shell_init_line}" "${shell_profile_path}") ]]; then + if [[ $(grep -L "^${shell_init_line}" "${shell_profile_path}") ]]; then echo "${shell_init_line}" >> "${shell_profile_path}" fi } diff --git a/Scripts/Bootstrap/macos.sh b/Scripts/Bootstrap/macos.sh index 8b2d85d..68ac8d5 100755 --- a/Scripts/Bootstrap/macos.sh +++ b/Scripts/Bootstrap/macos.sh @@ -10,7 +10,7 @@ plain_version() { echo "Checking ${macos_style}macOS${default_style} version:" -readonly macos_required_version='11.3.0' +readonly macos_required_version=$(cat "${root_path}"/.system-version) readonly macos_version=$(/usr/bin/sw_vers -productVersion 2>&1) if [ "$(plain_version ${macos_version})" -lt "$(plain_version ${macos_required_version})" ]; then diff --git a/Scripts/Bootstrap/mint.sh b/Scripts/Bootstrap/mint.sh index 5340701..7c17246 100755 --- a/Scripts/Bootstrap/mint.sh +++ b/Scripts/Bootstrap/mint.sh @@ -15,11 +15,11 @@ setup_shell() { > "${shell_profile_path}" fi - if [[ $(grep -L "${shell_mint_path_line}" "${shell_profile_path}") ]]; then + if [[ $(grep -L "^${shell_mint_path_line}" "${shell_profile_path}") ]]; then echo "${shell_mint_path_line}" >> "${shell_profile_path}" fi - if [[ $(grep -L "${shell_mint_link_path_line}" "${shell_profile_path}") ]]; then + if [[ $(grep -L "^${shell_mint_link_path_line}" "${shell_profile_path}") ]]; then echo "${shell_mint_link_path_line}" >> "${shell_profile_path}" fi } @@ -29,8 +29,4 @@ echo "Checking ${mint_style}Mint${default_style} installation:" brew_install_if_needed mint "$arguments" setup_shell "${HOME}/.zshrc" -if [[ -f "${HOME}/.bash_profile" ]]; then - setup_shell "${HOME}/.bash_profile" -fi - echo "" diff --git a/Scripts/Bootstrap/rbenv.sh b/Scripts/Bootstrap/rbenv.sh index 587f85e..e19ccfa 100755 --- a/Scripts/Bootstrap/rbenv.sh +++ b/Scripts/Bootstrap/rbenv.sh @@ -16,31 +16,28 @@ setup_shell() { > "${shell_profile_path}" fi - if [[ $(grep -L "${shell_init_line}" "${shell_profile_path}") ]]; then + if [[ $(grep -L "^${shell_init_line}" "${shell_profile_path}") ]]; then echo "${shell_init_line}" >> "${shell_profile_path}" fi } cleanup() { - rm -rf $doctor_temp_path; + rm -rf "${doctor_temp_path}" } trap cleanup EXIT echo "Checking ${rbenv_style}rbenv${default_style} installation:" -brew_install_if_needed rbenv +brew_install_if_needed rbenv "${arguments}" setup_shell "${HOME}/.zshrc" -if [[ -f "${HOME}/.bash_profile" ]]; then - setup_shell "${HOME}/.bash_profile" -fi - eval "$(rbenv init -)" if [[ " ${arguments[*]} " == *" ${verify_flag} "* ]]; then echo "" echo " Verifying that rbenv is properly set up..." + curl -fsSL "${doctor_url}" > "${doctor_temp_path}" 2> /dev/null rbenv_doctor_exit_code=$? diff --git a/Scripts/Bootstrap/spm.sh b/Scripts/Bootstrap/spm.sh index 61a24a7..39041dc 100755 --- a/Scripts/Bootstrap/spm.sh +++ b/Scripts/Bootstrap/spm.sh @@ -9,14 +9,7 @@ if [[ "$(uname -m)" == "arm64" ]]; then eval "$(/opt/homebrew/bin/brew shellenv)" fi -eval "$(swiftenv init -)" - -if [[ " ${arguments[*]} " == *" ${update_flag} "* ]]; then - echo "Updating ${spm_style}Swift packages${default_style} specified in Package.swift..." - assert_failure '(cd "${root_path}" && swift package update)' -else - echo "Resolving ${spm_style}Swift packages${default_style} specified in Package.swift..." - assert_failure '(cd "${root_path}" && swift package resolve)' -fi +echo "Resolving ${swift_style}Swift packages${default_style} specified in Package.swift..." +assert_failure '(cd "${root_path}" && swift package resolve)' echo "" diff --git a/Scripts/Bootstrap/swift.sh b/Scripts/Bootstrap/swift.sh deleted file mode 100755 index b0a708d..0000000 --- a/Scripts/Bootstrap/swift.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -readonly script_path="$( cd "$( dirname "$0" )" && pwd )" - -source "${script_path}/common.sh" - -echo "Checking ${swift_style}Swift${default_style} version:" - -if [[ "$(uname -m)" == "arm64" ]]; then - eval "$(/opt/homebrew/bin/brew shellenv)" -fi - -eval "$(swiftenv init -)" - -readonly swift_required_version=$(cat "${root_path}"/.swift-version) -readonly swift_versions=($(swiftenv versions 2>&1)) - -if [[ " ${swift_versions[@]} " =~ " ${swift_required_version} " ]]; then - echo " Required Swift version ($swift_required_version) already installed." -else - echo " Required Swift version ($swift_required_version) not found. Installing..." - assert_failure '(cd "${root_path}" && swiftenv install $swift_required_version)' - assert_warning '(cd "${root_path}" && swiftenv rehash)' -fi - -echo "" diff --git a/Scripts/Bootstrap/swiftenv.sh b/Scripts/Bootstrap/swiftenv.sh deleted file mode 100755 index 7b7be47..0000000 --- a/Scripts/Bootstrap/swiftenv.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -readonly arguments=$@ -readonly script_path="$( cd "$( dirname "$0" )" && pwd )" - -source "${script_path}/common.sh" - -readonly shell_init_line='if which swiftenv > /dev/null; then eval "$(swiftenv init -)"; fi' - -setup_shell() { - local shell_profile_path=$1 - - if [[ ! -f "${shell_profile_path}" ]]; then - > "${shell_profile_path}" - fi - - if [[ $(grep -L "${shell_init_line}" "${shell_profile_path}") ]]; then - echo "${shell_init_line}" >> "${shell_profile_path}" - fi -} - -echo "Checking ${swiftenv_style}swiftenv${default_style} installation:" - -brew_install_if_needed kylef/formulae/swiftenv "$arguments" -setup_shell "${HOME}/.zshrc" - -if [[ -f "${HOME}/.bash_profile" ]]; then - setup_shell "${HOME}/.bash_profile" -fi - -eval "$(swiftenv init -)" - -echo "" diff --git a/Scripts/Bootstrap/xcode.sh b/Scripts/Bootstrap/xcode.sh index c851f64..0957c75 100755 --- a/Scripts/Bootstrap/xcode.sh +++ b/Scripts/Bootstrap/xcode.sh @@ -11,7 +11,7 @@ while [[ "$#" -gt 0 ]]; do done if [ -n "${sudo_password}" ]; then - echo "${sudo_password}" | sudo -S -E "$0" "$@" + echo "${sudo_password}" | sudo -S -E "$0" exit $? fi @@ -25,23 +25,44 @@ if [[ "$(uname -m)" == "arm64" ]]; then eval "$(/opt/homebrew/bin/brew shellenv)" fi -eval "$(rbenv init -)" - readonly xcode_required_version=$(cat "${root_path}"/.xcode-version) -readonly xcode_version=($(bundle exec xcversion selected 2> /dev/null | sed -n 's/Xcode \(.*\)/\1/p')) +readonly xcode_installed_versions=($(xcodes installed 2>&1)) + +if [[ " ${xcode_installed_versions[@]} " =~ " ${xcode_required_version} " ]]; then + readonly xcode_selected_version=$(xcodes installed 2>&1 | sed -n '/Selected/p') -if [[ "$xcode_version" == "$xcode_required_version" ]]; then - echo " Required Xcode version ($xcode_required_version) already installed." + if [[ " ${xcode_selected_version} " =~ " ${xcode_required_version} " ]]; then + echo " Required Xcode version (${xcode_required_version}) already installed and selected." + else + echo " Required Xcode version (${xcode_required_version}) already installed. Selecting..." + assert_failure '(xcodes select "${xcode_required_version}")' + fi else echo " Required Xcode version ($xcode_required_version) not found. Installing..." - bundle exec xcversion update - bundle exec xcversion install ${xcode_required_version} + assert_failure 'xcodes update' + + if [ -n "${FASTLANE_SESSION}" ]; then + xcodes install "${xcode_required_version}" --use-fastlane-auth + else + xcodes install "${xcode_required_version}" + fi echo " Selecting Xcode version..." + assert_failure '(xcodes select "${xcode_required_version}")' - bundle exec xcversion select "${xcode_required_version}" - sudo xcodebuild -license accept + echo " Accepting license..." + assert_failure '(sudo xcodebuild -license accept)' +fi + +readonly xcode_runtime_required_version=$(cat "${root_path}"/.xcode-runtime-version) +readonly xcode_runtime_installed_versions=($(xcrun simctl runtime list 2>&1)) + +if [[ ! " ${xcode_runtime_installed_versions[@]} " =~ " ${xcode_runtime_required_version} " ]]; then + echo " Required Xcode runtime version (${xcode_runtime_required_version}) not found. Installing..." + xcodes runtimes install "iOS ${xcode_runtime_required_version}" +else + echo " Required Xcode runtime version (${xcode_runtime_required_version}) already installed." fi echo "" diff --git a/Scripts/Bootstrap/xcodes.sh b/Scripts/Bootstrap/xcodes.sh new file mode 100755 index 0000000..9422b7b --- /dev/null +++ b/Scripts/Bootstrap/xcodes.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +readonly arguments=$@ +readonly script_path="$( cd "$( dirname "$0" )" && pwd )" + +source "${script_path}/common.sh" + +echo "Checking ${xcode_style}xcodes${default_style} installation:" + +brew_install_if_needed xcodesorg/made/xcodes "$arguments" + +echo "" diff --git a/Scripts/Helpers/script-run.sh b/Scripts/Helpers/script-run.sh index 5b51133..bf1aa4b 100755 --- a/Scripts/Helpers/script-run.sh +++ b/Scripts/Helpers/script-run.sh @@ -19,7 +19,6 @@ run() { if which mint >/dev/null; then (cd "${root_path}" && mint run "$@") else - echo "error: Mint does not exist" - exit 1 + echo "warning: Mint does not exist" fi } diff --git a/Scripts/bootstrap.sh b/Scripts/bootstrap.sh index eab20c8..34f14df 100755 --- a/Scripts/bootstrap.sh +++ b/Scripts/bootstrap.sh @@ -15,11 +15,10 @@ readonly bootstrap_path="${script_path}/Bootstrap" "${bootstrap_path}/bundler.sh" --update "${bootstrap_path}/gemfile.sh" +"${bootstrap_path}/aria2.sh" --update +"${bootstrap_path}/xcodes.sh" --update "${bootstrap_path}/xcode.sh" -"${bootstrap_path}/swiftenv.sh" --update -"${bootstrap_path}/swift.sh" --update - "${bootstrap_path}/spm.sh" "${bootstrap_path}/mint.sh" --update diff --git a/Sources/.swiftlint.yml b/Sources/.swiftlint.yml deleted file mode 100644 index 89d7ea6..0000000 --- a/Sources/.swiftlint.yml +++ /dev/null @@ -1,6 +0,0 @@ -disabled_rules: - - extension_access_modifier - -opt_in_rules: - - explicit_acl - - explicit_top_level_acl diff --git a/Sources/Decoder/Options/URLQueryDataDecodingStrategy.swift b/Sources/Decoder/Options/URLQueryDataDecodingStrategy.swift index 6a12402..23fc095 100644 --- a/Sources/Decoder/Options/URLQueryDataDecodingStrategy.swift +++ b/Sources/Decoder/Options/URLQueryDataDecodingStrategy.swift @@ -1,7 +1,7 @@ import Foundation /// The strategies for decoding raw data. -public enum URLQueryDataDecodingStrategy { +public enum URLQueryDataDecodingStrategy: Sendable { /// The strategy that encodes data using the encoding specified by the data instance itself. case deferredToData @@ -10,5 +10,5 @@ public enum URLQueryDataDecodingStrategy { case base64 /// The strategy that decodes data using a user-defined function. - case custom((_ decoder: Decoder) throws -> Data) + case custom(@Sendable (_ decoder: Decoder) throws -> Data) } diff --git a/Sources/Decoder/Options/URLQueryDateDecodingStrategy.swift b/Sources/Decoder/Options/URLQueryDateDecodingStrategy.swift index ba616c5..9aee9d0 100644 --- a/Sources/Decoder/Options/URLQueryDateDecodingStrategy.swift +++ b/Sources/Decoder/Options/URLQueryDateDecodingStrategy.swift @@ -1,7 +1,7 @@ import Foundation /// The strategies available for formatting dates when decoding them from URL. -public enum URLQueryDateDecodingStrategy { +public enum URLQueryDateDecodingStrategy: Sendable { /// The strategy that uses formatting from the Date structure. case deferredToDate @@ -20,5 +20,5 @@ public enum URLQueryDateDecodingStrategy { case formatted(DateFormatter) /// The strategy that formats custom dates by calling a user-defined function. - case custom((_ decoder: Decoder) throws -> Date) + case custom(@Sendable (_ decoder: Decoder) throws -> Date) } diff --git a/Sources/Decoder/Options/URLQueryDecodingOptions.swift b/Sources/Decoder/Options/URLQueryDecodingOptions.swift index a33cc1e..5146159 100644 --- a/Sources/Decoder/Options/URLQueryDecodingOptions.swift +++ b/Sources/Decoder/Options/URLQueryDecodingOptions.swift @@ -2,8 +2,8 @@ import Foundation internal struct URLQueryDecodingOptions { - internal let dateDecodingStrategy: URLQueryDateDecodingStrategy - internal let dataDecodingStrategy: URLQueryDataDecodingStrategy - internal let nonConformingFloatDecodingStrategy: URLQueryNonConformingFloatDecodingStrategy - internal let keyDecodingStrategy: URLQueryKeyDecodingStrategy + internal var dateDecodingStrategy: URLQueryDateDecodingStrategy + internal var dataDecodingStrategy: URLQueryDataDecodingStrategy + internal var nonConformingFloatDecodingStrategy: URLQueryNonConformingFloatDecodingStrategy + internal var keyDecodingStrategy: URLQueryKeyDecodingStrategy } diff --git a/Sources/Decoder/Options/URLQueryKeyDecodingStrategy.swift b/Sources/Decoder/Options/URLQueryKeyDecodingStrategy.swift index 6187fed..f1a5be3 100644 --- a/Sources/Decoder/Options/URLQueryKeyDecodingStrategy.swift +++ b/Sources/Decoder/Options/URLQueryKeyDecodingStrategy.swift @@ -1,11 +1,11 @@ import Foundation /// The values that determine how to decode a type’s coding keys from URL query keys. -public enum URLQueryKeyDecodingStrategy { +public enum URLQueryKeyDecodingStrategy: Sendable { /// A key decoding strategy that doesn’t change key names during decoding. case useDefaultKeys /// A key decoding strategy defined by the closure you supply. - case custom((_ codingPath: [CodingKey]) -> CodingKey) + case custom(@Sendable (_ codingPath: [CodingKey]) -> CodingKey) } diff --git a/Sources/Decoder/Options/URLQueryNonConformingFloatDecodingStrategy.swift b/Sources/Decoder/Options/URLQueryNonConformingFloatDecodingStrategy.swift index 7d0cfd3..987b932 100644 --- a/Sources/Decoder/Options/URLQueryNonConformingFloatDecodingStrategy.swift +++ b/Sources/Decoder/Options/URLQueryNonConformingFloatDecodingStrategy.swift @@ -2,7 +2,7 @@ import Foundation /// The strategies for encoding nonconforming floating-point numbers, /// also known as IEEE 754 exceptional values. -public enum URLQueryNonConformingFloatDecodingStrategy { +public enum URLQueryNonConformingFloatDecodingStrategy: Sendable { /// The strategy that throws an error upon decoding an exceptional floating-point value. case `throw` diff --git a/Sources/Decoder/URLQueryDecoder.swift b/Sources/Decoder/URLQueryDecoder.swift index d9fea37..280235a 100644 --- a/Sources/Decoder/URLQueryDecoder.swift +++ b/Sources/Decoder/URLQueryDecoder.swift @@ -1,33 +1,44 @@ import Foundation -public struct URLQueryDecoder { +public final class URLQueryDecoder: Sendable { public static let `default` = URLQueryDecoder() - public var dateDecodingStrategy: URLQueryDateDecodingStrategy - public var dataDecodingStrategy: URLQueryDataDecodingStrategy - public var nonConformingFloatDecodingStrategy: URLQueryNonConformingFloatDecodingStrategy - public var keyDecodingStrategy: URLQueryKeyDecodingStrategy - public var userInfo: [CodingUserInfoKey: Any] + private let optionsMutex: Mutex + private let userInfoMutex: Mutex<[CodingUserInfoKey: Sendable]> + + public var dateDecodingStrategy: URLQueryDateDecodingStrategy { + get { optionsMutex.withLock { $0.dateDecodingStrategy } } + set { optionsMutex.withLock { $0.dateDecodingStrategy = newValue } } + } + + public var dataDecodingStrategy: URLQueryDataDecodingStrategy { + get { optionsMutex.withLock { $0.dataDecodingStrategy } } + set { optionsMutex.withLock { $0.dataDecodingStrategy = newValue } } + } + + public var nonConformingFloatDecodingStrategy: URLQueryNonConformingFloatDecodingStrategy { + get { optionsMutex.withLock { $0.nonConformingFloatDecodingStrategy } } + set { optionsMutex.withLock { $0.nonConformingFloatDecodingStrategy = newValue } } + } + + public var keyDecodingStrategy: URLQueryKeyDecodingStrategy { + get { optionsMutex.withLock { $0.keyDecodingStrategy } } + set { optionsMutex.withLock { $0.keyDecodingStrategy = newValue } } + } + + public var userInfo: [CodingUserInfoKey: Sendable] { + get { userInfoMutex.withLock { $0 } } + set { userInfoMutex.withLock { $0 = newValue } } + } public init( dateDecodingStrategy: URLQueryDateDecodingStrategy = .deferredToDate, dataDecodingStrategy: URLQueryDataDecodingStrategy = .base64, nonConformingFloatDecodingStrategy: URLQueryNonConformingFloatDecodingStrategy = .throw, keyDecodingStrategy: URLQueryKeyDecodingStrategy = .useDefaultKeys, - userInfo: [CodingUserInfoKey: Any] = [:] + userInfo: [CodingUserInfoKey: Sendable] = [:] ) { - self.dateDecodingStrategy = dateDecodingStrategy - self.dataDecodingStrategy = dataDecodingStrategy - self.nonConformingFloatDecodingStrategy = nonConformingFloatDecodingStrategy - self.keyDecodingStrategy = keyDecodingStrategy - self.userInfo = userInfo - } - - public func decode( - _ type: T.Type, - from query: String - ) throws -> T { let options = URLQueryDecodingOptions( dateDecodingStrategy: dateDecodingStrategy, dataDecodingStrategy: dataDecodingStrategy, @@ -35,6 +46,16 @@ public struct URLQueryDecoder { keyDecodingStrategy: keyDecodingStrategy ) + self.optionsMutex = Mutex(value: options) + self.userInfoMutex = Mutex(value: userInfo) + } + + public func decode( + _ type: T.Type, + from query: String + ) throws -> T { + let options = optionsMutex.withLock { $0 } + let deserializer = URLQueryDeserializer() let value = try deserializer.deserialize(query) diff --git a/Sources/Decoder/URLQueryDeserializer.swift b/Sources/Decoder/URLQueryDeserializer.swift index 225371f..fe2e3c5 100644 --- a/Sources/Decoder/URLQueryDeserializer.swift +++ b/Sources/Decoder/URLQueryDeserializer.swift @@ -20,7 +20,9 @@ internal final class URLQueryDeserializer { .map { index, part in if part.last == .rightSquareBracket { return String(part.dropLast()) - } else if key.first != .leftSquareBracket, index == .zero { + } + + if key.first != .leftSquareBracket, index == .zero { return String(part) } @@ -37,7 +39,7 @@ internal final class URLQueryDeserializer { _ value: Substring?, path: [String] ) throws -> URLQueryValue? { - guard let value = value else { + guard let value else { return nil } diff --git a/Sources/Decoder/URLQueryKeyedDecodingContainer.swift b/Sources/Decoder/URLQueryKeyedDecodingContainer.swift index 179a3de..d888129 100644 --- a/Sources/Decoder/URLQueryKeyedDecodingContainer.swift +++ b/Sources/Decoder/URLQueryKeyedDecodingContainer.swift @@ -46,14 +46,12 @@ internal final class URLQueryKeyedDecodingContainer: URLQueryVal } private func superDecoder(forAnyKey key: CodingKey) throws -> Decoder { - let decoder = URLQuerySingleValueDecodingContainer( + URLQuerySingleValueDecodingContainer( value: dictionary[key.stringValue], options: options, userInfo: userInfo, codingPath: codingPath.appending(key) ) - - return decoder } } @@ -151,9 +149,9 @@ extension URLQueryKeyedDecodingContainer: KeyedDecodingContainerProtocol { } } -private extension DecodingError { +extension DecodingError { - static func invalidValue( + fileprivate static func invalidValue( _ value: Any?, forKey key: Key, at codingPath: [CodingKey], diff --git a/Sources/Decoder/URLQuerySingleValueDecodingContainer.swift b/Sources/Decoder/URLQuerySingleValueDecodingContainer.swift index f767262..55310e8 100644 --- a/Sources/Decoder/URLQuerySingleValueDecodingContainer.swift +++ b/Sources/Decoder/URLQuerySingleValueDecodingContainer.swift @@ -122,9 +122,9 @@ extension URLQuerySingleValueDecodingContainer: Decoder { } } -private extension DecodingError { +extension DecodingError { - static func keyedContainerTypeMismatch( + fileprivate static func keyedContainerTypeMismatch( at codingPath: [CodingKey], value: URLQueryValue? ) -> Self { @@ -147,7 +147,7 @@ private extension DecodingError { return .typeMismatch([String: Any].self, Context(codingPath: codingPath, debugDescription: debugDescription)) } - static func unkeyedContainerTypeMismatch( + fileprivate static func unkeyedContainerTypeMismatch( at codingPath: [CodingKey], value: URLQueryValue? ) -> Self { diff --git a/Sources/Decoder/URLQueryValueDecoding.swift b/Sources/Decoder/URLQueryValueDecoding.swift index 90c4232..0be4883 100644 --- a/Sources/Decoder/URLQueryValueDecoding.swift +++ b/Sources/Decoder/URLQueryValueDecoding.swift @@ -276,9 +276,9 @@ extension URLQueryValueDecoding { } } -private extension DecodingError { +extension DecodingError { - static func invalidValue( + fileprivate static func invalidValue( _ component: URLQueryValue?, of type: Any.Type, at codingPath: [CodingKey] diff --git a/Sources/Encoder/Options/URLQueryArrayEncodingStrategy.swift b/Sources/Encoder/Options/URLQueryArrayEncodingStrategy.swift index ce71320..db697d1 100644 --- a/Sources/Encoder/Options/URLQueryArrayEncodingStrategy.swift +++ b/Sources/Encoder/Options/URLQueryArrayEncodingStrategy.swift @@ -1,6 +1,6 @@ import Foundation -public enum URLQueryArrayEncodingStrategy { +public enum URLQueryArrayEncodingStrategy: Sendable { case enumerated case unenumerated diff --git a/Sources/Encoder/Options/URLQueryBoolEncodingStrategy.swift b/Sources/Encoder/Options/URLQueryBoolEncodingStrategy.swift index 0ba7f79..b021c58 100644 --- a/Sources/Encoder/Options/URLQueryBoolEncodingStrategy.swift +++ b/Sources/Encoder/Options/URLQueryBoolEncodingStrategy.swift @@ -1,6 +1,6 @@ import Foundation -public enum URLQueryBoolEncodingStrategy { +public enum URLQueryBoolEncodingStrategy: Sendable { case numeric case literal diff --git a/Sources/Encoder/Options/URLQueryDataEncodingStrategy.swift b/Sources/Encoder/Options/URLQueryDataEncodingStrategy.swift index 14f15f5..3f3c44e 100644 --- a/Sources/Encoder/Options/URLQueryDataEncodingStrategy.swift +++ b/Sources/Encoder/Options/URLQueryDataEncodingStrategy.swift @@ -1,8 +1,8 @@ import Foundation -public enum URLQueryDataEncodingStrategy { +public enum URLQueryDataEncodingStrategy: Sendable { case deferredToData case base64 - case custom((_ data: Data, _ encoder: Encoder) throws -> Void) + case custom(@Sendable (_ data: Data, _ encoder: Encoder) throws -> Void) } diff --git a/Sources/Encoder/Options/URLQueryDateEncodingStrategy.swift b/Sources/Encoder/Options/URLQueryDateEncodingStrategy.swift index 58a863d..088ce95 100644 --- a/Sources/Encoder/Options/URLQueryDateEncodingStrategy.swift +++ b/Sources/Encoder/Options/URLQueryDateEncodingStrategy.swift @@ -1,6 +1,6 @@ import Foundation -public enum URLQueryDateEncodingStrategy { +public enum URLQueryDateEncodingStrategy: Sendable { case deferredToDate @@ -11,5 +11,5 @@ public enum URLQueryDateEncodingStrategy { case iso8601 case formatted(DateFormatter) - case custom((_ date: Date, _ encoder: Encoder) throws -> Void) + case custom(@Sendable (_ date: Date, _ encoder: Encoder) throws -> Void) } diff --git a/Sources/Encoder/Options/URLQueryEncodingOptions.swift b/Sources/Encoder/Options/URLQueryEncodingOptions.swift index 595bae8..4f9d1ca 100644 --- a/Sources/Encoder/Options/URLQueryEncodingOptions.swift +++ b/Sources/Encoder/Options/URLQueryEncodingOptions.swift @@ -2,11 +2,11 @@ import Foundation internal struct URLQueryEncodingOptions { - internal let dateEncodingStrategy: URLQueryDateEncodingStrategy - internal let dataEncodingStrategy: URLQueryDataEncodingStrategy - internal let nonConformingFloatEncodingStrategy: URLQueryNonConformingFloatEncodingStrategy - internal let boolEncodingStrategy: URLQueryBoolEncodingStrategy - internal let arrayEncodingStrategy: URLQueryArrayEncodingStrategy - internal let spaceEncodingStrategy: URLQuerySpaceEncodingStrategy - internal let keyEncodingStrategy: URLQueryKeyEncodingStrategy + internal var dateEncodingStrategy: URLQueryDateEncodingStrategy + internal var dataEncodingStrategy: URLQueryDataEncodingStrategy + internal var nonConformingFloatEncodingStrategy: URLQueryNonConformingFloatEncodingStrategy + internal var boolEncodingStrategy: URLQueryBoolEncodingStrategy + internal var arrayEncodingStrategy: URLQueryArrayEncodingStrategy + internal var spaceEncodingStrategy: URLQuerySpaceEncodingStrategy + internal var keyEncodingStrategy: URLQueryKeyEncodingStrategy } diff --git a/Sources/Encoder/Options/URLQueryKeyEncodingStrategy.swift b/Sources/Encoder/Options/URLQueryKeyEncodingStrategy.swift index ab180f2..bcd87d1 100644 --- a/Sources/Encoder/Options/URLQueryKeyEncodingStrategy.swift +++ b/Sources/Encoder/Options/URLQueryKeyEncodingStrategy.swift @@ -1,7 +1,7 @@ import Foundation -public enum URLQueryKeyEncodingStrategy { +public enum URLQueryKeyEncodingStrategy: Sendable { case useDefaultKeys - case custom((_ codingPath: [CodingKey]) -> CodingKey) + case custom(@Sendable (_ codingPath: [CodingKey]) -> CodingKey) } diff --git a/Sources/Encoder/Options/URLQueryNonConformingFloatEncodingStrategy.swift b/Sources/Encoder/Options/URLQueryNonConformingFloatEncodingStrategy.swift index adcff33..cd818a1 100644 --- a/Sources/Encoder/Options/URLQueryNonConformingFloatEncodingStrategy.swift +++ b/Sources/Encoder/Options/URLQueryNonConformingFloatEncodingStrategy.swift @@ -1,6 +1,6 @@ import Foundation -public enum URLQueryNonConformingFloatEncodingStrategy { +public enum URLQueryNonConformingFloatEncodingStrategy: Sendable { case `throw` case convertToString(positiveInfinity: String, negativeInfinity: String, nan: String) diff --git a/Sources/Encoder/Options/URLQuerySpaceEncodingStrategy.swift b/Sources/Encoder/Options/URLQuerySpaceEncodingStrategy.swift index bc4e9e0..3853252 100644 --- a/Sources/Encoder/Options/URLQuerySpaceEncodingStrategy.swift +++ b/Sources/Encoder/Options/URLQuerySpaceEncodingStrategy.swift @@ -1,6 +1,6 @@ import Foundation -public enum URLQuerySpaceEncodingStrategy { +public enum URLQuerySpaceEncodingStrategy: Sendable { case percentEscaped case plusReplaced diff --git a/Sources/Encoder/URLQueryAnyKeyedEncodingContainer.swift b/Sources/Encoder/URLQueryAnyKeyedEncodingContainer.swift index d74205a..89a9140 100644 --- a/Sources/Encoder/URLQueryAnyKeyedEncodingContainer.swift +++ b/Sources/Encoder/URLQueryAnyKeyedEncodingContainer.swift @@ -36,7 +36,7 @@ internal final class URLQueryAnyKeyedEncodingContainer { keyedBy keyType: NestedKey.Type, forKey key: Key ) -> URLQueryAnyKeyedEncodingContainer { - if case let .resolver(container as URLQueryAnyKeyedEncodingContainer) = dictionary[encodeKey(key)] { + if case let .resolver(container as Self) = dictionary[encodeKey(key)] { return container } diff --git a/Sources/Encoder/URLQueryEncoder.swift b/Sources/Encoder/URLQueryEncoder.swift index 1cca4ce..1e96ac6 100644 --- a/Sources/Encoder/URLQueryEncoder.swift +++ b/Sources/Encoder/URLQueryEncoder.swift @@ -1,17 +1,51 @@ import Foundation -public final class URLQueryEncoder { +public final class URLQueryEncoder: Sendable { public static let `default` = URLQueryEncoder() - public var dateEncodingStrategy: URLQueryDateEncodingStrategy - public var dataEncodingStrategy: URLQueryDataEncodingStrategy - public var nonConformingFloatEncodingStrategy: URLQueryNonConformingFloatEncodingStrategy - public var boolEncodingStrategy: URLQueryBoolEncodingStrategy - public var arrayEncodingStrategy: URLQueryArrayEncodingStrategy - public var spaceEncodingStrategy: URLQuerySpaceEncodingStrategy - public var keyEncodingStrategy: URLQueryKeyEncodingStrategy - public var userInfo: [CodingUserInfoKey: Any] + private let optionsMutex: Mutex + private let userInfoMutex: Mutex<[CodingUserInfoKey: Sendable]> + + public var dateEncodingStrategy: URLQueryDateEncodingStrategy { + get { optionsMutex.withLock { $0.dateEncodingStrategy } } + set { optionsMutex.withLock { $0.dateEncodingStrategy = newValue } } + } + + public var dataEncodingStrategy: URLQueryDataEncodingStrategy { + get { optionsMutex.withLock { $0.dataEncodingStrategy } } + set { optionsMutex.withLock { $0.dataEncodingStrategy = newValue } } + } + + public var nonConformingFloatEncodingStrategy: URLQueryNonConformingFloatEncodingStrategy { + get { optionsMutex.withLock { $0.nonConformingFloatEncodingStrategy } } + set { optionsMutex.withLock { $0.nonConformingFloatEncodingStrategy = newValue } } + } + + public var boolEncodingStrategy: URLQueryBoolEncodingStrategy { + get { optionsMutex.withLock { $0.boolEncodingStrategy } } + set { optionsMutex.withLock { $0.boolEncodingStrategy = newValue } } + } + + public var arrayEncodingStrategy: URLQueryArrayEncodingStrategy { + get { optionsMutex.withLock { $0.arrayEncodingStrategy } } + set { optionsMutex.withLock { $0.arrayEncodingStrategy = newValue } } + } + + public var spaceEncodingStrategy: URLQuerySpaceEncodingStrategy { + get { optionsMutex.withLock { $0.spaceEncodingStrategy } } + set { optionsMutex.withLock { $0.spaceEncodingStrategy = newValue } } + } + + public var keyEncodingStrategy: URLQueryKeyEncodingStrategy { + get { optionsMutex.withLock { $0.keyEncodingStrategy } } + set { optionsMutex.withLock { $0.keyEncodingStrategy = newValue } } + } + + public var userInfo: [CodingUserInfoKey: Sendable] { + get { userInfoMutex.withLock { $0 } } + set { userInfoMutex.withLock { $0 = newValue } } + } public init( dateEncodingStrategy: URLQueryDateEncodingStrategy = .deferredToDate, @@ -21,19 +55,8 @@ public final class URLQueryEncoder { arrayEncodingStrategy: URLQueryArrayEncodingStrategy = .enumerated, spaceEncodingStrategy: URLQuerySpaceEncodingStrategy = .percentEscaped, keyEncodingStrategy: URLQueryKeyEncodingStrategy = .useDefaultKeys, - userInfo: [CodingUserInfoKey: Any] = [:] + userInfo: [CodingUserInfoKey: Sendable] = [:] ) { - self.dateEncodingStrategy = dateEncodingStrategy - self.dataEncodingStrategy = dataEncodingStrategy - self.nonConformingFloatEncodingStrategy = nonConformingFloatEncodingStrategy - self.boolEncodingStrategy = boolEncodingStrategy - self.arrayEncodingStrategy = arrayEncodingStrategy - self.spaceEncodingStrategy = spaceEncodingStrategy - self.keyEncodingStrategy = keyEncodingStrategy - self.userInfo = userInfo - } - - public func encode(_ value: T) throws -> String { let options = URLQueryEncodingOptions( dateEncodingStrategy: dateEncodingStrategy, dataEncodingStrategy: dataEncodingStrategy, @@ -44,6 +67,13 @@ public final class URLQueryEncoder { keyEncodingStrategy: keyEncodingStrategy ) + self.optionsMutex = Mutex(value: options) + self.userInfoMutex = Mutex(value: userInfo) + } + + public func encode(_ value: T) throws -> String { + let options = optionsMutex.withLock { $0 } + let encoder = URLQuerySingleValueEncodingContainer( options: options, userInfo: userInfo, diff --git a/Sources/Encoder/URLQueryValueEncoding.swift b/Sources/Encoder/URLQueryValueEncoding.swift index 1f0bee8..cede75b 100644 --- a/Sources/Encoder/URLQueryValueEncoding.swift +++ b/Sources/Encoder/URLQueryValueEncoding.swift @@ -214,9 +214,12 @@ extension URLQueryValueEncoding { } } -private extension EncodingError { +extension EncodingError { - static func invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { + fileprivate static func invalidFloatingPointValue( + _ value: T, + at codingPath: [CodingKey] + ) -> EncodingError { let valueDescription: String switch value { diff --git a/Sources/Tools/AnyCodingKey.swift b/Sources/Tools/AnyCodingKey.swift index 511612b..cef2dbf 100644 --- a/Sources/Tools/AnyCodingKey.swift +++ b/Sources/Tools/AnyCodingKey.swift @@ -2,7 +2,7 @@ import Foundation internal struct AnyCodingKey: CodingKey { - internal static let `super` = AnyCodingKey("super") + internal static let `super` = Self("super") internal let stringValue: String internal let intValue: Int? diff --git a/Sources/Tools/Mutex/Mutex.swift b/Sources/Tools/Mutex/Mutex.swift new file mode 100644 index 0000000..1f3bcb2 --- /dev/null +++ b/Sources/Tools/Mutex/Mutex.swift @@ -0,0 +1,36 @@ +import Foundation + +public struct Mutex: @unchecked Sendable { + + private let storage: MutexStorage + + public init(value: Value) { + self.storage = MutexStorage(value: value) + } + + public borrowing func withLock( + _ body: (inout Value) throws -> Result + ) rethrows -> Result { + storage.lock() + + defer { + storage.unlock() + } + + return try body(&storage.value) + } + + public borrowing func withLockIfAvailable( + _ body: (inout Value) throws -> Result + ) rethrows -> Result? { + guard storage.tryLock() else { + return nil + } + + defer { + storage.unlock() + } + + return try body(&storage.value) + } +} diff --git a/Sources/Tools/Mutex/MutexStorage.swift b/Sources/Tools/Mutex/MutexStorage.swift new file mode 100644 index 0000000..a884dad --- /dev/null +++ b/Sources/Tools/Mutex/MutexStorage.swift @@ -0,0 +1,38 @@ +import Foundation + +import struct os.os_unfair_lock_t +import struct os.os_unfair_lock + +import func os.os_unfair_lock_lock +import func os.os_unfair_lock_unlock +import func os.os_unfair_lock_trylock + +internal final class MutexStorage { + + private let unfairLock = os_unfair_lock_t.allocate(capacity: 1) + + internal var value: Value + + internal init(value: consuming Value) { + self.value = value + + unfairLock.initialize(to: os_unfair_lock()) + } + + deinit { + unfairLock.deinitialize(count: 1) + unfairLock.deallocate() + } + + internal func lock() { + os_unfair_lock_lock(unfairLock) + } + + internal func unlock() { + os_unfair_lock_unlock(unfairLock) + } + + internal func tryLock() -> Bool { + os_unfair_lock_trylock(unfairLock) + } +} diff --git a/Sources/URLQueryCoder.h b/Sources/URLQueryCoder.h deleted file mode 100644 index d68ad81..0000000 --- a/Sources/URLQueryCoder.h +++ /dev/null @@ -1,4 +0,0 @@ -#import - -FOUNDATION_EXPORT double URLQueryCoderVersionNumber; -FOUNDATION_EXPORT const unsigned char URLQueryCoderVersionString[]; diff --git a/Sources/Value/URLQueryValue.swift b/Sources/Value/URLQueryValue.swift index 15ac522..1971528 100644 --- a/Sources/Value/URLQueryValue.swift +++ b/Sources/Value/URLQueryValue.swift @@ -3,8 +3,8 @@ import Foundation internal enum URLQueryValue { case string(String) - indirect case array([Int: URLQueryValue]) - indirect case dictionary([String: URLQueryValue]) + indirect case array([Int: Self]) + indirect case dictionary([String: Self]) internal var string: String? { switch self { @@ -16,7 +16,7 @@ internal enum URLQueryValue { } } - internal var array: [Int: URLQueryValue]? { + internal var array: [Int: Self]? { switch self { case let .array(array): return array @@ -26,7 +26,7 @@ internal enum URLQueryValue { } } - internal var dictionary: [String: URLQueryValue]? { + internal var dictionary: [String: Self]? { switch self { case let .dictionary(dictionary): return dictionary diff --git a/Tests/.swiftlint.yml b/Tests/.swiftlint.yml index 4ad33b7..7b37363 100644 --- a/Tests/.swiftlint.yml +++ b/Tests/.swiftlint.yml @@ -1,8 +1,8 @@ disabled_rules: - - closure_body_length + - explicit_acl + - explicit_top_level_acl - file_length - - force_try - function_body_length - - trailing_closure - - type_body_length + - implicitly_unwrapped_optional - nesting + - type_body_length diff --git a/Tests/Decoder/URLQueryDecoderStrategiesTests.swift b/Tests/Decoder/URLQueryDecoderStrategiesTests.swift index 9ae0fe4..765277f 100644 --- a/Tests/Decoder/URLQueryDecoderStrategiesTests.swift +++ b/Tests/Decoder/URLQueryDecoderStrategiesTests.swift @@ -35,11 +35,12 @@ final class URLQueryDecoderStrategiesTests: XCTestCase, URLQueryDecoderTesting { } decoder.keyDecodingStrategy = .custom { codingPath in - if let codingKey = codingPath.last?.stringValue.components(separatedBy: ".").first { - return AnyCodingKey(codingKey) - } else { - return AnyCodingKey("unknown") - } + codingPath + .last? + .stringValue + .components(separatedBy: ".") + .first + .map { AnyCodingKey($0) } ?? AnyCodingKey("unknown") } let query = "foo.value=true&bar.value=false" diff --git a/Tests/Decoder/URLQueryDecoderTesting.swift b/Tests/Decoder/URLQueryDecoderTesting.swift index 140cba6..8813a6e 100644 --- a/Tests/Decoder/URLQueryDecoderTesting.swift +++ b/Tests/Decoder/URLQueryDecoderTesting.swift @@ -13,7 +13,7 @@ extension URLQueryDecoderTesting { decoding valueType: [Key: Value].Type, from query: String, expecting expectedValue: [Key: Value], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { do { @@ -34,7 +34,7 @@ extension URLQueryDecoderTesting { decoding valueType: T.Type, from query: String, expecting expectedValue: T, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { do { @@ -49,7 +49,7 @@ extension URLQueryDecoderTesting { func assertDecoderFails( decoding valueType: T.Type, from query: String, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line, errorValidation: (_ error: Error) -> Bool ) { diff --git a/Tests/Decoder/URLQueryDecoderTests.swift b/Tests/Decoder/URLQueryDecoderTests.swift index 667ff1a..12b3e67 100644 --- a/Tests/Decoder/URLQueryDecoderTests.swift +++ b/Tests/Decoder/URLQueryDecoderTests.swift @@ -763,7 +763,7 @@ final class URLQueryDecoderTests: XCTestCase, URLQueryDecoderTesting { } override func isEqual(_ object: Any?) -> Bool { - guard let object = object as? DecodableSubclass else { + guard let object = object as? Self else { return false } @@ -859,7 +859,7 @@ final class URLQueryDecoderTests: XCTestCase, URLQueryDecoderTesting { } func testThatDecoderFailsWhenDecodingInvalidURL() { - let url = "invalid url" + let url = "//invalid url" let query = "foobar=\(url.urlQueryEncoded!)" assertDecoderFails(decoding: [String: URL].self, from: query) { error in diff --git a/Tests/Encoder/URLQueryEncoderTesting.swift b/Tests/Encoder/URLQueryEncoderTesting.swift index a5a4b22..90b3038 100644 --- a/Tests/Encoder/URLQueryEncoderTesting.swift +++ b/Tests/Encoder/URLQueryEncoderTesting.swift @@ -11,7 +11,7 @@ extension URLQueryEncoderTesting { func assertEncoderSucceeds( encoding value: T, expecting expectedQuery: String, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { let expectedQueryComponents = expectedQuery @@ -38,7 +38,7 @@ extension URLQueryEncoderTesting { func assertEncoderFails( encoding value: T, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line, errorValidation: (_ error: Error) -> Bool ) { diff --git a/URLQueryCoder.podspec b/URLQueryCoder.podspec index 90dbf0a..ddaf9f3 100644 --- a/URLQueryCoder.podspec +++ b/URLQueryCoder.podspec @@ -8,19 +8,19 @@ Pod::Spec.new do |spec| spec.author = { "Almaz Ibragimov" => "almazrafi@gmail.com" } spec.source = { :git => "https://github.com/almazrafi/URLQueryCoder.git", :tag => "#{spec.version}" } - spec.swift_version = '5.5' + spec.swift_version = '5.9' spec.requires_arc = true spec.source_files = 'Sources/**/*.swift' spec.ios.frameworks = 'Foundation' - spec.ios.deployment_target = "12.0" + spec.ios.deployment_target = "13.0" spec.osx.frameworks = 'Foundation' - spec.osx.deployment_target = "10.14" + spec.osx.deployment_target = "11.5" spec.watchos.frameworks = 'Foundation' - spec.watchos.deployment_target = "5.0" + spec.watchos.deployment_target = "6.0" spec.tvos.frameworks = 'Foundation' - spec.tvos.deployment_target = "12.0" + spec.tvos.deployment_target = "13.0" end diff --git a/URLQueryCoder.xcodeproj/project.pbxproj b/URLQueryCoder.xcodeproj/project.pbxproj index d33bae2..9c44fc2 100644 --- a/URLQueryCoder.xcodeproj/project.pbxproj +++ b/URLQueryCoder.xcodeproj/project.pbxproj @@ -19,8 +19,15 @@ C013EB5B23E1E23B00F12CCB /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C013EB5A23E1E23B00F12CCB /* Optional+Extensions.swift */; }; C013EB5C23E1E23B00F12CCB /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C013EB5A23E1E23B00F12CCB /* Optional+Extensions.swift */; }; C013EB5D23E1E23B00F12CCB /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C013EB5A23E1E23B00F12CCB /* Optional+Extensions.swift */; }; + C0153AFF2F02AF3600A7322E /* MutexStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0153AFD2F02AF3600A7322E /* MutexStorage.swift */; }; + C0153B002F02AF3600A7322E /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0153AFC2F02AF3600A7322E /* Mutex.swift */; }; + C0153B012F02AF3600A7322E /* MutexStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0153AFD2F02AF3600A7322E /* MutexStorage.swift */; }; + C0153B022F02AF3600A7322E /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0153AFC2F02AF3600A7322E /* Mutex.swift */; }; + C0153B032F02AF3600A7322E /* MutexStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0153AFD2F02AF3600A7322E /* MutexStorage.swift */; }; + C0153B042F02AF3600A7322E /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0153AFC2F02AF3600A7322E /* Mutex.swift */; }; + C0153B052F02AF3600A7322E /* MutexStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0153AFD2F02AF3600A7322E /* MutexStorage.swift */; }; + C0153B062F02AF3600A7322E /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0153AFC2F02AF3600A7322E /* Mutex.swift */; }; C057F01823CB8EEB00C2D895 /* URLQueryCoder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C057F00E23CB8EEB00C2D895 /* URLQueryCoder.framework */; }; - C057F01F23CB8EEB00C2D895 /* URLQueryCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = C057F01123CB8EEB00C2D895 /* URLQueryCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C09C107428BE49480020E2B3 /* URLQueryDataDecodingStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C09C106F28BE49480020E2B3 /* URLQueryDataDecodingStrategy.swift */; }; C09C107528BE49480020E2B3 /* URLQueryDataDecodingStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C09C106F28BE49480020E2B3 /* URLQueryDataDecodingStrategy.swift */; }; C09C107628BE49480020E2B3 /* URLQueryDataDecodingStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C09C106F28BE49480020E2B3 /* URLQueryDataDecodingStrategy.swift */; }; @@ -176,9 +183,7 @@ C09C116228BECC230020E2B3 /* URLQueryEncoderStrategiesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C09C116028BECC230020E2B3 /* URLQueryEncoderStrategiesTests.swift */; }; C09C116328BECC230020E2B3 /* URLQueryEncoderStrategiesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C09C116028BECC230020E2B3 /* URLQueryEncoderStrategiesTests.swift */; }; C0A01A3223CB90F200AC2C3A /* URLQueryCoder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0A01A2923CB90F200AC2C3A /* URLQueryCoder.framework */; }; - C0A01A4123CB912C00AC2C3A /* URLQueryCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = C057F01123CB8EEB00C2D895 /* URLQueryCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; C0A01A5023CB92EB00AC2C3A /* URLQueryCoder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0A01A4723CB92EB00AC2C3A /* URLQueryCoder.framework */; }; - C0A01A5E23CB92F200AC2C3A /* URLQueryCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = C057F01123CB8EEB00C2D895 /* URLQueryCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -211,8 +216,14 @@ C013EAF223E1E0AE00F12CCB /* RangeReplaceableCollection+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RangeReplaceableCollection+Extensions.swift"; sourceTree = ""; }; C013EAF323E1E0AE00F12CCB /* AnyCodingKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodingKey.swift; sourceTree = ""; }; C013EB5A23E1E23B00F12CCB /* Optional+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Optional+Extensions.swift"; sourceTree = ""; }; + C0153AF72F02AD6600A7322E /* .system-version */ = {isa = PBXFileReference; lastKnownFileType = text; path = ".system-version"; sourceTree = ""; }; + C0153AF82F02AD6600A7322E /* .xcode-runtime-version */ = {isa = PBXFileReference; lastKnownFileType = text; path = ".xcode-runtime-version"; sourceTree = ""; }; + C0153AF92F02AD6600A7322E /* .xcode-version */ = {isa = PBXFileReference; lastKnownFileType = text; path = ".xcode-version"; sourceTree = ""; }; + C0153AFA2F02AD6600A7322E /* Gemfile.lock */ = {isa = PBXFileReference; lastKnownFileType = text; path = Gemfile.lock; sourceTree = ""; }; + C0153AFB2F02AD6600A7322E /* Package@swift-5.9.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Package@swift-5.9.swift"; sourceTree = ""; }; + C0153AFC2F02AF3600A7322E /* Mutex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = ""; }; + C0153AFD2F02AF3600A7322E /* MutexStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutexStorage.swift; sourceTree = ""; }; C057F00E23CB8EEB00C2D895 /* URLQueryCoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = URLQueryCoder.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C057F01123CB8EEB00C2D895 /* URLQueryCoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = URLQueryCoder.h; sourceTree = ""; }; C057F01223CB8EEB00C2D895 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C057F01723CB8EEB00C2D895 /* URLQueryCoder Tests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "URLQueryCoder Tests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; C057F01E23CB8EEB00C2D895 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -257,13 +268,11 @@ C09C115828BEB5A50020E2B3 /* URLQueryEncoderTesting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLQueryEncoderTesting.swift; sourceTree = ""; }; C09C115C28BEBB8D0020E2B3 /* URLQueryEncoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLQueryEncoderTests.swift; sourceTree = ""; }; C09C116028BECC230020E2B3 /* URLQueryEncoderStrategiesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLQueryEncoderStrategiesTests.swift; sourceTree = ""; }; - C0A01A1423CB8FF300AC2C3A /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; C0A01A1523CB8FFC00AC2C3A /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; C0A01A1723CB900900AC2C3A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; C0A01A1823CB900900AC2C3A /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; C0A01A1923CB900900AC2C3A /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; C0A01A1A23CB901C00AC2C3A /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = ""; }; - C0A01A1B23CB901C00AC2C3A /* .codecov.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .codecov.yml; sourceTree = ""; }; C0A01A1C23CB901C00AC2C3A /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; C0A01A1D23CB901C00AC2C3A /* .ruby-version */ = {isa = PBXFileReference; lastKnownFileType = text; path = ".ruby-version"; sourceTree = ""; }; C0A01A2923CB90F200AC2C3A /* URLQueryCoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = URLQueryCoder.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -335,6 +344,7 @@ C013EAF123E1E0AE00F12CCB /* Tools */ = { isa = PBXGroup; children = ( + C0153AFE2F02AF3600A7322E /* Mutex */, C013EAF323E1E0AE00F12CCB /* AnyCodingKey.swift */, C09C10A728BE4F9A0020E2B3 /* Character+Extensions.swift */, C09C10B628BE4FFA0020E2B3 /* Collection+Extensions.swift */, @@ -409,6 +419,15 @@ path = Encoder; sourceTree = ""; }; + C0153AFE2F02AF3600A7322E /* Mutex */ = { + isa = PBXGroup; + children = ( + C0153AFC2F02AF3600A7322E /* Mutex.swift */, + C0153AFD2F02AF3600A7322E /* MutexStorage.swift */, + ); + path = Mutex; + sourceTree = ""; + }; C057F00423CB8EEB00C2D895 = { isa = PBXGroup; children = ( @@ -416,16 +435,20 @@ C057F01B23CB8EEB00C2D895 /* Tests */, C057F00F23CB8EEB00C2D895 /* Products */, C0A01A6323CB9B0A00AC2C3A /* Scripts */, - C0A01A1B23CB901C00AC2C3A /* .codecov.yml */, C0A01A1A23CB901C00AC2C3A /* .gitignore */, + C0153AF72F02AD6600A7322E /* .system-version */, + C0153AF82F02AD6600A7322E /* .xcode-runtime-version */, + C0153AF92F02AD6600A7322E /* .xcode-version */, C0A01A1D23CB901C00AC2C3A /* .ruby-version */, C0007FFA23CBAAA5005F95E0 /* .swift-version */, C0A01A1C23CB901C00AC2C3A /* .swiftlint.yml */, C0A01A6423CB9B1600AC2C3A /* Dangerfile */, C0A01A6523CB9B1600AC2C3A /* Gemfile */, + C0153AFA2F02AD6600A7322E /* Gemfile.lock */, C07811BC2675FD15002FE9D4 /* Mintfile */, C0A01A1923CB900900AC2C3A /* LICENSE */, C0A01A1823CB900900AC2C3A /* Package.swift */, + C0153AFB2F02AD6600A7322E /* Package@swift-5.9.swift */, C0A01A1723CB900900AC2C3A /* README.md */, C0D991F528BE452300031CB8 /* URLQueryCoder.podspec */, ); @@ -452,9 +475,7 @@ C013EB0023E1E0AF00F12CCB /* Encoder */, C013EAF123E1E0AE00F12CCB /* Tools */, C09C108828BE4D0C0020E2B3 /* Value */, - C0A01A1423CB8FF300AC2C3A /* .swiftlint.yml */, C057F01223CB8EEB00C2D895 /* Info.plist */, - C057F01123CB8EEB00C2D895 /* URLQueryCoder.h */, ); path = Sources; sourceTree = ""; @@ -496,47 +517,12 @@ }; /* End PBXGroup section */ -/* Begin PBXHeadersBuildPhase section */ - C006F19D2406B13E00C3F783 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C057F00923CB8EEB00C2D895 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - C057F01F23CB8EEB00C2D895 /* URLQueryCoder.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C0A01A2423CB90F200AC2C3A /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - C0A01A4123CB912C00AC2C3A /* URLQueryCoder.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C0A01A4223CB92EB00AC2C3A /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - C0A01A5E23CB92F200AC2C3A /* URLQueryCoder.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - /* Begin PBXNativeTarget section */ C006F1A12406B13E00C3F783 /* URLQueryCoder watchOS */ = { isa = PBXNativeTarget; buildConfigurationList = C006F1A92406B13E00C3F783 /* Build configuration list for PBXNativeTarget "URLQueryCoder watchOS" */; buildPhases = ( C006F1C42406B21000C3F783 /* SwiftLint */, - C006F19D2406B13E00C3F783 /* Headers */, C006F19E2406B13E00C3F783 /* Sources */, C006F19F2406B13E00C3F783 /* Frameworks */, C006F1A02406B13E00C3F783 /* Resources */, @@ -555,7 +541,6 @@ buildConfigurationList = C057F02223CB8EEB00C2D895 /* Build configuration list for PBXNativeTarget "URLQueryCoder iOS" */; buildPhases = ( C0A01A2323CB907300AC2C3A /* SwiftLint */, - C057F00923CB8EEB00C2D895 /* Headers */, C057F00A23CB8EEB00C2D895 /* Sources */, C057F00B23CB8EEB00C2D895 /* Frameworks */, C057F00C23CB8EEB00C2D895 /* Resources */, @@ -592,7 +577,6 @@ buildConfigurationList = C0A01A3A23CB90F200AC2C3A /* Build configuration list for PBXNativeTarget "URLQueryCoder macOS" */; buildPhases = ( C0A01A6123CB931500AC2C3A /* SwiftLint */, - C0A01A2423CB90F200AC2C3A /* Headers */, C0A01A2523CB90F200AC2C3A /* Sources */, C0A01A2623CB90F200AC2C3A /* Frameworks */, C0A01A2723CB90F200AC2C3A /* Resources */, @@ -629,7 +613,6 @@ buildConfigurationList = C0A01A5823CB92EB00AC2C3A /* Build configuration list for PBXNativeTarget "URLQueryCoder tvOS" */; buildPhases = ( C0A01A6223CB932700AC2C3A /* SwiftLint */, - C0A01A4223CB92EB00AC2C3A /* Headers */, C0A01A4323CB92EB00AC2C3A /* Sources */, C0A01A4423CB92EB00AC2C3A /* Frameworks */, C0A01A4523CB92EB00AC2C3A /* Resources */, @@ -667,8 +650,9 @@ C057F00523CB8EEB00C2D895 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1130; - LastUpgradeCheck = 1410; + LastUpgradeCheck = 1640; ORGANIZATIONNAME = "Almaz Ibragimov"; TargetAttributes = { C006F1A12406B13E00C3F783 = { @@ -873,6 +857,8 @@ C09C113E28BEA50E0020E2B3 /* URLQueryValueForm.swift in Sources */, C09C112428BE95750020E2B3 /* URLQueryUnkeyedDecodingContainer.swift in Sources */, C09C10B028BE4FB50020E2B3 /* Dictionary+Extensions.swift in Sources */, + C0153B032F02AF3600A7322E /* MutexStorage.swift in Sources */, + C0153B042F02AF3600A7322E /* Mutex.swift in Sources */, C09C112028BE948D0020E2B3 /* URLQuerySingleValueDecodingContainer.swift in Sources */, C09C109228BE4E660020E2B3 /* URLQueryValueDecoding.swift in Sources */, C09C108D28BE4D130020E2B3 /* URLQueryValue.swift in Sources */, @@ -917,6 +903,8 @@ C09C113B28BEA50E0020E2B3 /* URLQueryValueForm.swift in Sources */, C09C112128BE95740020E2B3 /* URLQueryUnkeyedDecodingContainer.swift in Sources */, C09C10AD28BE4FB50020E2B3 /* Dictionary+Extensions.swift in Sources */, + C0153AFF2F02AF3600A7322E /* MutexStorage.swift in Sources */, + C0153B002F02AF3600A7322E /* Mutex.swift in Sources */, C09C111D28BE948B0020E2B3 /* URLQuerySingleValueDecodingContainer.swift in Sources */, C09C108A28BE4D130020E2B3 /* URLQueryValue.swift in Sources */, C09C107828BE49480020E2B3 /* URLQueryDateDecodingStrategy.swift in Sources */, @@ -974,6 +962,8 @@ C09C113C28BEA50E0020E2B3 /* URLQueryValueForm.swift in Sources */, C09C112228BE95740020E2B3 /* URLQueryUnkeyedDecodingContainer.swift in Sources */, C09C10AE28BE4FB50020E2B3 /* Dictionary+Extensions.swift in Sources */, + C0153B052F02AF3600A7322E /* MutexStorage.swift in Sources */, + C0153B062F02AF3600A7322E /* Mutex.swift in Sources */, C09C111E28BE948C0020E2B3 /* URLQuerySingleValueDecodingContainer.swift in Sources */, C09C108B28BE4D130020E2B3 /* URLQueryValue.swift in Sources */, C09C107928BE49480020E2B3 /* URLQueryDateDecodingStrategy.swift in Sources */, @@ -1031,6 +1021,8 @@ C09C113D28BEA50E0020E2B3 /* URLQueryValueForm.swift in Sources */, C09C112328BE95750020E2B3 /* URLQueryUnkeyedDecodingContainer.swift in Sources */, C09C10AF28BE4FB50020E2B3 /* Dictionary+Extensions.swift in Sources */, + C0153B012F02AF3600A7322E /* MutexStorage.swift in Sources */, + C0153B022F02AF3600A7322E /* Mutex.swift in Sources */, C09C111F28BE948C0020E2B3 /* URLQuerySingleValueDecodingContainer.swift in Sources */, C09C108C28BE4D130020E2B3 /* URLQueryValue.swift in Sources */, C09C107A28BE49480020E2B3 /* URLQueryDateDecodingStrategy.swift in Sources */, @@ -1099,6 +1091,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1107,6 +1100,7 @@ "@loader_path/Frameworks", ); MARKETING_VERSION = 1.1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = com.almazrafi.URLQueryCoder; PRODUCT_NAME = URLQueryCoder; SDKROOT = watchos; @@ -1125,6 +1119,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1133,6 +1128,7 @@ "@loader_path/Frameworks", ); MARKETING_VERSION = 1.1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = com.almazrafi.URLQueryCoder; PRODUCT_NAME = URLQueryCoder; SDKROOT = watchos; @@ -1145,6 +1141,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -1179,6 +1176,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -1193,8 +1191,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MACOSX_DEPLOYMENT_TARGET = 10.14; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 11.5; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -1202,11 +1200,11 @@ SKIP_SWIFTLINT = ""; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.5; - TVOS_DEPLOYMENT_TARGET = 12.0; + SWIFT_VERSION = 6.0; + TVOS_DEPLOYMENT_TARGET = 13.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 5.0; + WATCHOS_DEPLOYMENT_TARGET = 6.0; }; name = Debug; }; @@ -1214,6 +1212,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -1248,6 +1247,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -1256,20 +1256,20 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MACOSX_DEPLOYMENT_TARGET = 10.14; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 11.5; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; SKIP_SWIFTLINT = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 5.5; - TVOS_DEPLOYMENT_TARGET = 12.0; + SWIFT_VERSION = 6.0; + TVOS_DEPLOYMENT_TARGET = 13.0; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 5.0; + WATCHOS_DEPLOYMENT_TARGET = 6.0; }; name = Release; }; @@ -1284,6 +1284,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1292,6 +1293,7 @@ "@loader_path/Frameworks", ); MARKETING_VERSION = 1.1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = com.almazrafi.URLQueryCoder; PRODUCT_NAME = URLQueryCoder; SKIP_INSTALL = YES; @@ -1310,6 +1312,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1318,6 +1321,7 @@ "@loader_path/Frameworks", ); MARKETING_VERSION = 1.1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = com.almazrafi.URLQueryCoder; PRODUCT_NAME = URLQueryCoder; SKIP_INSTALL = YES; @@ -1328,7 +1332,6 @@ C057F02623CB8EEB00C2D895 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = Tests/Info.plist; @@ -1346,7 +1349,6 @@ C057F02723CB8EEB00C2D895 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = Tests/Info.plist; @@ -1373,6 +1375,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1381,6 +1384,7 @@ "@loader_path/Frameworks", ); MARKETING_VERSION = 1.1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = com.almazrafi.URLQueryCoder; PRODUCT_NAME = URLQueryCoder; SDKROOT = macosx; @@ -1400,6 +1404,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1408,6 +1413,7 @@ "@loader_path/Frameworks", ); MARKETING_VERSION = 1.1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = com.almazrafi.URLQueryCoder; PRODUCT_NAME = URLQueryCoder; SDKROOT = macosx; @@ -1418,7 +1424,6 @@ C0A01A3E23CB90F200AC2C3A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEAD_CODE_STRIPPING = YES; @@ -1437,7 +1442,6 @@ C0A01A3F23CB90F200AC2C3A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEAD_CODE_STRIPPING = YES; @@ -1464,6 +1468,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1472,6 +1477,7 @@ "@loader_path/Frameworks", ); MARKETING_VERSION = 1.1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = com.almazrafi.URLQueryCoder; PRODUCT_NAME = URLQueryCoder; SDKROOT = appletvos; @@ -1491,6 +1497,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1499,6 +1506,7 @@ "@loader_path/Frameworks", ); MARKETING_VERSION = 1.1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = com.almazrafi.URLQueryCoder; PRODUCT_NAME = URLQueryCoder; SDKROOT = appletvos; @@ -1510,7 +1518,6 @@ C0A01A5C23CB92EB00AC2C3A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = Tests/Info.plist; @@ -1529,7 +1536,6 @@ C0A01A5D23CB92EB00AC2C3A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = Tests/Info.plist; diff --git a/URLQueryCoder.xcodeproj/xcshareddata/xcschemes/URLQueryCoder iOS.xcscheme b/URLQueryCoder.xcodeproj/xcshareddata/xcschemes/URLQueryCoder iOS.xcscheme index 97192ec..90be8ee 100644 --- a/URLQueryCoder.xcodeproj/xcshareddata/xcschemes/URLQueryCoder iOS.xcscheme +++ b/URLQueryCoder.xcodeproj/xcshareddata/xcschemes/URLQueryCoder iOS.xcscheme @@ -1,6 +1,6 @@