├── .github └── workflows │ ├── main.yml │ └── static.yml ├── .gitignore ├── .hound.yml ├── .jazzy.yml ├── .mise.toml ├── .swift-format ├── .swift-version ├── .swiftlint.yml ├── FUNDING.yml ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Package.swift ├── Punycode.podspec ├── Punycode.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── Punycode.xcscheme ├── README.md ├── Sources ├── Extensions.swift ├── Helpers.swift ├── Punycode.h └── Punycode.swift ├── Tests └── PunycodeTests.swift ├── docs └── swiftdoc │ ├── Classes.html │ ├── Classes │ └── Puny.html │ ├── Extensions.html │ ├── Extensions │ ├── String.html │ └── Substring.html │ ├── css │ ├── highlight.css │ └── jazzy.css │ ├── docsets │ ├── Punycode.docset │ │ └── Contents │ │ │ ├── Info.plist │ │ │ └── Resources │ │ │ ├── Documents │ │ │ ├── Classes.html │ │ │ ├── Classes │ │ │ │ └── Puny.html │ │ │ ├── Extensions.html │ │ │ ├── Extensions │ │ │ │ ├── String.html │ │ │ │ └── Substring.html │ │ │ ├── css │ │ │ │ ├── highlight.css │ │ │ │ └── jazzy.css │ │ │ ├── img │ │ │ │ ├── carat.png │ │ │ │ ├── dash.png │ │ │ │ ├── gh.png │ │ │ │ └── spinner.gif │ │ │ ├── index.html │ │ │ ├── js │ │ │ │ ├── jazzy.js │ │ │ │ ├── jazzy.search.js │ │ │ │ ├── jquery.min.js │ │ │ │ ├── lunr.min.js │ │ │ │ └── typeahead.jquery.js │ │ │ └── search.json │ │ │ └── docSet.dsidx │ └── Punycode.xml │ ├── img │ ├── carat.png │ ├── dash.png │ ├── gh.png │ └── spinner.gif │ ├── index.html │ ├── js │ ├── jazzy.js │ ├── jazzy.search.js │ ├── jquery.min.js │ ├── lunr.min.js │ └── typeahead.jquery.js │ ├── search.json │ └── undocumented.json ├── fastlane ├── Appfile ├── Fastfile ├── Pluginfile └── README.md └── run.sh /.github/workflows/static.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy Github Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["main"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 20 | concurrency: 21 | group: "pages" 22 | cancel-in-progress: false 23 | 24 | jobs: 25 | # Single deploy job since we're just deploying 26 | deploy: 27 | environment: 28 | name: github-pages 29 | url: ${{ steps.deployment.outputs.page_url }} 30 | runs-on: ubuntu-latest 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v4 34 | - name: Setup Pages 35 | uses: actions/configure-pages@v5 36 | - name: Upload artifact 37 | uses: actions/upload-pages-artifact@v3 38 | with: 39 | # Upload entire repository 40 | path: './docs' 41 | - name: Deploy to GitHub Pages 42 | id: deployment 43 | uses: actions/deploy-pages@v4 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots/**/*.png 68 | fastlane/test_output 69 | fastlane/reports 70 | 71 | # Direnv 72 | .envrc 73 | 74 | # Ruby 75 | .bundle -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | swift: 2 | enabled: true 3 | config_file: .swift-format 4 | -------------------------------------------------------------------------------- /.jazzy.yml: -------------------------------------------------------------------------------- 1 | module: Punycode 2 | version: 3.0.0 3 | 4 | author: Kojiro Futamura 5 | author_url: https://github.com/gumob 6 | github_url: https://github.com/gumob/PunycodeSwift 7 | # copyright: 'Copyright © 2024 Kojiro Futamura. All rights reserved.' 8 | 9 | source_host_url: https://github.com/gumob/PunycodeSwift 10 | root_url: https://github.com/gumob/PunycodeSwift/tree/3.0.0/docs/ 11 | 12 | readme: "README.md" 13 | 14 | theme: fullwidth 15 | 16 | xcodebuild_arguments: 17 | - -project 18 | - ../Punycode.xcodeproj 19 | - -scheme 20 | - Punycode 21 | 22 | output: "docs/swiftdoc" 23 | min_acl: public 24 | clean: true 25 | skip_undocumented: false 26 | hide_documentation_coverage: true 27 | source_directory: Sources 28 | umbrella_header: "Sources/Punycode.h" 29 | 30 | exclude: 31 | - Tests/* 32 | -------------------------------------------------------------------------------- /.mise.toml: -------------------------------------------------------------------------------- 1 | [tools] 2 | python = "3.11.9" 3 | ruby = "3.2.5" 4 | 5 | [env] 6 | _.python.venv = ".venv" 7 | EXPANDED_CODE_SIGN_IDENTITY="" 8 | EXPANDED_CODE_SIGN_IDENTITY_NAME="" 9 | EXPANDED_PROVISIONING_PROFILE="" -------------------------------------------------------------------------------- /.swift-format: -------------------------------------------------------------------------------- 1 | { 2 | "fileScopedDeclarationPrivacy" : { 3 | "accessLevel" : "private" 4 | }, 5 | "indentation" : { 6 | "spaces" : 4 7 | }, 8 | "indentConditionalCompilationBlocks" : false, 9 | "indentSwitchCaseLabels" : false, 10 | "lineBreakAroundMultilineExpressionChainComponents" : false, 11 | "lineBreakBeforeControlFlowKeywords" : false, 12 | "lineBreakBeforeEachArgument" : true, 13 | "lineBreakBeforeEachGenericRequirement" : false, 14 | "lineLength" : 200, 15 | "maximumBlankLines" : 1, 16 | "multiElementCollectionTrailingCommas" : true, 17 | "noAssignmentInExpressions" : { 18 | "allowedFunctions" : [ 19 | "XCTAssertNoThrow" 20 | ] 21 | }, 22 | "prioritizeKeepingFunctionOutputTogether" : false, 23 | "respectsExistingLineBreaks" : true, 24 | "rules" : { 25 | "AllPublicDeclarationsHaveDocumentation" : false, 26 | "AlwaysUseLiteralForEmptyCollectionInit" : false, 27 | "AlwaysUseLowerCamelCase" : true, 28 | "AmbiguousTrailingClosureOverload" : true, 29 | "BeginDocumentationCommentWithOneLineSummary" : false, 30 | "DoNotUseSemicolons" : true, 31 | "DontRepeatTypeInStaticProperties" : true, 32 | "FileScopedDeclarationPrivacy" : true, 33 | "FullyIndirectEnum" : true, 34 | "GroupNumericLiterals" : true, 35 | "IdentifiersMustBeASCII" : true, 36 | "NeverForceUnwrap" : false, 37 | "NeverUseForceTry" : false, 38 | "NeverUseImplicitlyUnwrappedOptionals" : false, 39 | "NoAccessLevelOnExtensionDeclaration" : false, 40 | "NoAssignmentInExpressions" : true, 41 | "NoBlockComments" : false, 42 | "NoCasesWithOnlyFallthrough" : true, 43 | "NoEmptyTrailingClosureParentheses" : true, 44 | "NoLabelsInCasePatterns" : true, 45 | "NoLeadingUnderscores" : false, 46 | "NoParensAroundConditions" : true, 47 | "NoPlaygroundLiterals" : true, 48 | "NoVoidReturnOnFunctionSignature" : true, 49 | "OmitExplicitReturns" : false, 50 | "OneCasePerLine" : true, 51 | "OneVariableDeclarationPerLine" : true, 52 | "OnlyOneTrailingClosureArgument" : true, 53 | "OrderedImports" : true, 54 | "ReplaceForEachWithForLoop" : true, 55 | "ReturnVoidInsteadOfEmptyTuple" : true, 56 | "TypeNamesShouldBeCapitalized" : true, 57 | "UseEarlyExits" : false, 58 | "UseLetInEveryBoundCaseVariable" : false, 59 | "UseShorthandTypeNames" : true, 60 | "UseSingleLinePropertyGetter" : true, 61 | "UseSynthesizedInitializer" : false, 62 | "UseTripleSlashForDocumentationComments" : true, 63 | "UseWhereClausesInForLoops" : false, 64 | "ValidateDocumentationComments" : false 65 | }, 66 | "spacesAroundRangeFormationOperators" : false, 67 | "tabWidth" : 4, 68 | "version" : 1 69 | } 70 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - trailing_whitespace 3 | - todo 4 | 5 | line_length: 960 6 | function_body_length: 100 7 | 8 | excluded: 9 | - Sources/SPMPSL.swift 10 | - Tests 11 | - Carthage 12 | - Pods 13 | - fastlane 14 | -------------------------------------------------------------------------------- /FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [gumob] 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } 6 | 7 | gem "cocoapods" 8 | gem "cocoapods-deintegrate" 9 | gem "cocoapods-clean" 10 | gem "fastlane" 11 | gem "slather" 12 | gem "jazzy" 13 | gem "xcpretty" 14 | 15 | plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') 16 | eval_gemfile(plugins_path) if File.exist?(plugins_path) 17 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.7) 5 | base64 6 | nkf 7 | rexml 8 | activesupport (7.2.1) 9 | base64 10 | bigdecimal 11 | concurrent-ruby (~> 1.0, >= 1.3.1) 12 | connection_pool (>= 2.2.5) 13 | drb 14 | i18n (>= 1.6, < 2) 15 | logger (>= 1.4.2) 16 | minitest (>= 5.1) 17 | securerandom (>= 0.3) 18 | tzinfo (~> 2.0, >= 2.0.5) 19 | addressable (2.8.7) 20 | public_suffix (>= 2.0.2, < 7.0) 21 | algoliasearch (1.27.5) 22 | httpclient (~> 2.8, >= 2.8.3) 23 | json (>= 1.5.1) 24 | artifactory (3.0.17) 25 | atomos (0.1.3) 26 | aws-eventstream (1.3.0) 27 | aws-partitions (1.968.0) 28 | aws-sdk-core (3.201.5) 29 | aws-eventstream (~> 1, >= 1.3.0) 30 | aws-partitions (~> 1, >= 1.651.0) 31 | aws-sigv4 (~> 1.9) 32 | jmespath (~> 1, >= 1.6.1) 33 | aws-sdk-kms (1.88.0) 34 | aws-sdk-core (~> 3, >= 3.201.0) 35 | aws-sigv4 (~> 1.5) 36 | aws-sdk-s3 (1.159.0) 37 | aws-sdk-core (~> 3, >= 3.201.0) 38 | aws-sdk-kms (~> 1) 39 | aws-sigv4 (~> 1.5) 40 | aws-sigv4 (1.9.1) 41 | aws-eventstream (~> 1, >= 1.0.2) 42 | babosa (1.0.4) 43 | base64 (0.2.0) 44 | bigdecimal (3.1.8) 45 | claide (1.1.0) 46 | clamp (1.3.2) 47 | cocoapods (1.15.2) 48 | addressable (~> 2.8) 49 | claide (>= 1.0.2, < 2.0) 50 | cocoapods-core (= 1.15.2) 51 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 52 | cocoapods-downloader (>= 2.1, < 3.0) 53 | cocoapods-plugins (>= 1.0.0, < 2.0) 54 | cocoapods-search (>= 1.0.0, < 2.0) 55 | cocoapods-trunk (>= 1.6.0, < 2.0) 56 | cocoapods-try (>= 1.1.0, < 2.0) 57 | colored2 (~> 3.1) 58 | escape (~> 0.0.4) 59 | fourflusher (>= 2.3.0, < 3.0) 60 | gh_inspector (~> 1.0) 61 | molinillo (~> 0.8.0) 62 | nap (~> 1.0) 63 | ruby-macho (>= 2.3.0, < 3.0) 64 | xcodeproj (>= 1.23.0, < 2.0) 65 | cocoapods-clean (0.0.1) 66 | cocoapods-core (1.15.2) 67 | activesupport (>= 5.0, < 8) 68 | addressable (~> 2.8) 69 | algoliasearch (~> 1.0) 70 | concurrent-ruby (~> 1.1) 71 | fuzzy_match (~> 2.0.4) 72 | nap (~> 1.0) 73 | netrc (~> 0.11) 74 | public_suffix (~> 4.0) 75 | typhoeus (~> 1.0) 76 | cocoapods-deintegrate (1.0.5) 77 | cocoapods-downloader (2.1) 78 | cocoapods-plugins (1.0.0) 79 | nap 80 | cocoapods-search (1.0.1) 81 | cocoapods-trunk (1.6.0) 82 | nap (>= 0.8, < 2.0) 83 | netrc (~> 0.11) 84 | cocoapods-try (1.2.0) 85 | colored (1.2) 86 | colored2 (3.1.2) 87 | commander (4.6.0) 88 | highline (~> 2.0.0) 89 | concurrent-ruby (1.3.4) 90 | connection_pool (2.4.1) 91 | declarative (0.0.20) 92 | digest-crc (0.6.5) 93 | rake (>= 12.0.0, < 14.0.0) 94 | domain_name (0.6.20240107) 95 | dotenv (2.8.1) 96 | drb (2.2.1) 97 | emoji_regex (3.2.3) 98 | escape (0.0.4) 99 | ethon (0.16.0) 100 | ffi (>= 1.15.0) 101 | excon (0.111.0) 102 | faraday (1.10.3) 103 | faraday-em_http (~> 1.0) 104 | faraday-em_synchrony (~> 1.0) 105 | faraday-excon (~> 1.1) 106 | faraday-httpclient (~> 1.0) 107 | faraday-multipart (~> 1.0) 108 | faraday-net_http (~> 1.0) 109 | faraday-net_http_persistent (~> 1.0) 110 | faraday-patron (~> 1.0) 111 | faraday-rack (~> 1.0) 112 | faraday-retry (~> 1.0) 113 | ruby2_keywords (>= 0.0.4) 114 | faraday-cookie_jar (0.0.7) 115 | faraday (>= 0.8.0) 116 | http-cookie (~> 1.0.0) 117 | faraday-em_http (1.0.0) 118 | faraday-em_synchrony (1.0.0) 119 | faraday-excon (1.1.0) 120 | faraday-httpclient (1.0.1) 121 | faraday-multipart (1.0.4) 122 | multipart-post (~> 2) 123 | faraday-net_http (1.0.2) 124 | faraday-net_http_persistent (1.2.0) 125 | faraday-patron (1.0.0) 126 | faraday-rack (1.0.0) 127 | faraday-retry (1.0.3) 128 | faraday_middleware (1.2.0) 129 | faraday (~> 1.0) 130 | fastimage (2.3.1) 131 | fastlane (2.222.0) 132 | CFPropertyList (>= 2.3, < 4.0.0) 133 | addressable (>= 2.8, < 3.0.0) 134 | artifactory (~> 3.0) 135 | aws-sdk-s3 (~> 1.0) 136 | babosa (>= 1.0.3, < 2.0.0) 137 | bundler (>= 1.12.0, < 3.0.0) 138 | colored (~> 1.2) 139 | commander (~> 4.6) 140 | dotenv (>= 2.1.1, < 3.0.0) 141 | emoji_regex (>= 0.1, < 4.0) 142 | excon (>= 0.71.0, < 1.0.0) 143 | faraday (~> 1.0) 144 | faraday-cookie_jar (~> 0.0.6) 145 | faraday_middleware (~> 1.0) 146 | fastimage (>= 2.1.0, < 3.0.0) 147 | gh_inspector (>= 1.1.2, < 2.0.0) 148 | google-apis-androidpublisher_v3 (~> 0.3) 149 | google-apis-playcustomapp_v1 (~> 0.1) 150 | google-cloud-env (>= 1.6.0, < 2.0.0) 151 | google-cloud-storage (~> 1.31) 152 | highline (~> 2.0) 153 | http-cookie (~> 1.0.5) 154 | json (< 3.0.0) 155 | jwt (>= 2.1.0, < 3) 156 | mini_magick (>= 4.9.4, < 5.0.0) 157 | multipart-post (>= 2.0.0, < 3.0.0) 158 | naturally (~> 2.2) 159 | optparse (>= 0.1.1, < 1.0.0) 160 | plist (>= 3.1.0, < 4.0.0) 161 | rubyzip (>= 2.0.0, < 3.0.0) 162 | security (= 0.1.5) 163 | simctl (~> 1.6.3) 164 | terminal-notifier (>= 2.0.0, < 3.0.0) 165 | terminal-table (~> 3) 166 | tty-screen (>= 0.6.3, < 1.0.0) 167 | tty-spinner (>= 0.8.0, < 1.0.0) 168 | word_wrap (~> 1.0.0) 169 | xcodeproj (>= 1.13.0, < 2.0.0) 170 | xcpretty (~> 0.3.0) 171 | xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) 172 | fastlane-plugin-versioning (0.6.0) 173 | ffi (1.17.0-aarch64-linux-gnu) 174 | ffi (1.17.0-aarch64-linux-musl) 175 | ffi (1.17.0-arm-linux-gnu) 176 | ffi (1.17.0-arm-linux-musl) 177 | ffi (1.17.0-arm64-darwin) 178 | ffi (1.17.0-x86-linux-gnu) 179 | ffi (1.17.0-x86-linux-musl) 180 | ffi (1.17.0-x86_64-darwin) 181 | ffi (1.17.0-x86_64-linux-gnu) 182 | ffi (1.17.0-x86_64-linux-musl) 183 | fourflusher (2.3.1) 184 | fuzzy_match (2.0.4) 185 | gh_inspector (1.1.3) 186 | google-apis-androidpublisher_v3 (0.54.0) 187 | google-apis-core (>= 0.11.0, < 2.a) 188 | google-apis-core (0.11.3) 189 | addressable (~> 2.5, >= 2.5.1) 190 | googleauth (>= 0.16.2, < 2.a) 191 | httpclient (>= 2.8.1, < 3.a) 192 | mini_mime (~> 1.0) 193 | representable (~> 3.0) 194 | retriable (>= 2.0, < 4.a) 195 | rexml 196 | google-apis-iamcredentials_v1 (0.17.0) 197 | google-apis-core (>= 0.11.0, < 2.a) 198 | google-apis-playcustomapp_v1 (0.13.0) 199 | google-apis-core (>= 0.11.0, < 2.a) 200 | google-apis-storage_v1 (0.31.0) 201 | google-apis-core (>= 0.11.0, < 2.a) 202 | google-cloud-core (1.7.1) 203 | google-cloud-env (>= 1.0, < 3.a) 204 | google-cloud-errors (~> 1.0) 205 | google-cloud-env (1.6.0) 206 | faraday (>= 0.17.3, < 3.0) 207 | google-cloud-errors (1.4.0) 208 | google-cloud-storage (1.47.0) 209 | addressable (~> 2.8) 210 | digest-crc (~> 0.4) 211 | google-apis-iamcredentials_v1 (~> 0.1) 212 | google-apis-storage_v1 (~> 0.31.0) 213 | google-cloud-core (~> 1.6) 214 | googleauth (>= 0.16.2, < 2.a) 215 | mini_mime (~> 1.0) 216 | googleauth (1.8.1) 217 | faraday (>= 0.17.3, < 3.a) 218 | jwt (>= 1.4, < 3.0) 219 | multi_json (~> 1.11) 220 | os (>= 0.9, < 2.0) 221 | signet (>= 0.16, < 2.a) 222 | highline (2.0.3) 223 | http-cookie (1.0.7) 224 | domain_name (~> 0.5) 225 | httpclient (2.8.3) 226 | i18n (1.14.5) 227 | concurrent-ruby (~> 1.0) 228 | jazzy (0.15.1) 229 | cocoapods (~> 1.5) 230 | mustache (~> 1.1) 231 | open4 (~> 1.3) 232 | redcarpet (~> 3.4) 233 | rexml (>= 3.2.7, < 4.0) 234 | rouge (>= 2.0.6, < 5.0) 235 | sassc (~> 2.1) 236 | sqlite3 (~> 1.3) 237 | xcinvoke (~> 0.3.0) 238 | jmespath (1.6.2) 239 | json (2.7.2) 240 | jwt (2.8.2) 241 | base64 242 | liferaft (0.0.6) 243 | logger (1.6.0) 244 | mini_magick (4.13.2) 245 | mini_mime (1.1.5) 246 | minitest (5.25.1) 247 | molinillo (0.8.0) 248 | multi_json (1.15.0) 249 | multipart-post (2.4.1) 250 | mustache (1.1.1) 251 | nanaimo (0.3.0) 252 | nap (1.1.0) 253 | naturally (2.2.1) 254 | netrc (0.11.0) 255 | nkf (0.2.0) 256 | nokogiri (1.16.7-aarch64-linux) 257 | racc (~> 1.4) 258 | nokogiri (1.16.7-arm-linux) 259 | racc (~> 1.4) 260 | nokogiri (1.16.7-arm64-darwin) 261 | racc (~> 1.4) 262 | nokogiri (1.16.7-x86-linux) 263 | racc (~> 1.4) 264 | nokogiri (1.16.7-x86_64-darwin) 265 | racc (~> 1.4) 266 | nokogiri (1.16.7-x86_64-linux) 267 | racc (~> 1.4) 268 | open4 (1.3.4) 269 | optparse (0.5.0) 270 | os (1.1.4) 271 | plist (3.7.1) 272 | public_suffix (4.0.7) 273 | racc (1.8.1) 274 | rake (13.2.1) 275 | redcarpet (3.6.0) 276 | representable (3.2.0) 277 | declarative (< 0.1.0) 278 | trailblazer-option (>= 0.1.1, < 0.2.0) 279 | uber (< 0.2.0) 280 | retriable (3.1.2) 281 | rexml (3.3.6) 282 | strscan 283 | rouge (2.0.7) 284 | ruby-macho (2.5.1) 285 | ruby2_keywords (0.0.5) 286 | rubyzip (2.3.2) 287 | sassc (2.4.0) 288 | ffi (~> 1.9) 289 | securerandom (0.3.1) 290 | security (0.1.5) 291 | signet (0.19.0) 292 | addressable (~> 2.8) 293 | faraday (>= 0.17.5, < 3.a) 294 | jwt (>= 1.5, < 3.0) 295 | multi_json (~> 1.10) 296 | simctl (1.6.10) 297 | CFPropertyList 298 | naturally 299 | slather (2.8.3) 300 | CFPropertyList (>= 2.2, < 4) 301 | activesupport 302 | clamp (~> 1.3) 303 | nokogiri (>= 1.14.3) 304 | xcodeproj (~> 1.21) 305 | sqlite3 (1.7.3-aarch64-linux) 306 | sqlite3 (1.7.3-arm-linux) 307 | sqlite3 (1.7.3-arm64-darwin) 308 | sqlite3 (1.7.3-x86-linux) 309 | sqlite3 (1.7.3-x86_64-darwin) 310 | sqlite3 (1.7.3-x86_64-linux) 311 | strscan (3.1.0) 312 | terminal-notifier (2.0.0) 313 | terminal-table (3.0.2) 314 | unicode-display_width (>= 1.1.1, < 3) 315 | trailblazer-option (0.1.2) 316 | tty-cursor (0.7.1) 317 | tty-screen (0.8.2) 318 | tty-spinner (0.9.3) 319 | tty-cursor (~> 0.7) 320 | typhoeus (1.4.1) 321 | ethon (>= 0.9.0) 322 | tzinfo (2.0.6) 323 | concurrent-ruby (~> 1.0) 324 | uber (0.1.0) 325 | unicode-display_width (2.5.0) 326 | word_wrap (1.0.0) 327 | xcinvoke (0.3.0) 328 | liferaft (~> 0.0.6) 329 | xcodeproj (1.25.0) 330 | CFPropertyList (>= 2.3.3, < 4.0) 331 | atomos (~> 0.1.3) 332 | claide (>= 1.0.2, < 2.0) 333 | colored2 (~> 3.1) 334 | nanaimo (~> 0.3.0) 335 | rexml (>= 3.3.2, < 4.0) 336 | xcpretty (0.3.0) 337 | rouge (~> 2.0.7) 338 | xcpretty-travis-formatter (1.0.1) 339 | xcpretty (~> 0.2, >= 0.0.7) 340 | 341 | PLATFORMS 342 | aarch64-linux 343 | aarch64-linux-gnu 344 | aarch64-linux-musl 345 | arm-linux 346 | arm-linux-gnu 347 | arm-linux-musl 348 | arm64-darwin 349 | x86-linux 350 | x86-linux-gnu 351 | x86-linux-musl 352 | x86_64-darwin 353 | x86_64-linux 354 | x86_64-linux-gnu 355 | x86_64-linux-musl 356 | 357 | DEPENDENCIES 358 | cocoapods 359 | cocoapods-clean 360 | cocoapods-deintegrate 361 | fastlane 362 | fastlane-plugin-versioning 363 | jazzy 364 | slather 365 | xcpretty 366 | 367 | BUNDLED WITH 368 | 2.5.17 369 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Gumob 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Punycode", 8 | products: [ 9 | .library( 10 | name: "Punycode", 11 | targets: ["Punycode"]) 12 | ], 13 | targets: [ 14 | .target( 15 | name: "Punycode", 16 | dependencies: [], 17 | path: "Sources"), 18 | .testTarget( 19 | name: "PunycodeSwiftTests", 20 | dependencies: ["Punycode"], 21 | path: "Tests") 22 | ] 23 | ) 24 | -------------------------------------------------------------------------------- /Punycode.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "Punycode" 4 | s.version = "3.0.0" 5 | s.summary = "A Pure Swift library for encode and decode punycoded strings supporting iOS, macOS, tvOS, watchOS, and visionOS." 6 | s.homepage = "https://github.com/gumob/PunycodeSwift" 7 | s.license = { :type => "MIT", :file => "LICENSE" } 8 | s.author = { "Kojiro Futamura" => "gumob.dev@gmail.com" } 9 | s.frameworks = 'Foundation' 10 | s.requires_arc = true 11 | s.source = { :git => "https://github.com/gumob/PunycodeSwift.git", :tag => "#{s.version}" } 12 | s.source_files = "Sources/*.{swift}" 13 | s.osx.deployment_target = "10.13" 14 | s.ios.deployment_target = "12.0" 15 | s.tvos.deployment_target = "12.0" 16 | s.watchos.deployment_target = "4.0" 17 | s.visionos.deployment_target = "1.0" 18 | s.swift_version = '5.0' 19 | 20 | end 21 | -------------------------------------------------------------------------------- /Punycode.xcodeproj/xcshareddata/xcschemes/Punycode.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 25 | 26 | 32 | 33 | 36 | 42 | 43 | 44 | 45 | 46 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Swift Package Manager compatible](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange)](https://github.com/gumob/PunycodeSwift) 2 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg)](https://github.com/gumob/PunycodeSwift) 3 | [![Cocoapods Version](https://img.shields.io/cocoapods/v/Punycode.svg)](https://cocoapods.org/pods/Punycode) 4 | [![Cocoapods Platform](https://img.shields.io/cocoapods/p/Punycode.svg)](https://cocoadocs.org/docsets/Punycode) 5 | [![Build](https://github.com/gumob/PunycodeSwift/actions/workflows/main.yml/badge.svg)](https://github.com/gumob/PunycodeSwift/actions/workflows/main.yml) 6 | [![codecov](https://codecov.io/gh/gumob/PunycodeSwift/branch/master/graph/badge.svg)](https://codecov.io/gh/gumob/PunycodeSwift) 7 | ![Language](https://img.shields.io/badge/Language-Swift%205.0-orange.svg) 8 | ![Packagist](https://img.shields.io/packagist/l/doctrine/orm.svg) 9 | 10 | # PunycodeSwift 11 | 12 | PunycodeSwift is a pure Swift library to allows you to encode and decode `punycoded` strings by using String extension. 13 | 14 | ## What is Punycode? 15 | 16 | Punycode is a representation of Unicode with the limited ASCII character subset used for Internet host names. Using Punycode, host names containing Unicode characters are transcoded to a subset of ASCII consisting of letters, digits, and hyphen, which is called the Letter-Digit-Hyphen (LDH) subset. For example, München (German name for Munich) is encoded as Mnchen-3ya. [(Wikipedia)](https://en.wikipedia.org/wiki/Punycode) 17 | 18 | ## Requirements 19 | - macOS 10.13 or later 20 | - iOS 12.0 or later 21 | - tvOS 12.0 or later 22 | - watchOS 4.0 or later 23 | - visionOS 1.0 or later 24 | - Swift 5.0 or later 25 | 26 | ## Installation 27 | 28 | ### Swift Package Manager 29 | 30 | Add the following to your `Package.swift` file. 31 | 32 | - macOS, iOS, tvOS, watchOS, visionOS, and Swift 5 33 | ```swift 34 | dependencies: [ 35 | .package(url: "https://github.com/gumob/PunycodeSwift.git", .upToNextMajor(from: "3.0.0")) 36 | ] 37 | ``` 38 | 39 | - macOS, iOS, tvOS, and Swift 5 40 | ```swift 41 | dependencies: [ 42 | .package(url: "https://github.com/gumob/PunycodeSwift.git", .upToNextMajor(from: "2.1.1")) 43 | ] 44 | ``` 45 | 46 | ### Carthage 47 | 48 | Add the following to your `Cartfile` and follow [these instructions](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application). 49 | 50 | - macOS, iOS, tvOS, watchOS, visionOS, and Swift 5 51 | 52 | ``` 53 | github "gumob/PunycodeSwift" ~> 3.0 54 | ``` 55 | 56 | - macOS, iOS, tvOS, and Swift 5 57 | 58 | ``` 59 | github "gumob/PunycodeSwift" ~> 2.0 60 | ``` 61 | 62 | - macOS, iOS, tvOS, and Swift 4 63 | 64 | ``` 65 | github "gumob/PunycodeSwift" ~> 1.0 66 | ``` 67 | 68 | ### CocoaPods 69 | 70 | To integrate TLDExtract into your project, add the following to your `Podfile`. 71 | 72 | - macOS, iOS, tvOS, watchOS, visionOS, and Swift 5.0 73 | 74 | ```ruby 75 | pod 'Punycode', '~> 3.0' 76 | ``` 77 | 78 | - macOS, iOS, tvOS, and Swift 5.0 79 | 80 | ```ruby 81 | pod 'Punycode', '~> 2.0' 82 | ``` 83 | 84 | - macOS, iOS, tvOS, and Swift 4.2 85 | 86 | ```ruby 87 | pod 'Punycode', '~> 1.0' 88 | ``` 89 | 90 | ## Usage 91 | 92 | Full documentation is available at [https://gumob.github.io/PunycodeSwift/swiftdoc/](https://gumob.github.io/PunycodeSwift/swiftdoc/). 93 | 94 | ### Encode and decode IDNA: 95 | 96 | ```swift 97 | import Punycode 98 | 99 | var sushi: String = "寿司" 100 | 101 | sushi = sushi.idnaEncoded! 102 | print(sushi) // xn--sprr0q 103 | 104 | sushi = sushi.idnaDecoded! 105 | print(sushi) // "寿司" 106 | ``` 107 | 108 | ### Encode and decode Punycode directly: 109 | 110 | ```swift 111 | import Punycode 112 | 113 | var sushi: String = "寿司" 114 | 115 | sushi = sushi.punycodeEncoded! 116 | print(sushi) // sprr0q 117 | 118 | sushi = sushi.punycodeDecoded! 119 | print(sushi) // "寿司" 120 | ``` 121 | 122 | ## Copyright 123 | 124 | Punycode is released under MIT license, which means you can modify it, redistribute it or use it however you like. 125 | -------------------------------------------------------------------------------- /Sources/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Kojiro Futamura on 2018-11-19. 3 | // 4 | 5 | import Foundation 6 | 7 | /// This extension provides methods for encoding and decoding strings using Punycode (RFC 3492) 8 | /// and IDNA encoding. It allows for the conversion of Substring instances to their Punycode 9 | /// and IDNA representations, facilitating the handling of internationalized domain names. 10 | public extension Substring { 11 | /// Returns new string in punycode encoding (RFC 3492) 12 | /// 13 | /// - Returns: Punycode encoded string or nil if the string can't be encoded 14 | var punycodeEncoded: String? { 15 | return Puny().encodePunycode(self) 16 | } 17 | 18 | /// Returns new string decoded from punycode representation (RFC 3492) 19 | /// 20 | /// - Returns: Original string or nil if the string doesn't contain correct encoding 21 | var punycodeDecoded: String? { 22 | return Puny().decodePunycode(self) 23 | } 24 | 25 | /// Returns new string containing IDNA-encoded hostname 26 | /// 27 | /// - Returns: IDNA encoded hostname or nil if the string can't be encoded 28 | var idnaEncoded: String? { 29 | return Puny().encodeIDNA(self) 30 | } 31 | 32 | /// Returns new string containing hostname decoded from IDNA representation 33 | /// 34 | /// - Returns: Original hostname or nil if the string doesn't contain correct encoding 35 | var idnaDecoded: String? { 36 | return Puny().decodedIDNA(self) 37 | } 38 | } 39 | 40 | /// This extension provides methods for encoding and decoding strings using Punycode (RFC 3492) 41 | /// and IDNA encoding. It allows for the conversion of String instances to their Punycode 42 | /// and IDNA representations, facilitating the handling of internationalized domain names. 43 | public extension String { 44 | 45 | /// Returns new string in punycode encoding (RFC 3492) 46 | /// 47 | /// - Returns: Punycode encoded string or nil if the string can't be encoded 48 | var punycodeEncoded: String? { 49 | return self[.. String.Index? { 13 | var position: Index = endIndex 14 | while position > startIndex { 15 | position = self.index(before: position) 16 | if self[position] == element { 17 | return position 18 | } 19 | } 20 | return nil 21 | } 22 | } 23 | 24 | /// A computed property that checks if the Unicode scalar is valid. 25 | /// 26 | /// - Returns: A boolean value indicating whether the Unicode scalar is valid. 27 | /// A Unicode scalar is considered valid if its value is less than 0xD880 28 | /// or within the range of 0xE000 to 0x1FFFFF. 29 | extension UnicodeScalar { 30 | internal var isValid: Bool { 31 | return value < 0xD880 || (value >= 0xE000 && value <= 0x1FFFFF) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Punycode.h: -------------------------------------------------------------------------------- 1 | // 2 | // Punycode.h 3 | // Punycode 4 | // 5 | // Created by Kojiro Futamura on 2024/08/25. 6 | // 7 | 8 | #import 9 | 10 | //! Project version number for Punycode. 11 | FOUNDATION_EXPORT double PunycodeVersionNumber; 12 | 13 | //! Project version string for Punycode. 14 | FOUNDATION_EXPORT const unsigned char PunycodeVersionString[]; 15 | 16 | // In this header, you should import all the public headers of your framework using statements like #import 17 | -------------------------------------------------------------------------------- /Sources/Punycode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Kojiro Futamura on 2018-11-19. 3 | // 4 | 5 | import Foundation 6 | 7 | /// Puny class provides methods to encode and decode strings using Punycode (RFC 3492). 8 | /// It allows for the conversion of Unicode strings into ASCII-compatible encoding, 9 | /// which is essential for domain names and other applications that require ASCII representation. 10 | /// 11 | /// - Note: This implementation follows the specifications outlined in RFC 3492. 12 | /// - Usage: Create an instance of Puny and call the appropriate methods for encoding or decoding. 13 | public class Puny { 14 | 15 | /// Punycode RFC 3492 16 | /// See https://www.ietf.org/rfc/rfc3492.txt for standard details 17 | 18 | /// Base value for Punycode encoding, representing the number of valid characters. 19 | private let base: Int = 36 20 | 21 | /// Minimum threshold for the number of characters to be encoded. 22 | private let tMin: Int = 1 23 | 24 | /// Maximum threshold for the number of characters to be encoded. 25 | private let tMax: Int = 26 26 | 27 | /// Skew value used in the adaptation of the bias. 28 | private let skew: Int = 38 29 | 30 | /// Damping factor used in the adaptation of the bias. 31 | private let damp: Int = 700 32 | 33 | /// Initial bias value for the encoding process. 34 | private let initialBias: Int = 72 35 | 36 | /// Initial value for the encoded characters. 37 | private let initialN: Int = 128 38 | 39 | /// Delimiter used in Punycode encoding to separate encoded segments. (RFC 3492 specific) 40 | private let delimiter: Character = "-" 41 | 42 | /// Range of lowercase letters used in Punycode encoding. 43 | private let lowercase: ClosedRange = "a"..."z" 44 | 45 | /// Range of digits used in Punycode encoding. 46 | private let digits: ClosedRange = "0"..."9" 47 | 48 | /// Base value for lowercase letters in Unicode scalar representation. 49 | private let lettersBase: UInt32 = Character("a").unicodeScalars.first!.value 50 | 51 | /// Base value for digits in Unicode scalar representation. 52 | private let digitsBase: UInt32 = Character("0").unicodeScalars.first!.value 53 | 54 | /// IDNA 55 | private let ace: String = "xn--" 56 | 57 | /// Adjusts the bias for Punycode encoding based on the given delta and number of points. 58 | /// This function is used to adapt the bias during the encoding process to ensure proper 59 | /// distribution of encoded characters. 60 | /// 61 | /// - Parameters: 62 | /// - delta: The value to be adjusted. 63 | /// - numberOfPoints: The number of points to consider for the adjustment. 64 | /// - firstTime: A boolean indicating if this is the first adjustment. 65 | /// - Returns: The adjusted bias value as an integer. 66 | private func adaptBias(_ delta: Int, _ numberOfPoints: Int, _ firstTime: Bool) -> Int { 67 | var delta: Int = delta 68 | if firstTime { 69 | delta /= damp 70 | } else { 71 | delta /= 2 72 | } 73 | delta += delta / numberOfPoints 74 | var k: Int = 0 75 | while delta > ((base - tMin) * tMax) / 2 { 76 | delta /= base - tMin 77 | k += base 78 | } 79 | return k + ((base - tMin + 1) * delta) / (delta + skew) 80 | } 81 | 82 | /// Maps a punycode character to its corresponding index. 83 | /// 84 | /// - Parameter character: The punycode character to be mapped. 85 | /// - Returns: The index of the character if it is a valid punycode character; otherwise, nil. 86 | private func punycodeIndex(for character: Character) -> Int? { 87 | if lowercase.contains(character) { 88 | return Int(character.unicodeScalars.first!.value - lettersBase) 89 | } else if digits.contains(character) { 90 | return Int(character.unicodeScalars.first!.value - digitsBase) + 26/// count of lowercase letters range 91 | } else { 92 | return nil 93 | } 94 | } 95 | 96 | /// Maps an index to its corresponding punycode character. 97 | /// 98 | /// - Parameter digit: The integer digit to be mapped. 99 | /// - Returns: The corresponding punycode character if the digit is valid; otherwise, nil. 100 | private func punycodeValue(for digit: Int) -> Character? { 101 | guard digit < base else { return nil } 102 | if digit < 26 { 103 | return Character(UnicodeScalar(lettersBase.advanced(by: digit))!) 104 | } else { 105 | return Character(UnicodeScalar(digitsBase.advanced(by: digit - 26))!) 106 | } 107 | } 108 | 109 | /// Decodes a punycode encoded string to its original representation. 110 | /// 111 | /// - Parameter punycode: A substring containing the punycode encoding (RFC 3492). 112 | /// - Returns: The decoded original string or nil if the input cannot be decoded due to invalid formatting. 113 | public func decodePunycode(_ punycode: Substring) -> String? { 114 | var n: Int = initialN 115 | var i: Int = 0 116 | var bias: Int = initialBias 117 | var output: [Character] = [] 118 | var inputPosition: Substring.Index = punycode.startIndex 119 | 120 | let delimiterPosition: Substring.Index = punycode.lastIndex(of: delimiter) ?? punycode.startIndex 121 | if delimiterPosition > punycode.startIndex { 122 | output.append(contentsOf: punycode[..= bias + tMax ? tMax : k - bias) 137 | if digit < t { 138 | break 139 | } 140 | w *= base - t 141 | k += base 142 | } while !punycodeInput.isEmpty 143 | bias = adaptBias(i - oldI, output.count + 1, oldI == 0) 144 | n += i / (output.count + 1) 145 | i %= (output.count + 1) 146 | guard n >= 0x80, let scalar: Unicode.Scalar = UnicodeScalar(n) else { 147 | return nil 148 | } 149 | output.insert(Character(scalar), at: i) 150 | i += 1 151 | } 152 | 153 | return String(output) 154 | } 155 | 156 | /// Encodes a substring to punycode (RFC 3492). 157 | /// 158 | /// - Parameter input: A substring to be encoded in punycode. 159 | /// - Returns: A punycode encoded string or nil if the input contains invalid characters. 160 | public func encodePunycode(_ input: Substring) -> String? { 161 | var n: Int = initialN 162 | var delta: Int = 0 163 | var bias: Int = initialBias 164 | var output: String = "" 165 | for scalar: Substring.UnicodeScalarView.Element in input.unicodeScalars { 166 | if scalar.isASCII { 167 | let char: Character = Character(scalar) 168 | output.append(char) 169 | } else if !scalar.isValid { 170 | return nil/// Encountered a scalar out of acceptable range 171 | } 172 | } 173 | var handled: Int = output.count 174 | let basic: Int = handled 175 | if basic > 0 { 176 | output.append(delimiter) 177 | } 178 | while handled < input.unicodeScalars.count { 179 | var minimumCodepoint: Int = 0x10FFFF 180 | for scalar: Unicode.Scalar in input.unicodeScalars { 181 | if scalar.value < minimumCodepoint && scalar.value >= n { 182 | minimumCodepoint = Int(scalar.value) 183 | } 184 | } 185 | delta += (minimumCodepoint - n) * (handled + 1) 186 | n = minimumCodepoint 187 | for scalar: Unicode.Scalar in input.unicodeScalars { 188 | if scalar.value < n { 189 | delta += 1 190 | } else if scalar.value == n { 191 | var q: Int = delta 192 | var k: Int = base 193 | while true { 194 | let t: Int = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias) 195 | if q < t { 196 | break 197 | } 198 | guard let character: Character = punycodeValue(for: t + ((q - t) % (base - t))) else { return nil } 199 | output.append(character) 200 | q = (q - t) / (base - t) 201 | k += base 202 | } 203 | guard let character: Character = punycodeValue(for: q) else { return nil } 204 | output.append(character) 205 | bias = adaptBias(delta, handled + 1, handled == basic) 206 | delta = 0 207 | handled += 1 208 | } 209 | } 210 | delta += 1 211 | n += 1 212 | } 213 | 214 | return output 215 | } 216 | 217 | /// Returns new string containing IDNA-encoded hostname. 218 | /// 219 | /// - Parameter input: The Substring to be encoded. 220 | /// - Returns: An IDNA encoded hostname or nil if the string can't be encoded. 221 | public func encodeIDNA(_ input: Substring) -> String? { 222 | let parts: [Substring] = input.split(separator: ".") 223 | var output: String = "" 224 | for part: Substring in parts { 225 | if output.count > 0 { 226 | output.append(".") 227 | } 228 | if part.rangeOfCharacter(from: CharacterSet.urlHostAllowed.inverted) != nil { 229 | guard let encoded: String = part.lowercased().punycodeEncoded else { return nil } 230 | output += ace + encoded 231 | } else { 232 | output += part 233 | } 234 | } 235 | return output 236 | } 237 | 238 | /// Returns a new string containing the hostname decoded from IDNA representation. 239 | /// 240 | /// - Parameter input: The Substring to be decoded. 241 | /// - Returns: The original hostname or nil if the string doesn't contain correct encoding. 242 | public func decodedIDNA(_ input: Substring) -> String? { 243 | let parts: [Substring] = input.split(separator: ".") 244 | var output: String = "" 245 | for part: Substring in parts { 246 | if output.count > 0 { 247 | output.append(".") 248 | } 249 | if part.hasPrefix(ace) { 250 | guard let decoded: String = part.dropFirst(ace.count).punycodeDecoded else { return nil } 251 | output += decoded 252 | } else { 253 | output += part 254 | } 255 | } 256 | return output 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /Tests/PunycodeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PunycodeTests.swift 3 | // PunycodeTests 4 | // 5 | // Created by Kojiro Futamura on 2024/08/25. 6 | // 7 | 8 | import XCTest 9 | 10 | @testable import Punycode 11 | 12 | final class PunycodeTests: XCTestCase { 13 | 14 | let egyptian: String = "\u{0644}\u{064A}\u{0647}\u{0645}\u{0627}\u{0628}\u{062A}\u{0643}\u{0644}\u{0645}\u{0648}\u{0634}\u{0639}\u{0631}\u{0628}\u{064A}\u{061F}" 15 | let chineseSimplified: String = "\u{4ED6}\u{4EEC}\u{4E3A}\u{4EC0}\u{4E48}\u{4E0D}\u{8BF4}\u{4E2D}\u{6587}" 16 | let chineseTraditional: String = "\u{4ED6}\u{5011}\u{7232}\u{4EC0}\u{9EBD}\u{4E0D}\u{8AAA}\u{4E2D}\u{6587}" 17 | let czech: String = 18 | "\u{0050}\u{0072}\u{006F}\u{010D}\u{0070}\u{0072}\u{006F}\u{0073}\u{0074}\u{011B}\u{006E}\u{0065}\u{006D}\u{006C}\u{0075}\u{0076}\u{00ED}\u{010D}\u{0065}\u{0073}\u{006B}\u{0079}" 19 | let hebrew: String = 20 | "\u{05DC}\u{05DE}\u{05D4}\u{05D4}\u{05DD}\u{05E4}\u{05E9}\u{05D5}\u{05D8}\u{05DC}\u{05D0}\u{05DE}\u{05D3}\u{05D1}\u{05E8}\u{05D9}\u{05DD}\u{05E2}\u{05D1}\u{05E8}\u{05D9}\u{05EA}" 21 | let hindi: String = 22 | "\u{092F}\u{0939}\u{0932}\u{094B}\u{0917}\u{0939}\u{093F}\u{0928}\u{094D}\u{0926}\u{0940}\u{0915}\u{094D}\u{092F}\u{094B}\u{0902}\u{0928}\u{0939}\u{0940}\u{0902}\u{092C}\u{094B}\u{0932}\u{0938}\u{0915}\u{0924}\u{0947}\u{0939}\u{0948}\u{0902}" 23 | let japanese: String = "\u{306A}\u{305C}\u{307F}\u{3093}\u{306A}\u{65E5}\u{672C}\u{8A9E}\u{3092}\u{8A71}\u{3057}\u{3066}\u{304F}\u{308C}\u{306A}\u{3044}\u{306E}\u{304B}" 24 | let korean: String = 25 | "\u{C138}\u{ACC4}\u{C758}\u{BAA8}\u{B4E0}\u{C0AC}\u{B78C}\u{B4E4}\u{C774}\u{D55C}\u{AD6D}\u{C5B4}\u{B97C}\u{C774}\u{D574}\u{D55C}\u{B2E4}\u{BA74}\u{C5BC}\u{B9C8}\u{B098}\u{C88B}\u{C744}\u{AE4C}" 26 | let russian: String = 27 | "\u{043F}\u{043E}\u{0447}\u{0435}\u{043C}\u{0443}\u{0436}\u{0435}\u{043E}\u{043D}\u{0438}\u{043D}\u{0435}\u{0433}\u{043E}\u{0432}\u{043E}\u{0440}\u{044F}\u{0442}\u{043F}\u{043E}\u{0440}\u{0443}\u{0441}\u{0441}\u{043A}\u{0438}" 28 | let spanish: String = 29 | "\u{0050}\u{006F}\u{0072}\u{0071}\u{0075}\u{00E9}\u{006E}\u{006F}\u{0070}\u{0075}\u{0065}\u{0064}\u{0065}\u{006E}\u{0073}\u{0069}\u{006D}\u{0070}\u{006C}\u{0065}\u{006D}\u{0065}\u{006E}\u{0074}\u{0065}\u{0068}\u{0061}\u{0062}\u{006C}\u{0061}\u{0072}\u{0065}\u{006E}\u{0045}\u{0073}\u{0070}\u{0061}\u{00F1}\u{006F}\u{006C}" 30 | let vietnamese: String = 31 | "\u{0054}\u{1EA1}\u{0069}\u{0073}\u{0061}\u{006F}\u{0068}\u{1ECD}\u{006B}\u{0068}\u{00F4}\u{006E}\u{0067}\u{0074}\u{0068}\u{1EC3}\u{0063}\u{0068}\u{1EC9}\u{006E}\u{00F3}\u{0069}\u{0074}\u{0069}\u{1EBF}\u{006E}\u{0067}\u{0056}\u{0069}\u{1EC7}\u{0074}" 32 | 33 | let jBlockL: String = "\u{0033}\u{5E74}\u{0042}\u{7D44}\u{91D1}\u{516B}\u{5148}\u{751F}" 34 | let jBlockM: String = 35 | "\u{5B89}\u{5BA4}\u{5948}\u{7F8E}\u{6075}\u{002D}\u{0077}\u{0069}\u{0074}\u{0068}\u{002D}\u{0053}\u{0055}\u{0050}\u{0045}\u{0052}\u{002D}\u{004D}\u{004F}\u{004E}\u{004B}\u{0045}\u{0059}\u{0053}" 36 | let jBlockN: String = 37 | "\u{0048}\u{0065}\u{006C}\u{006C}\u{006F}\u{002D}\u{0041}\u{006E}\u{006F}\u{0074}\u{0068}\u{0065}\u{0072}\u{002D}\u{0057}\u{0061}\u{0079}\u{002D}\u{305D}\u{308C}\u{305E}\u{308C}\u{306E}\u{5834}\u{6240}" 38 | let jBlockO: String = "\u{3072}\u{3068}\u{3064}\u{5C4B}\u{6839}\u{306E}\u{4E0B}\u{0032}" 39 | let jBlockP: String = "\u{004D}\u{0061}\u{006A}\u{0069}\u{3067}\u{004B}\u{006F}\u{0069}\u{3059}\u{308B}\u{0035}\u{79D2}\u{524D}" 40 | let jBlockQ: String = "\u{30D1}\u{30D5}\u{30A3}\u{30FC}\u{0064}\u{0065}\u{30EB}\u{30F3}\u{30D0}" 41 | let jBlockR: String = "\u{305D}\u{306E}\u{30B9}\u{30D4}\u{30FC}\u{30C9}\u{3067}" 42 | 43 | let plain: String = "\u{002D}\u{003E}\u{0020}\u{0024}\u{0031}\u{002E}\u{0030}\u{0030}\u{0020}\u{003C}\u{002D}" 44 | let multiscalar: String = "🇨🇦" 45 | let idna: String = "погода-в-египте.рф.com" 46 | 47 | let egyptianCode: String = "egbpdaj6bu4bxfgehfvwxn" 48 | let chineseSimplifiedCode: String = "ihqwcrb4cv8a8dqg056pqjye" 49 | let chineseTraditionalCode: String = "ihqwctvzc91f659drss3x8bo0yb" 50 | let czechCode: String = "Proprostnemluvesky-uyb24dma41a" 51 | let hebrewCode: String = "4dbcagdahymbxekheh6e0a7fei0b" 52 | let hindiCode: String = "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd" 53 | let japaneseCode: String = "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa" 54 | let koreanCode: String = "989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c" 55 | let russianCode: String = "b1abfaaepdrnnbgefbadotcwatmq2g4l" 56 | let spanishCode: String = "PorqunopuedensimplementehablarenEspaol-fmd56a" 57 | let vietnameseCode: String = "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g" 58 | 59 | let jBlockLCode: String = "3B-ww4c5e180e575a65lsy2b" 60 | let jBlockMCode: String = "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n" 61 | let jBlockNCode: String = "Hello-Another-Way--fc4qua05auwb3674vfr0b" 62 | let jBlockOCode: String = "2-u9tlzr9756bt3uc0v" 63 | let jBlockPCode: String = "MajiKoi5-783gue6qz075azm5e" 64 | let jBlockQCode: String = "de-jg4avhby1noc0d" 65 | let jBlockRCode: String = "d9juau41awczczp" 66 | 67 | let plainCode: String = "-> $1.00 <--" 68 | let multiscalarCode: String = "e77hd" 69 | 70 | let idnaCode: String = "xn-----6kcjcecmb3a1dbkl9b.xn--p1ai.com" 71 | 72 | /// https://tools.ietf.org/html/rfc3492#section-7 73 | 74 | func testEncodingCorrectness() { 75 | XCTAssert(egyptian.punycodeEncoded == egyptianCode) 76 | XCTAssert(chineseSimplified.punycodeEncoded == chineseSimplifiedCode) 77 | XCTAssert(chineseTraditional.punycodeEncoded == chineseTraditionalCode) 78 | XCTAssert(czech.punycodeEncoded == czechCode) 79 | XCTAssert(hebrew.punycodeEncoded == hebrewCode) 80 | XCTAssert(hindi.punycodeEncoded == hindiCode) 81 | XCTAssert(japanese.punycodeEncoded == japaneseCode) 82 | XCTAssert(korean.punycodeEncoded == koreanCode) 83 | XCTAssert(russian.punycodeEncoded == russianCode) 84 | XCTAssert(spanish.punycodeEncoded == spanishCode) 85 | XCTAssert(vietnamese.punycodeEncoded == vietnameseCode) 86 | 87 | XCTAssert(jBlockL.punycodeEncoded == jBlockLCode) 88 | XCTAssert(jBlockM.punycodeEncoded == jBlockMCode) 89 | XCTAssert(jBlockN.punycodeEncoded == jBlockNCode) 90 | XCTAssert(jBlockO.punycodeEncoded == jBlockOCode) 91 | XCTAssert(jBlockP.punycodeEncoded == jBlockPCode) 92 | XCTAssert(jBlockQ.punycodeEncoded == jBlockQCode) 93 | XCTAssert(jBlockR.punycodeEncoded == jBlockRCode) 94 | 95 | XCTAssert(multiscalar.punycodeEncoded == multiscalarCode) 96 | XCTAssert(plain.punycodeEncoded == plainCode) 97 | 98 | XCTAssert(idna.idnaEncoded == idnaCode) 99 | } 100 | 101 | func testDecodingCorrectness() { 102 | XCTAssert(egyptianCode.punycodeDecoded == egyptian) 103 | XCTAssert(chineseSimplifiedCode.punycodeDecoded == chineseSimplified) 104 | XCTAssert(chineseTraditionalCode.punycodeDecoded == chineseTraditional) 105 | XCTAssert(czechCode.punycodeDecoded == czech) 106 | XCTAssert(hebrewCode.punycodeDecoded == hebrew) 107 | XCTAssert(hindiCode.punycodeDecoded == hindi) 108 | XCTAssert(japaneseCode.punycodeDecoded == japanese) 109 | XCTAssert(koreanCode.punycodeDecoded == korean) 110 | XCTAssert(russianCode.punycodeDecoded == russian) 111 | XCTAssert(spanishCode.punycodeDecoded == spanish) 112 | XCTAssert(vietnameseCode.punycodeDecoded == vietnamese) 113 | 114 | XCTAssert(jBlockLCode.punycodeDecoded == jBlockL) 115 | XCTAssert(jBlockMCode.punycodeDecoded == jBlockM) 116 | XCTAssert(jBlockNCode.punycodeDecoded == jBlockN) 117 | XCTAssert(jBlockOCode.punycodeDecoded == jBlockO) 118 | XCTAssert(jBlockPCode.punycodeDecoded == jBlockP) 119 | XCTAssert(jBlockQCode.punycodeDecoded == jBlockQ) 120 | XCTAssert(jBlockRCode.punycodeDecoded == jBlockR) 121 | 122 | XCTAssert(multiscalarCode.punycodeDecoded == multiscalar) 123 | XCTAssert(plainCode.punycodeDecoded == plain) 124 | 125 | XCTAssert(idnaCode.idnaDecoded == idna) 126 | } 127 | 128 | func testInvalidPunycodeIsNotFatal() { 129 | let invalidPunycode: String = "xn--g" 130 | XCTAssertNoThrow(invalidPunycode.idnaDecoded) 131 | } 132 | 133 | // func testFoo1() { 134 | // var sushi: String = "寿司" 135 | // 136 | // sushi = sushi.idnaEncoded! 137 | // print(sushi) // xn--sprr0q 138 | // 139 | // sushi = sushi.idnaDecoded! 140 | // print(sushi) // "寿司" 141 | // } 142 | // 143 | // func testFoo2() { 144 | // var sushi: String = "寿司" 145 | // 146 | // sushi = sushi.punycodeEncoded! 147 | // print(sushi) // sprr0q 148 | // 149 | // sushi = sushi.punycodeDecoded! 150 | // print(sushi) // "寿司" 151 | // } 152 | // 153 | // func testFoo3() { 154 | // var sushi: Substring = "寿司大好き".prefix(2) 155 | // print(sushi) // "寿司" 156 | // 157 | // var sushiStr = sushi.idnaEncoded! 158 | // print(sushiStr) // xn--sprr0q 159 | // 160 | // sushiStr = sushiStr.idnaDecoded! 161 | // print(sushiStr) // "寿司" 162 | // } 163 | // 164 | // func testFoo4() { 165 | // var sushi: Substring = "寿司大好き".prefix(2) 166 | // print(sushi) // "寿司" 167 | // 168 | // var sushiStr = sushi.punycodeEncoded! 169 | // print(sushiStr) // sprr0q 170 | // 171 | // sushiStr = sushiStr.punycodeDecoded! 172 | // print(sushiStr) // "寿司" 173 | // } 174 | } 175 | -------------------------------------------------------------------------------- /docs/swiftdoc/Classes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Classes Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Punycode 3.0.0 Docs 25 | 26 | 27 |

28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 |

36 | 37 | GitHub 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | Dash 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 80 |
81 | 82 |
83 |
84 |

Classes

85 |

The following classes are available globally.

86 | 87 |
88 |
89 | 90 |
91 |
92 |
93 |
    94 |
  • 95 |
    96 | 97 | 98 | 99 | Puny 100 | 101 |
    102 |
    103 |
    104 |
    105 |
    106 |
    107 |

    Puny class provides methods to encode and decode strings using Punycode (RFC 3492). 108 | It allows for the conversion of Unicode strings into ASCII-compatible encoding, 109 | which is essential for domain names and other applications that require ASCII representation.

    110 |
    111 |

    Note

    112 | This implementation follows the specifications outlined in RFC 3492. 113 | 114 |
      115 |
    • Usage: Create an instance of Puny and call the appropriate methods for encoding or decoding.
    • 116 |
    117 | 118 | See more 119 |
    120 |
    121 |

    Declaration

    122 |
    123 |

    Swift

    124 |
    public class Puny
    125 | 126 |
    127 |
    128 |
    129 |
    130 |
  • 131 |
132 |
133 |
134 |
135 | 136 |
137 |
138 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /docs/swiftdoc/Extensions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Extensions Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Punycode 3.0.0 Docs 25 | 26 | 27 |

28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 |

36 | 37 | GitHub 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | Dash 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 80 |
81 | 82 |
83 |
84 |

Extensions

85 |

The following extensions are available globally.

86 | 87 |
88 |
89 | 90 |
91 |
92 |
93 |
    94 |
  • 95 |
    96 | 97 | 98 | 99 | Substring 100 | 101 |
    102 |
    103 |
    104 |
    105 |
    106 |
    107 |

    This extension provides methods for encoding and decoding strings using Punycode (RFC 3492) 108 | and IDNA encoding. It allows for the conversion of Substring instances to their Punycode 109 | and IDNA representations, facilitating the handling of internationalized domain names.

    110 | 111 | See more 112 |
    113 |
    114 |

    Declaration

    115 |
    116 |

    Swift

    117 |
    public extension Substring
    118 | 119 |
    120 |
    121 |
    122 |
    123 |
  • 124 |
  • 125 |
    126 | 127 | 128 | 129 | String 130 | 131 |
    132 |
    133 |
    134 |
    135 |
    136 |
    137 |

    This extension provides methods for encoding and decoding strings using Punycode (RFC 3492) 138 | and IDNA encoding. It allows for the conversion of String instances to their Punycode 139 | and IDNA representations, facilitating the handling of internationalized domain names.

    140 | 141 | See more 142 |
    143 |
    144 |

    Declaration

    145 |
    146 |

    Swift

    147 |
    public extension String
    148 | 149 |
    150 |
    151 |
    152 |
    153 |
  • 154 |
155 |
156 |
157 |
158 | 159 |
160 |
161 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /docs/swiftdoc/Extensions/String.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | String Extension Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Punycode 3.0.0 Docs 25 | 26 | 27 |

28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 |

36 | 37 | GitHub 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | Dash 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 57 | 58 |
59 | 82 |
83 | 84 |
85 |
86 |

String

87 |
88 |
89 | 90 |
public extension String
91 | 92 |
93 |
94 |

This extension provides methods for encoding and decoding strings using Punycode (RFC 3492) 95 | and IDNA encoding. It allows for the conversion of String instances to their Punycode 96 | and IDNA representations, facilitating the handling of internationalized domain names.

97 | 98 |
99 |
100 | 101 |
102 |
103 |
104 |
    105 |
  • 106 |
    107 | 108 | 109 | 110 | punycodeEncoded 111 | 112 |
    113 |
    114 |
    115 |
    116 |
    117 |
    118 |

    Returns new string in punycode encoding (RFC 3492)

    119 | 120 |
    121 |
    122 |

    Declaration

    123 |
    124 |

    Swift

    125 |
    var punycodeEncoded: String? { get }
    126 | 127 |
    128 |
    129 |
    130 |

    Return Value

    131 |

    Punycode encoded string or nil if the string can’t be encoded

    132 |
    133 |
    134 |
    135 |
  • 136 |
  • 137 |
    138 | 139 | 140 | 141 | punycodeDecoded 142 | 143 |
    144 |
    145 |
    146 |
    147 |
    148 |
    149 |

    Returns new string decoded from punycode representation (RFC 3492)

    150 | 151 |
    152 |
    153 |

    Declaration

    154 |
    155 |

    Swift

    156 |
    var punycodeDecoded: String? { get }
    157 | 158 |
    159 |
    160 |
    161 |

    Return Value

    162 |

    Original string or nil if the string doesn’t contain correct encoding

    163 |
    164 |
    165 |
    166 |
  • 167 |
  • 168 |
    169 | 170 | 171 | 172 | idnaEncoded 173 | 174 |
    175 |
    176 |
    177 |
    178 |
    179 |
    180 |

    Returns new string containing IDNA-encoded hostname

    181 | 182 |
    183 |
    184 |

    Declaration

    185 |
    186 |

    Swift

    187 |
    var idnaEncoded: String? { get }
    188 | 189 |
    190 |
    191 |
    192 |

    Return Value

    193 |

    IDNA encoded hostname or nil if the string can’t be encoded

    194 |
    195 |
    196 |
    197 |
  • 198 |
  • 199 |
    200 | 201 | 202 | 203 | idnaDecoded 204 | 205 |
    206 |
    207 |
    208 |
    209 |
    210 |
    211 |

    Returns new string containing hostname decoded from IDNA representation

    212 | 213 |
    214 |
    215 |

    Declaration

    216 |
    217 |

    Swift

    218 |
    var idnaDecoded: String? { get }
    219 | 220 |
    221 |
    222 |
    223 |

    Return Value

    224 |

    Original hostname or nil if the string doesn’t contain correct encoding

    225 |
    226 |
    227 |
    228 |
  • 229 |
230 |
231 |
232 |
233 | 234 |
235 |
236 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /docs/swiftdoc/Extensions/Substring.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Substring Extension Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Punycode 3.0.0 Docs 25 | 26 | 27 |

28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 |

36 | 37 | GitHub 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | Dash 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 57 | 58 |
59 | 82 |
83 | 84 |
85 |
86 |

Substring

87 |
88 |
89 | 90 |
public extension Substring
91 | 92 |
93 |
94 |

This extension provides methods for encoding and decoding strings using Punycode (RFC 3492) 95 | and IDNA encoding. It allows for the conversion of Substring instances to their Punycode 96 | and IDNA representations, facilitating the handling of internationalized domain names.

97 | 98 |
99 |
100 | 101 |
102 |
103 |
104 |
    105 |
  • 106 |
    107 | 108 | 109 | 110 | punycodeEncoded 111 | 112 |
    113 |
    114 |
    115 |
    116 |
    117 |
    118 |

    Returns new string in punycode encoding (RFC 3492)

    119 | 120 |
    121 |
    122 |

    Declaration

    123 |
    124 |

    Swift

    125 |
    var punycodeEncoded: String? { get }
    126 | 127 |
    128 |
    129 |
    130 |

    Return Value

    131 |

    Punycode encoded string or nil if the string can’t be encoded

    132 |
    133 |
    134 |
    135 |
  • 136 |
  • 137 |
    138 | 139 | 140 | 141 | punycodeDecoded 142 | 143 |
    144 |
    145 |
    146 |
    147 |
    148 |
    149 |

    Returns new string decoded from punycode representation (RFC 3492)

    150 | 151 |
    152 |
    153 |

    Declaration

    154 |
    155 |

    Swift

    156 |
    var punycodeDecoded: String? { get }
    157 | 158 |
    159 |
    160 |
    161 |

    Return Value

    162 |

    Original string or nil if the string doesn’t contain correct encoding

    163 |
    164 |
    165 |
    166 |
  • 167 |
  • 168 |
    169 | 170 | 171 | 172 | idnaEncoded 173 | 174 |
    175 |
    176 |
    177 |
    178 |
    179 |
    180 |

    Returns new string containing IDNA-encoded hostname

    181 | 182 |
    183 |
    184 |

    Declaration

    185 |
    186 |

    Swift

    187 |
    var idnaEncoded: String? { get }
    188 | 189 |
    190 |
    191 |
    192 |

    Return Value

    193 |

    IDNA encoded hostname or nil if the string can’t be encoded

    194 |
    195 |
    196 |
    197 |
  • 198 |
  • 199 |
    200 | 201 | 202 | 203 | idnaDecoded 204 | 205 |
    206 |
    207 |
    208 |
    209 |
    210 |
    211 |

    Returns new string containing hostname decoded from IDNA representation

    212 | 213 |
    214 |
    215 |

    Declaration

    216 |
    217 |

    Swift

    218 |
    var idnaDecoded: String? { get }
    219 | 220 |
    221 |
    222 |
    223 |

    Return Value

    224 |

    Original hostname or nil if the string doesn’t contain correct encoding

    225 |
    226 |
    227 |
    228 |
  • 229 |
230 |
231 |
232 |
233 | 234 |
235 |
236 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /docs/swiftdoc/css/highlight.css: -------------------------------------------------------------------------------- 1 | /*! Jazzy - https://github.com/realm/jazzy 2 | * Copyright Realm Inc. 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | /* Credit to https://gist.github.com/wataru420/2048287 */ 6 | .highlight .c { 7 | color: #999988; 8 | font-style: italic; } 9 | 10 | .highlight .err { 11 | color: #a61717; 12 | background-color: #e3d2d2; } 13 | 14 | .highlight .k { 15 | color: #000000; 16 | font-weight: bold; } 17 | 18 | .highlight .o { 19 | color: #000000; 20 | font-weight: bold; } 21 | 22 | .highlight .cm { 23 | color: #999988; 24 | font-style: italic; } 25 | 26 | .highlight .cp { 27 | color: #999999; 28 | font-weight: bold; } 29 | 30 | .highlight .c1 { 31 | color: #999988; 32 | font-style: italic; } 33 | 34 | .highlight .cs { 35 | color: #999999; 36 | font-weight: bold; 37 | font-style: italic; } 38 | 39 | .highlight .gd { 40 | color: #000000; 41 | background-color: #ffdddd; } 42 | 43 | .highlight .gd .x { 44 | color: #000000; 45 | background-color: #ffaaaa; } 46 | 47 | .highlight .ge { 48 | color: #000000; 49 | font-style: italic; } 50 | 51 | .highlight .gr { 52 | color: #aa0000; } 53 | 54 | .highlight .gh { 55 | color: #999999; } 56 | 57 | .highlight .gi { 58 | color: #000000; 59 | background-color: #ddffdd; } 60 | 61 | .highlight .gi .x { 62 | color: #000000; 63 | background-color: #aaffaa; } 64 | 65 | .highlight .go { 66 | color: #888888; } 67 | 68 | .highlight .gp { 69 | color: #555555; } 70 | 71 | .highlight .gs { 72 | font-weight: bold; } 73 | 74 | .highlight .gu { 75 | color: #aaaaaa; } 76 | 77 | .highlight .gt { 78 | color: #aa0000; } 79 | 80 | .highlight .kc { 81 | color: #000000; 82 | font-weight: bold; } 83 | 84 | .highlight .kd { 85 | color: #000000; 86 | font-weight: bold; } 87 | 88 | .highlight .kp { 89 | color: #000000; 90 | font-weight: bold; } 91 | 92 | .highlight .kr { 93 | color: #000000; 94 | font-weight: bold; } 95 | 96 | .highlight .kt { 97 | color: #445588; } 98 | 99 | .highlight .m { 100 | color: #009999; } 101 | 102 | .highlight .s { 103 | color: #d14; } 104 | 105 | .highlight .na { 106 | color: #008080; } 107 | 108 | .highlight .nb { 109 | color: #0086B3; } 110 | 111 | .highlight .nc { 112 | color: #445588; 113 | font-weight: bold; } 114 | 115 | .highlight .no { 116 | color: #008080; } 117 | 118 | .highlight .ni { 119 | color: #800080; } 120 | 121 | .highlight .ne { 122 | color: #990000; 123 | font-weight: bold; } 124 | 125 | .highlight .nf { 126 | color: #990000; } 127 | 128 | .highlight .nn { 129 | color: #555555; } 130 | 131 | .highlight .nt { 132 | color: #000080; } 133 | 134 | .highlight .nv { 135 | color: #008080; } 136 | 137 | .highlight .ow { 138 | color: #000000; 139 | font-weight: bold; } 140 | 141 | .highlight .w { 142 | color: #bbbbbb; } 143 | 144 | .highlight .mf { 145 | color: #009999; } 146 | 147 | .highlight .mh { 148 | color: #009999; } 149 | 150 | .highlight .mi { 151 | color: #009999; } 152 | 153 | .highlight .mo { 154 | color: #009999; } 155 | 156 | .highlight .sb { 157 | color: #d14; } 158 | 159 | .highlight .sc { 160 | color: #d14; } 161 | 162 | .highlight .sd { 163 | color: #d14; } 164 | 165 | .highlight .s2 { 166 | color: #d14; } 167 | 168 | .highlight .se { 169 | color: #d14; } 170 | 171 | .highlight .sh { 172 | color: #d14; } 173 | 174 | .highlight .si { 175 | color: #d14; } 176 | 177 | .highlight .sx { 178 | color: #d14; } 179 | 180 | .highlight .sr { 181 | color: #009926; } 182 | 183 | .highlight .s1 { 184 | color: #d14; } 185 | 186 | .highlight .ss { 187 | color: #990073; } 188 | 189 | .highlight .bp { 190 | color: #999999; } 191 | 192 | .highlight .vc { 193 | color: #008080; } 194 | 195 | .highlight .vg { 196 | color: #008080; } 197 | 198 | .highlight .vi { 199 | color: #008080; } 200 | 201 | .highlight .il { 202 | color: #009999; } 203 | -------------------------------------------------------------------------------- /docs/swiftdoc/css/jazzy.css: -------------------------------------------------------------------------------- 1 | /*! Jazzy - https://github.com/realm/jazzy 2 | * Copyright Realm Inc. 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | *, *:before, *:after { 6 | box-sizing: inherit; } 7 | 8 | body { 9 | margin: 0; 10 | background: #fff; 11 | color: #333; 12 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 13 | letter-spacing: .2px; 14 | -webkit-font-smoothing: antialiased; 15 | box-sizing: border-box; } 16 | 17 | h1 { 18 | font-size: 2rem; 19 | font-weight: 700; 20 | margin: 1.275em 0 0.6em; } 21 | 22 | h2 { 23 | font-size: 1.75rem; 24 | font-weight: 700; 25 | margin: 1.275em 0 0.3em; } 26 | 27 | h3 { 28 | font-size: 1.5rem; 29 | font-weight: 700; 30 | margin: 1em 0 0.3em; } 31 | 32 | h4 { 33 | font-size: 1.25rem; 34 | font-weight: 700; 35 | margin: 1.275em 0 0.85em; } 36 | 37 | h5 { 38 | font-size: 1rem; 39 | font-weight: 700; 40 | margin: 1.275em 0 0.85em; } 41 | 42 | h6 { 43 | font-size: 1rem; 44 | font-weight: 700; 45 | margin: 1.275em 0 0.85em; 46 | color: #777; } 47 | 48 | p { 49 | margin: 0 0 1em; } 50 | 51 | ul, ol { 52 | padding: 0 0 0 2em; 53 | margin: 0 0 0.85em; } 54 | 55 | blockquote { 56 | margin: 0 0 0.85em; 57 | padding: 0 15px; 58 | color: #858585; 59 | border-left: 4px solid #e5e5e5; } 60 | 61 | img { 62 | max-width: 100%; } 63 | 64 | a { 65 | color: #4183c4; 66 | text-decoration: none; } 67 | a:hover, a:focus { 68 | outline: 0; 69 | text-decoration: underline; } 70 | a.discouraged { 71 | text-decoration: line-through; } 72 | a.discouraged:hover, a.discouraged:focus { 73 | text-decoration: underline line-through; } 74 | 75 | table { 76 | background: #fff; 77 | width: 100%; 78 | border-collapse: collapse; 79 | border-spacing: 0; 80 | overflow: auto; 81 | margin: 0 0 0.85em; } 82 | 83 | tr:nth-child(2n) { 84 | background-color: #fbfbfb; } 85 | 86 | th, td { 87 | padding: 6px 13px; 88 | border: 1px solid #ddd; } 89 | 90 | hr { 91 | height: 1px; 92 | border: none; 93 | background-color: #ddd; } 94 | 95 | pre { 96 | margin: 0 0 1.275em; 97 | padding: .85em 1em; 98 | overflow: auto; 99 | background: #f7f7f7; 100 | font-size: .85em; 101 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } 102 | 103 | code { 104 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } 105 | 106 | .item-container p > code, .item-container li > code, .top-matter p > code, .top-matter li > code { 107 | background: #f7f7f7; 108 | padding: .2em; } 109 | .item-container p > code:before, .item-container p > code:after, .item-container li > code:before, .item-container li > code:after, .top-matter p > code:before, .top-matter p > code:after, .top-matter li > code:before, .top-matter li > code:after { 110 | letter-spacing: -.2em; 111 | content: "\00a0"; } 112 | 113 | pre code { 114 | padding: 0; 115 | white-space: pre; } 116 | 117 | .content-wrapper { 118 | display: flex; 119 | flex-direction: column; } 120 | @media (min-width: 768px) { 121 | .content-wrapper { 122 | flex-direction: row; } } 123 | .header { 124 | display: flex; 125 | padding: 8px; 126 | font-size: 0.875em; 127 | background: #444; 128 | color: #999; } 129 | 130 | .header-col { 131 | margin: 0; 132 | padding: 0 8px; } 133 | 134 | .header-col--primary { 135 | flex: 1; } 136 | 137 | .header-link { 138 | color: #fff; } 139 | 140 | .header-icon { 141 | padding-right: 2px; 142 | vertical-align: -3px; 143 | height: 16px; } 144 | 145 | .breadcrumbs { 146 | font-size: 0.875em; 147 | padding: 8px 16px; 148 | margin: 0; 149 | background: #fbfbfb; 150 | border-bottom: 1px solid #ddd; } 151 | 152 | .carat { 153 | height: 10px; 154 | margin: 0 5px; } 155 | 156 | .navigation { 157 | order: 2; } 158 | @media (min-width: 768px) { 159 | .navigation { 160 | order: 1; 161 | width: 25%; 162 | max-width: 300px; 163 | padding-bottom: 64px; 164 | overflow: hidden; 165 | word-wrap: normal; 166 | background: #fbfbfb; 167 | border-right: 1px solid #ddd; } } 168 | .nav-groups { 169 | list-style-type: none; 170 | padding-left: 0; } 171 | 172 | .nav-group-name { 173 | border-bottom: 1px solid #ddd; 174 | padding: 8px 0 8px 16px; } 175 | 176 | .nav-group-name-link { 177 | color: #333; } 178 | 179 | .nav-group-tasks { 180 | margin: 8px 0; 181 | padding: 0 0 0 8px; } 182 | 183 | .nav-group-task { 184 | font-size: 1em; 185 | list-style-type: none; 186 | white-space: nowrap; } 187 | 188 | .nav-group-task-link { 189 | color: #808080; } 190 | 191 | .main-content { 192 | order: 1; } 193 | @media (min-width: 768px) { 194 | .main-content { 195 | order: 2; 196 | flex: 1; 197 | padding-bottom: 60px; } } 198 | .section { 199 | padding: 0 32px; 200 | border-bottom: 1px solid #ddd; } 201 | 202 | .section-content { 203 | max-width: 834px; 204 | margin: 0 auto; 205 | padding: 16px 0; } 206 | 207 | .section-name { 208 | color: #666; 209 | display: block; } 210 | .section-name p { 211 | margin-bottom: inherit; } 212 | 213 | .declaration .highlight { 214 | overflow-x: initial; 215 | padding: 8px 0; 216 | margin: 0; 217 | background-color: transparent; 218 | border: none; } 219 | 220 | .task-group-section { 221 | border-top: 1px solid #ddd; } 222 | 223 | .task-group { 224 | padding-top: 0px; } 225 | 226 | .task-name-container a[name]:before { 227 | content: ""; 228 | display: block; } 229 | 230 | .section-name-container { 231 | position: relative; } 232 | .section-name-container .section-name-link { 233 | position: absolute; 234 | top: 0; 235 | left: 0; 236 | bottom: 0; 237 | right: 0; 238 | margin-bottom: 0; } 239 | .section-name-container .section-name { 240 | position: relative; 241 | pointer-events: none; 242 | z-index: 1; } 243 | .section-name-container .section-name a { 244 | pointer-events: auto; } 245 | 246 | .item-container { 247 | padding: 0; } 248 | 249 | .item { 250 | padding-top: 8px; 251 | width: 100%; 252 | list-style-type: none; } 253 | .item a[name]:before { 254 | content: ""; 255 | display: block; } 256 | .item .token, .item .direct-link { 257 | display: inline-block; 258 | text-indent: -20px; 259 | padding-left: 3px; 260 | margin-left: 20px; 261 | font-size: 1rem; } 262 | 263 | .declaration-note { 264 | font-size: .85em; 265 | color: #808080; 266 | font-style: italic; } 267 | 268 | .pointer-container { 269 | border-bottom: 1px solid #ddd; 270 | left: -23px; 271 | padding-bottom: 13px; 272 | position: relative; 273 | width: 110%; } 274 | 275 | .pointer { 276 | left: 21px; 277 | top: 7px; 278 | display: block; 279 | position: absolute; 280 | width: 12px; 281 | height: 12px; 282 | border-left: 1px solid #ddd; 283 | border-top: 1px solid #ddd; 284 | background: #fff; 285 | transform: rotate(45deg); } 286 | 287 | .height-container { 288 | display: none; 289 | position: relative; 290 | width: 100%; 291 | overflow: hidden; } 292 | .height-container .section { 293 | background: #fff; 294 | border: 1px solid #ddd; 295 | border-top-width: 0; 296 | padding-top: 10px; 297 | padding-bottom: 5px; 298 | padding: 8px 16px; } 299 | 300 | .aside, .language { 301 | padding: 6px 12px; 302 | margin: 12px 0; 303 | border-left: 5px solid #dddddd; 304 | overflow-y: hidden; } 305 | .aside .aside-title, .language .aside-title { 306 | font-size: 9px; 307 | letter-spacing: 2px; 308 | text-transform: uppercase; 309 | padding-bottom: 0; 310 | margin: 0; 311 | color: #aaa; 312 | -webkit-user-select: none; } 313 | .aside p:last-child, .language p:last-child { 314 | margin-bottom: 0; } 315 | 316 | .language { 317 | border-left: 5px solid #cde9f4; } 318 | .language .aside-title { 319 | color: #4183c4; } 320 | 321 | .aside-warning, .aside-deprecated, .aside-unavailable { 322 | border-left: 5px solid #ff6666; } 323 | .aside-warning .aside-title, .aside-deprecated .aside-title, .aside-unavailable .aside-title { 324 | color: #ff0000; } 325 | 326 | .graybox { 327 | border-collapse: collapse; 328 | width: 100%; } 329 | .graybox p { 330 | margin: 0; 331 | word-break: break-word; 332 | min-width: 50px; } 333 | .graybox td { 334 | border: 1px solid #ddd; 335 | padding: 5px 25px 5px 10px; 336 | vertical-align: middle; } 337 | .graybox tr td:first-of-type { 338 | text-align: right; 339 | padding: 7px; 340 | vertical-align: top; 341 | word-break: normal; 342 | width: 40px; } 343 | 344 | .slightly-smaller { 345 | font-size: 0.9em; } 346 | 347 | .footer { 348 | padding: 8px 16px; 349 | background: #444; 350 | color: #ddd; 351 | font-size: 0.8em; } 352 | .footer p { 353 | margin: 8px 0; } 354 | .footer a { 355 | color: #fff; } 356 | 357 | html.dash .header, html.dash .breadcrumbs, html.dash .navigation { 358 | display: none; } 359 | 360 | html.dash .height-container { 361 | display: block; } 362 | 363 | form[role=search] input { 364 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 365 | font-size: 14px; 366 | line-height: 24px; 367 | padding: 0 10px; 368 | margin: 0; 369 | border: none; 370 | border-radius: 1em; } 371 | .loading form[role=search] input { 372 | background: white url(../img/spinner.gif) center right 4px no-repeat; } 373 | 374 | form[role=search] .tt-menu { 375 | margin: 0; 376 | min-width: 300px; 377 | background: #fbfbfb; 378 | color: #333; 379 | border: 1px solid #ddd; } 380 | 381 | form[role=search] .tt-highlight { 382 | font-weight: bold; } 383 | 384 | form[role=search] .tt-suggestion { 385 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 386 | padding: 0 8px; } 387 | form[role=search] .tt-suggestion span { 388 | display: table-cell; 389 | white-space: nowrap; } 390 | form[role=search] .tt-suggestion .doc-parent-name { 391 | width: 100%; 392 | text-align: right; 393 | font-weight: normal; 394 | font-size: 0.9em; 395 | padding-left: 16px; } 396 | 397 | form[role=search] .tt-suggestion:hover, 398 | form[role=search] .tt-suggestion.tt-cursor { 399 | cursor: pointer; 400 | background-color: #4183c4; 401 | color: #fff; } 402 | 403 | form[role=search] .tt-suggestion:hover .doc-parent-name, 404 | form[role=search] .tt-suggestion.tt-cursor .doc-parent-name { 405 | color: #fff; } 406 | -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy.punycode 7 | CFBundleName 8 | Punycode 9 | DocSetPlatformFamily 10 | punycode 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | DashDocSetFallbackURL 20 | https://github.com/gumob/PunycodeSwift/tree/3.0.0/docs/ 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/Classes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Classes Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Punycode 3.0.0 Docs 25 | 26 | 27 |

28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 |

36 | 37 | GitHub 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | Dash 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 80 |
81 | 82 |
83 |
84 |

Classes

85 |

The following classes are available globally.

86 | 87 |
88 |
89 | 90 |
91 |
92 |
93 |
    94 |
  • 95 |
    96 | 97 | 98 | 99 | Puny 100 | 101 |
    102 |
    103 |
    104 |
    105 |
    106 |
    107 |

    Puny class provides methods to encode and decode strings using Punycode (RFC 3492). 108 | It allows for the conversion of Unicode strings into ASCII-compatible encoding, 109 | which is essential for domain names and other applications that require ASCII representation.

    110 |
    111 |

    Note

    112 | This implementation follows the specifications outlined in RFC 3492. 113 | 114 |
      115 |
    • Usage: Create an instance of Puny and call the appropriate methods for encoding or decoding.
    • 116 |
    117 | 118 | See more 119 |
    120 |
    121 |

    Declaration

    122 |
    123 |

    Swift

    124 |
    public class Puny
    125 | 126 |
    127 |
    128 |
    129 |
    130 |
  • 131 |
132 |
133 |
134 |
135 | 136 |
137 |
138 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/Extensions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Extensions Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Punycode 3.0.0 Docs 25 | 26 | 27 |

28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 |

36 | 37 | GitHub 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | Dash 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 80 |
81 | 82 |
83 |
84 |

Extensions

85 |

The following extensions are available globally.

86 | 87 |
88 |
89 | 90 |
91 |
92 |
93 |
    94 |
  • 95 |
    96 | 97 | 98 | 99 | Substring 100 | 101 |
    102 |
    103 |
    104 |
    105 |
    106 |
    107 |

    This extension provides methods for encoding and decoding strings using Punycode (RFC 3492) 108 | and IDNA encoding. It allows for the conversion of Substring instances to their Punycode 109 | and IDNA representations, facilitating the handling of internationalized domain names.

    110 | 111 | See more 112 |
    113 |
    114 |

    Declaration

    115 |
    116 |

    Swift

    117 |
    public extension Substring
    118 | 119 |
    120 |
    121 |
    122 |
    123 |
  • 124 |
  • 125 |
    126 | 127 | 128 | 129 | String 130 | 131 |
    132 |
    133 |
    134 |
    135 |
    136 |
    137 |

    This extension provides methods for encoding and decoding strings using Punycode (RFC 3492) 138 | and IDNA encoding. It allows for the conversion of String instances to their Punycode 139 | and IDNA representations, facilitating the handling of internationalized domain names.

    140 | 141 | See more 142 |
    143 |
    144 |

    Declaration

    145 |
    146 |

    Swift

    147 |
    public extension String
    148 | 149 |
    150 |
    151 |
    152 |
    153 |
  • 154 |
155 |
156 |
157 |
158 | 159 |
160 |
161 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/Extensions/String.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | String Extension Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Punycode 3.0.0 Docs 25 | 26 | 27 |

28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 |

36 | 37 | GitHub 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | Dash 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 57 | 58 |
59 | 82 |
83 | 84 |
85 |
86 |

String

87 |
88 |
89 | 90 |
public extension String
91 | 92 |
93 |
94 |

This extension provides methods for encoding and decoding strings using Punycode (RFC 3492) 95 | and IDNA encoding. It allows for the conversion of String instances to their Punycode 96 | and IDNA representations, facilitating the handling of internationalized domain names.

97 | 98 |
99 |
100 | 101 |
102 |
103 |
104 |
    105 |
  • 106 |
    107 | 108 | 109 | 110 | punycodeEncoded 111 | 112 |
    113 |
    114 |
    115 |
    116 |
    117 |
    118 |

    Returns new string in punycode encoding (RFC 3492)

    119 | 120 |
    121 |
    122 |

    Declaration

    123 |
    124 |

    Swift

    125 |
    var punycodeEncoded: String? { get }
    126 | 127 |
    128 |
    129 |
    130 |

    Return Value

    131 |

    Punycode encoded string or nil if the string can’t be encoded

    132 |
    133 |
    134 |
    135 |
  • 136 |
  • 137 |
    138 | 139 | 140 | 141 | punycodeDecoded 142 | 143 |
    144 |
    145 |
    146 |
    147 |
    148 |
    149 |

    Returns new string decoded from punycode representation (RFC 3492)

    150 | 151 |
    152 |
    153 |

    Declaration

    154 |
    155 |

    Swift

    156 |
    var punycodeDecoded: String? { get }
    157 | 158 |
    159 |
    160 |
    161 |

    Return Value

    162 |

    Original string or nil if the string doesn’t contain correct encoding

    163 |
    164 |
    165 |
    166 |
  • 167 |
  • 168 |
    169 | 170 | 171 | 172 | idnaEncoded 173 | 174 |
    175 |
    176 |
    177 |
    178 |
    179 |
    180 |

    Returns new string containing IDNA-encoded hostname

    181 | 182 |
    183 |
    184 |

    Declaration

    185 |
    186 |

    Swift

    187 |
    var idnaEncoded: String? { get }
    188 | 189 |
    190 |
    191 |
    192 |

    Return Value

    193 |

    IDNA encoded hostname or nil if the string can’t be encoded

    194 |
    195 |
    196 |
    197 |
  • 198 |
  • 199 |
    200 | 201 | 202 | 203 | idnaDecoded 204 | 205 |
    206 |
    207 |
    208 |
    209 |
    210 |
    211 |

    Returns new string containing hostname decoded from IDNA representation

    212 | 213 |
    214 |
    215 |

    Declaration

    216 |
    217 |

    Swift

    218 |
    var idnaDecoded: String? { get }
    219 | 220 |
    221 |
    222 |
    223 |

    Return Value

    224 |

    Original hostname or nil if the string doesn’t contain correct encoding

    225 |
    226 |
    227 |
    228 |
  • 229 |
230 |
231 |
232 |
233 | 234 |
235 |
236 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/Extensions/Substring.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Substring Extension Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Punycode 3.0.0 Docs 25 | 26 | 27 |

28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 |

36 | 37 | GitHub 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | Dash 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 57 | 58 |
59 | 82 |
83 | 84 |
85 |
86 |

Substring

87 |
88 |
89 | 90 |
public extension Substring
91 | 92 |
93 |
94 |

This extension provides methods for encoding and decoding strings using Punycode (RFC 3492) 95 | and IDNA encoding. It allows for the conversion of Substring instances to their Punycode 96 | and IDNA representations, facilitating the handling of internationalized domain names.

97 | 98 |
99 |
100 | 101 |
102 |
103 |
104 |
    105 |
  • 106 |
    107 | 108 | 109 | 110 | punycodeEncoded 111 | 112 |
    113 |
    114 |
    115 |
    116 |
    117 |
    118 |

    Returns new string in punycode encoding (RFC 3492)

    119 | 120 |
    121 |
    122 |

    Declaration

    123 |
    124 |

    Swift

    125 |
    var punycodeEncoded: String? { get }
    126 | 127 |
    128 |
    129 |
    130 |

    Return Value

    131 |

    Punycode encoded string or nil if the string can’t be encoded

    132 |
    133 |
    134 |
    135 |
  • 136 |
  • 137 |
    138 | 139 | 140 | 141 | punycodeDecoded 142 | 143 |
    144 |
    145 |
    146 |
    147 |
    148 |
    149 |

    Returns new string decoded from punycode representation (RFC 3492)

    150 | 151 |
    152 |
    153 |

    Declaration

    154 |
    155 |

    Swift

    156 |
    var punycodeDecoded: String? { get }
    157 | 158 |
    159 |
    160 |
    161 |

    Return Value

    162 |

    Original string or nil if the string doesn’t contain correct encoding

    163 |
    164 |
    165 |
    166 |
  • 167 |
  • 168 |
    169 | 170 | 171 | 172 | idnaEncoded 173 | 174 |
    175 |
    176 |
    177 |
    178 |
    179 |
    180 |

    Returns new string containing IDNA-encoded hostname

    181 | 182 |
    183 |
    184 |

    Declaration

    185 |
    186 |

    Swift

    187 |
    var idnaEncoded: String? { get }
    188 | 189 |
    190 |
    191 |
    192 |

    Return Value

    193 |

    IDNA encoded hostname or nil if the string can’t be encoded

    194 |
    195 |
    196 |
    197 |
  • 198 |
  • 199 |
    200 | 201 | 202 | 203 | idnaDecoded 204 | 205 |
    206 |
    207 |
    208 |
    209 |
    210 |
    211 |

    Returns new string containing hostname decoded from IDNA representation

    212 | 213 |
    214 |
    215 |

    Declaration

    216 |
    217 |

    Swift

    218 |
    var idnaDecoded: String? { get }
    219 | 220 |
    221 |
    222 |
    223 |

    Return Value

    224 |

    Original hostname or nil if the string doesn’t contain correct encoding

    225 |
    226 |
    227 |
    228 |
  • 229 |
230 |
231 |
232 |
233 | 234 |
235 |
236 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/css/highlight.css: -------------------------------------------------------------------------------- 1 | /*! Jazzy - https://github.com/realm/jazzy 2 | * Copyright Realm Inc. 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | /* Credit to https://gist.github.com/wataru420/2048287 */ 6 | .highlight .c { 7 | color: #999988; 8 | font-style: italic; } 9 | 10 | .highlight .err { 11 | color: #a61717; 12 | background-color: #e3d2d2; } 13 | 14 | .highlight .k { 15 | color: #000000; 16 | font-weight: bold; } 17 | 18 | .highlight .o { 19 | color: #000000; 20 | font-weight: bold; } 21 | 22 | .highlight .cm { 23 | color: #999988; 24 | font-style: italic; } 25 | 26 | .highlight .cp { 27 | color: #999999; 28 | font-weight: bold; } 29 | 30 | .highlight .c1 { 31 | color: #999988; 32 | font-style: italic; } 33 | 34 | .highlight .cs { 35 | color: #999999; 36 | font-weight: bold; 37 | font-style: italic; } 38 | 39 | .highlight .gd { 40 | color: #000000; 41 | background-color: #ffdddd; } 42 | 43 | .highlight .gd .x { 44 | color: #000000; 45 | background-color: #ffaaaa; } 46 | 47 | .highlight .ge { 48 | color: #000000; 49 | font-style: italic; } 50 | 51 | .highlight .gr { 52 | color: #aa0000; } 53 | 54 | .highlight .gh { 55 | color: #999999; } 56 | 57 | .highlight .gi { 58 | color: #000000; 59 | background-color: #ddffdd; } 60 | 61 | .highlight .gi .x { 62 | color: #000000; 63 | background-color: #aaffaa; } 64 | 65 | .highlight .go { 66 | color: #888888; } 67 | 68 | .highlight .gp { 69 | color: #555555; } 70 | 71 | .highlight .gs { 72 | font-weight: bold; } 73 | 74 | .highlight .gu { 75 | color: #aaaaaa; } 76 | 77 | .highlight .gt { 78 | color: #aa0000; } 79 | 80 | .highlight .kc { 81 | color: #000000; 82 | font-weight: bold; } 83 | 84 | .highlight .kd { 85 | color: #000000; 86 | font-weight: bold; } 87 | 88 | .highlight .kp { 89 | color: #000000; 90 | font-weight: bold; } 91 | 92 | .highlight .kr { 93 | color: #000000; 94 | font-weight: bold; } 95 | 96 | .highlight .kt { 97 | color: #445588; } 98 | 99 | .highlight .m { 100 | color: #009999; } 101 | 102 | .highlight .s { 103 | color: #d14; } 104 | 105 | .highlight .na { 106 | color: #008080; } 107 | 108 | .highlight .nb { 109 | color: #0086B3; } 110 | 111 | .highlight .nc { 112 | color: #445588; 113 | font-weight: bold; } 114 | 115 | .highlight .no { 116 | color: #008080; } 117 | 118 | .highlight .ni { 119 | color: #800080; } 120 | 121 | .highlight .ne { 122 | color: #990000; 123 | font-weight: bold; } 124 | 125 | .highlight .nf { 126 | color: #990000; } 127 | 128 | .highlight .nn { 129 | color: #555555; } 130 | 131 | .highlight .nt { 132 | color: #000080; } 133 | 134 | .highlight .nv { 135 | color: #008080; } 136 | 137 | .highlight .ow { 138 | color: #000000; 139 | font-weight: bold; } 140 | 141 | .highlight .w { 142 | color: #bbbbbb; } 143 | 144 | .highlight .mf { 145 | color: #009999; } 146 | 147 | .highlight .mh { 148 | color: #009999; } 149 | 150 | .highlight .mi { 151 | color: #009999; } 152 | 153 | .highlight .mo { 154 | color: #009999; } 155 | 156 | .highlight .sb { 157 | color: #d14; } 158 | 159 | .highlight .sc { 160 | color: #d14; } 161 | 162 | .highlight .sd { 163 | color: #d14; } 164 | 165 | .highlight .s2 { 166 | color: #d14; } 167 | 168 | .highlight .se { 169 | color: #d14; } 170 | 171 | .highlight .sh { 172 | color: #d14; } 173 | 174 | .highlight .si { 175 | color: #d14; } 176 | 177 | .highlight .sx { 178 | color: #d14; } 179 | 180 | .highlight .sr { 181 | color: #009926; } 182 | 183 | .highlight .s1 { 184 | color: #d14; } 185 | 186 | .highlight .ss { 187 | color: #990073; } 188 | 189 | .highlight .bp { 190 | color: #999999; } 191 | 192 | .highlight .vc { 193 | color: #008080; } 194 | 195 | .highlight .vg { 196 | color: #008080; } 197 | 198 | .highlight .vi { 199 | color: #008080; } 200 | 201 | .highlight .il { 202 | color: #009999; } 203 | -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/css/jazzy.css: -------------------------------------------------------------------------------- 1 | /*! Jazzy - https://github.com/realm/jazzy 2 | * Copyright Realm Inc. 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | *, *:before, *:after { 6 | box-sizing: inherit; } 7 | 8 | body { 9 | margin: 0; 10 | background: #fff; 11 | color: #333; 12 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 13 | letter-spacing: .2px; 14 | -webkit-font-smoothing: antialiased; 15 | box-sizing: border-box; } 16 | 17 | h1 { 18 | font-size: 2rem; 19 | font-weight: 700; 20 | margin: 1.275em 0 0.6em; } 21 | 22 | h2 { 23 | font-size: 1.75rem; 24 | font-weight: 700; 25 | margin: 1.275em 0 0.3em; } 26 | 27 | h3 { 28 | font-size: 1.5rem; 29 | font-weight: 700; 30 | margin: 1em 0 0.3em; } 31 | 32 | h4 { 33 | font-size: 1.25rem; 34 | font-weight: 700; 35 | margin: 1.275em 0 0.85em; } 36 | 37 | h5 { 38 | font-size: 1rem; 39 | font-weight: 700; 40 | margin: 1.275em 0 0.85em; } 41 | 42 | h6 { 43 | font-size: 1rem; 44 | font-weight: 700; 45 | margin: 1.275em 0 0.85em; 46 | color: #777; } 47 | 48 | p { 49 | margin: 0 0 1em; } 50 | 51 | ul, ol { 52 | padding: 0 0 0 2em; 53 | margin: 0 0 0.85em; } 54 | 55 | blockquote { 56 | margin: 0 0 0.85em; 57 | padding: 0 15px; 58 | color: #858585; 59 | border-left: 4px solid #e5e5e5; } 60 | 61 | img { 62 | max-width: 100%; } 63 | 64 | a { 65 | color: #4183c4; 66 | text-decoration: none; } 67 | a:hover, a:focus { 68 | outline: 0; 69 | text-decoration: underline; } 70 | a.discouraged { 71 | text-decoration: line-through; } 72 | a.discouraged:hover, a.discouraged:focus { 73 | text-decoration: underline line-through; } 74 | 75 | table { 76 | background: #fff; 77 | width: 100%; 78 | border-collapse: collapse; 79 | border-spacing: 0; 80 | overflow: auto; 81 | margin: 0 0 0.85em; } 82 | 83 | tr:nth-child(2n) { 84 | background-color: #fbfbfb; } 85 | 86 | th, td { 87 | padding: 6px 13px; 88 | border: 1px solid #ddd; } 89 | 90 | hr { 91 | height: 1px; 92 | border: none; 93 | background-color: #ddd; } 94 | 95 | pre { 96 | margin: 0 0 1.275em; 97 | padding: .85em 1em; 98 | overflow: auto; 99 | background: #f7f7f7; 100 | font-size: .85em; 101 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } 102 | 103 | code { 104 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } 105 | 106 | .item-container p > code, .item-container li > code, .top-matter p > code, .top-matter li > code { 107 | background: #f7f7f7; 108 | padding: .2em; } 109 | .item-container p > code:before, .item-container p > code:after, .item-container li > code:before, .item-container li > code:after, .top-matter p > code:before, .top-matter p > code:after, .top-matter li > code:before, .top-matter li > code:after { 110 | letter-spacing: -.2em; 111 | content: "\00a0"; } 112 | 113 | pre code { 114 | padding: 0; 115 | white-space: pre; } 116 | 117 | .content-wrapper { 118 | display: flex; 119 | flex-direction: column; } 120 | @media (min-width: 768px) { 121 | .content-wrapper { 122 | flex-direction: row; } } 123 | .header { 124 | display: flex; 125 | padding: 8px; 126 | font-size: 0.875em; 127 | background: #444; 128 | color: #999; } 129 | 130 | .header-col { 131 | margin: 0; 132 | padding: 0 8px; } 133 | 134 | .header-col--primary { 135 | flex: 1; } 136 | 137 | .header-link { 138 | color: #fff; } 139 | 140 | .header-icon { 141 | padding-right: 2px; 142 | vertical-align: -3px; 143 | height: 16px; } 144 | 145 | .breadcrumbs { 146 | font-size: 0.875em; 147 | padding: 8px 16px; 148 | margin: 0; 149 | background: #fbfbfb; 150 | border-bottom: 1px solid #ddd; } 151 | 152 | .carat { 153 | height: 10px; 154 | margin: 0 5px; } 155 | 156 | .navigation { 157 | order: 2; } 158 | @media (min-width: 768px) { 159 | .navigation { 160 | order: 1; 161 | width: 25%; 162 | max-width: 300px; 163 | padding-bottom: 64px; 164 | overflow: hidden; 165 | word-wrap: normal; 166 | background: #fbfbfb; 167 | border-right: 1px solid #ddd; } } 168 | .nav-groups { 169 | list-style-type: none; 170 | padding-left: 0; } 171 | 172 | .nav-group-name { 173 | border-bottom: 1px solid #ddd; 174 | padding: 8px 0 8px 16px; } 175 | 176 | .nav-group-name-link { 177 | color: #333; } 178 | 179 | .nav-group-tasks { 180 | margin: 8px 0; 181 | padding: 0 0 0 8px; } 182 | 183 | .nav-group-task { 184 | font-size: 1em; 185 | list-style-type: none; 186 | white-space: nowrap; } 187 | 188 | .nav-group-task-link { 189 | color: #808080; } 190 | 191 | .main-content { 192 | order: 1; } 193 | @media (min-width: 768px) { 194 | .main-content { 195 | order: 2; 196 | flex: 1; 197 | padding-bottom: 60px; } } 198 | .section { 199 | padding: 0 32px; 200 | border-bottom: 1px solid #ddd; } 201 | 202 | .section-content { 203 | max-width: 834px; 204 | margin: 0 auto; 205 | padding: 16px 0; } 206 | 207 | .section-name { 208 | color: #666; 209 | display: block; } 210 | .section-name p { 211 | margin-bottom: inherit; } 212 | 213 | .declaration .highlight { 214 | overflow-x: initial; 215 | padding: 8px 0; 216 | margin: 0; 217 | background-color: transparent; 218 | border: none; } 219 | 220 | .task-group-section { 221 | border-top: 1px solid #ddd; } 222 | 223 | .task-group { 224 | padding-top: 0px; } 225 | 226 | .task-name-container a[name]:before { 227 | content: ""; 228 | display: block; } 229 | 230 | .section-name-container { 231 | position: relative; } 232 | .section-name-container .section-name-link { 233 | position: absolute; 234 | top: 0; 235 | left: 0; 236 | bottom: 0; 237 | right: 0; 238 | margin-bottom: 0; } 239 | .section-name-container .section-name { 240 | position: relative; 241 | pointer-events: none; 242 | z-index: 1; } 243 | .section-name-container .section-name a { 244 | pointer-events: auto; } 245 | 246 | .item-container { 247 | padding: 0; } 248 | 249 | .item { 250 | padding-top: 8px; 251 | width: 100%; 252 | list-style-type: none; } 253 | .item a[name]:before { 254 | content: ""; 255 | display: block; } 256 | .item .token, .item .direct-link { 257 | display: inline-block; 258 | text-indent: -20px; 259 | padding-left: 3px; 260 | margin-left: 20px; 261 | font-size: 1rem; } 262 | 263 | .declaration-note { 264 | font-size: .85em; 265 | color: #808080; 266 | font-style: italic; } 267 | 268 | .pointer-container { 269 | border-bottom: 1px solid #ddd; 270 | left: -23px; 271 | padding-bottom: 13px; 272 | position: relative; 273 | width: 110%; } 274 | 275 | .pointer { 276 | left: 21px; 277 | top: 7px; 278 | display: block; 279 | position: absolute; 280 | width: 12px; 281 | height: 12px; 282 | border-left: 1px solid #ddd; 283 | border-top: 1px solid #ddd; 284 | background: #fff; 285 | transform: rotate(45deg); } 286 | 287 | .height-container { 288 | display: none; 289 | position: relative; 290 | width: 100%; 291 | overflow: hidden; } 292 | .height-container .section { 293 | background: #fff; 294 | border: 1px solid #ddd; 295 | border-top-width: 0; 296 | padding-top: 10px; 297 | padding-bottom: 5px; 298 | padding: 8px 16px; } 299 | 300 | .aside, .language { 301 | padding: 6px 12px; 302 | margin: 12px 0; 303 | border-left: 5px solid #dddddd; 304 | overflow-y: hidden; } 305 | .aside .aside-title, .language .aside-title { 306 | font-size: 9px; 307 | letter-spacing: 2px; 308 | text-transform: uppercase; 309 | padding-bottom: 0; 310 | margin: 0; 311 | color: #aaa; 312 | -webkit-user-select: none; } 313 | .aside p:last-child, .language p:last-child { 314 | margin-bottom: 0; } 315 | 316 | .language { 317 | border-left: 5px solid #cde9f4; } 318 | .language .aside-title { 319 | color: #4183c4; } 320 | 321 | .aside-warning, .aside-deprecated, .aside-unavailable { 322 | border-left: 5px solid #ff6666; } 323 | .aside-warning .aside-title, .aside-deprecated .aside-title, .aside-unavailable .aside-title { 324 | color: #ff0000; } 325 | 326 | .graybox { 327 | border-collapse: collapse; 328 | width: 100%; } 329 | .graybox p { 330 | margin: 0; 331 | word-break: break-word; 332 | min-width: 50px; } 333 | .graybox td { 334 | border: 1px solid #ddd; 335 | padding: 5px 25px 5px 10px; 336 | vertical-align: middle; } 337 | .graybox tr td:first-of-type { 338 | text-align: right; 339 | padding: 7px; 340 | vertical-align: top; 341 | word-break: normal; 342 | width: 40px; } 343 | 344 | .slightly-smaller { 345 | font-size: 0.9em; } 346 | 347 | .footer { 348 | padding: 8px 16px; 349 | background: #444; 350 | color: #ddd; 351 | font-size: 0.8em; } 352 | .footer p { 353 | margin: 8px 0; } 354 | .footer a { 355 | color: #fff; } 356 | 357 | html.dash .header, html.dash .breadcrumbs, html.dash .navigation { 358 | display: none; } 359 | 360 | html.dash .height-container { 361 | display: block; } 362 | 363 | form[role=search] input { 364 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 365 | font-size: 14px; 366 | line-height: 24px; 367 | padding: 0 10px; 368 | margin: 0; 369 | border: none; 370 | border-radius: 1em; } 371 | .loading form[role=search] input { 372 | background: white url(../img/spinner.gif) center right 4px no-repeat; } 373 | 374 | form[role=search] .tt-menu { 375 | margin: 0; 376 | min-width: 300px; 377 | background: #fbfbfb; 378 | color: #333; 379 | border: 1px solid #ddd; } 380 | 381 | form[role=search] .tt-highlight { 382 | font-weight: bold; } 383 | 384 | form[role=search] .tt-suggestion { 385 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 386 | padding: 0 8px; } 387 | form[role=search] .tt-suggestion span { 388 | display: table-cell; 389 | white-space: nowrap; } 390 | form[role=search] .tt-suggestion .doc-parent-name { 391 | width: 100%; 392 | text-align: right; 393 | font-weight: normal; 394 | font-size: 0.9em; 395 | padding-left: 16px; } 396 | 397 | form[role=search] .tt-suggestion:hover, 398 | form[role=search] .tt-suggestion.tt-cursor { 399 | cursor: pointer; 400 | background-color: #4183c4; 401 | color: #fff; } 402 | 403 | form[role=search] .tt-suggestion:hover .doc-parent-name, 404 | form[role=search] .tt-suggestion.tt-cursor .doc-parent-name { 405 | color: #fff; } 406 | -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumob/PunycodeSwift/46aa59ec5262a994026b1b2c42a7a7f821dd45c8/docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumob/PunycodeSwift/46aa59ec5262a994026b1b2c42a7a7f821dd45c8/docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumob/PunycodeSwift/46aa59ec5262a994026b1b2c42a7a7f821dd45c8/docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumob/PunycodeSwift/46aa59ec5262a994026b1b2c42a7a7f821dd45c8/docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/img/spinner.gif -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Punycode Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

22 | 23 | Punycode 3.0.0 Docs 24 | 25 | 26 |

27 | 28 |
29 |
30 | 31 |
32 |
33 | 34 |

35 | 36 | GitHub 37 | View on GitHub 38 | 39 |

40 | 41 |

42 | 43 | Dash 44 | Install in Dash 45 | 46 |

47 |
48 | 49 | 52 | 53 |
54 | 77 |
78 | 79 |
80 |
81 | 82 |

Swift Package Manager compatible 83 | Carthage compatible 84 | Cocoapods Version 85 | Cocoapods Platform 86 | Build 87 | codecov 88 | Language 89 | Packagist

90 |

PunycodeSwift

91 | 92 |

PunycodeSwift is a pure Swift library to allows you to encode and decode punycoded strings by using String extension.

93 |

What is Punycode?

94 | 95 |

Punycode is a representation of Unicode with the limited ASCII character subset used for Internet host names. Using Punycode, host names containing Unicode characters are transcoded to a subset of ASCII consisting of letters, digits, and hyphen, which is called the Letter-Digit-Hyphen (LDH) subset. For example, München (German name for Munich) is encoded as Mnchen-3ya. (Wikipedia)

96 |

Requirements

97 | 98 |
    99 |
  • macOS 10.13 or later
  • 100 |
  • iOS 12.0 or later
  • 101 |
  • tvOS 12.0 or later
  • 102 |
  • watchOS 4.0 or later
  • 103 |
  • visionOS 1.0 or later
  • 104 |
  • Swift 5.0 or later
  • 105 |
106 |

Installation

107 |

Swift Package Manager

108 | 109 |

Add the following to your Package.swift file.

110 | 111 |
    112 |
  • macOS, iOS, tvOS, watchOS, visionOS, and Swift 5

    113 |
    dependencies: [
    114 |     .package(url: "https://github.com/gumob/PunycodeSwift.git", .upToNextMajor(from: "3.0.0"))
    115 | ]
    116 | 
  • 117 |
  • macOS, iOS, tvOS, and Swift 5

    118 |
    dependencies: [
    119 |     .package(url: "https://github.com/gumob/PunycodeSwift.git", .upToNextMajor(from: "2.1.1"))
    120 | ]
    121 | 
  • 122 |
123 |

Carthage

124 | 125 |

Add the following to your Cartfile and follow these instructions.

126 | 127 |
    128 |
  • macOS, iOS, tvOS, watchOS, visionOS, and Swift 5

    129 |
    github "gumob/PunycodeSwift" ~> 3.0
    130 | 
  • 131 |
  • macOS, iOS, tvOS, and Swift 5

    132 |
    github "gumob/PunycodeSwift" ~> 2.0
    133 | 
  • 134 |
  • macOS, iOS, tvOS, and Swift 4

    135 |
    github "gumob/PunycodeSwift" ~> 1.0
    136 | 
  • 137 |
138 |

CocoaPods

139 | 140 |

To integrate TLDExtract into your project, add the following to your Podfile.

141 | 142 |
    143 |
  • macOS, iOS, tvOS, watchOS, visionOS, and Swift 5.0

    144 |
    pod 'Punycode', '~> 3.0'
    145 | 
  • 146 |
  • macOS, iOS, tvOS, and Swift 5.0

    147 |
    pod 'Punycode', '~> 2.0'
    148 | 
  • 149 |
  • macOS, iOS, tvOS, and Swift 4.2

    150 |
    pod 'Punycode', '~> 1.0'
    151 | 
  • 152 |
153 |

Usage

154 | 155 |

Full documentation is available at https://gumob.github.io/PunycodeSwift/swiftdoc/.

156 |

Encode and decode IDNA:

157 |
import Punycode
158 | 
159 | var sushi: String = "寿司"
160 | 
161 | sushi = sushi.idnaEncoded!
162 | print(sushi)  // xn--sprr0q
163 | 
164 | sushi = sushi.idnaDecoded!
165 | print(sushi)  // "寿司"
166 | 
167 |

Encode and decode Punycode directly:

168 |
import Punycode
169 | 
170 | var sushi: String = "寿司"
171 | 
172 | sushi = sushi.punycodeEncoded!
173 | print(sushi)  // sprr0q
174 | 
175 | sushi = sushi.punycodeDecoded!
176 | print(sushi)  // "寿司"
177 | 
178 | 179 | 180 |

Punycode is released under MIT license, which means you can modify it, redistribute it or use it however you like.

181 | 182 |
183 |
184 | 185 | 186 |
187 |
188 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/js/jazzy.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | window.jazzy = {'docset': false} 6 | if (typeof window.dash != 'undefined') { 7 | document.documentElement.className += ' dash' 8 | window.jazzy.docset = true 9 | } 10 | if (navigator.userAgent.match(/xcode/i)) { 11 | document.documentElement.className += ' xcode' 12 | window.jazzy.docset = true 13 | } 14 | 15 | function toggleItem($link, $content) { 16 | var animationDuration = 300; 17 | $link.toggleClass('token-open'); 18 | $content.slideToggle(animationDuration); 19 | } 20 | 21 | function itemLinkToContent($link) { 22 | return $link.parent().parent().next(); 23 | } 24 | 25 | // On doc load + hash-change, open any targetted item 26 | function openCurrentItemIfClosed() { 27 | if (window.jazzy.docset) { 28 | return; 29 | } 30 | var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); 31 | $content = itemLinkToContent($link); 32 | if ($content.is(':hidden')) { 33 | toggleItem($link, $content); 34 | } 35 | } 36 | 37 | $(openCurrentItemIfClosed); 38 | $(window).on('hashchange', openCurrentItemIfClosed); 39 | 40 | // On item link ('token') click, toggle its discussion 41 | $('.token').on('click', function(event) { 42 | if (window.jazzy.docset) { 43 | return; 44 | } 45 | var $link = $(this); 46 | toggleItem($link, itemLinkToContent($link)); 47 | 48 | // Keeps the document from jumping to the hash. 49 | var href = $link.attr('href'); 50 | if (history.pushState) { 51 | history.pushState({}, '', href); 52 | } else { 53 | location.hash = href; 54 | } 55 | event.preventDefault(); 56 | }); 57 | 58 | // Clicks on links to the current, closed, item need to open the item 59 | $("a:not('.token')").on('click', function() { 60 | if (location == this.href) { 61 | openCurrentItemIfClosed(); 62 | } 63 | }); 64 | 65 | // KaTeX rendering 66 | if ("katex" in window) { 67 | $($('.math').each( (_, element) => { 68 | katex.render(element.textContent, element, { 69 | displayMode: $(element).hasClass('m-block'), 70 | throwOnError: false, 71 | trust: true 72 | }); 73 | })) 74 | } 75 | -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/js/jazzy.search.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | $(function(){ 6 | var $typeahead = $('[data-typeahead]'); 7 | var $form = $typeahead.parents('form'); 8 | var searchURL = $form.attr('action'); 9 | 10 | function displayTemplate(result) { 11 | return result.name; 12 | } 13 | 14 | function suggestionTemplate(result) { 15 | var t = '
'; 16 | t += '' + result.name + ''; 17 | if (result.parent_name) { 18 | t += '' + result.parent_name + ''; 19 | } 20 | t += '
'; 21 | return t; 22 | } 23 | 24 | $typeahead.one('focus', function() { 25 | $form.addClass('loading'); 26 | 27 | $.getJSON(searchURL).then(function(searchData) { 28 | const searchIndex = lunr(function() { 29 | this.ref('url'); 30 | this.field('name'); 31 | this.field('abstract'); 32 | for (const [url, doc] of Object.entries(searchData)) { 33 | this.add({url: url, name: doc.name, abstract: doc.abstract}); 34 | } 35 | }); 36 | 37 | $typeahead.typeahead( 38 | { 39 | highlight: true, 40 | minLength: 3, 41 | autoselect: true 42 | }, 43 | { 44 | limit: 10, 45 | display: displayTemplate, 46 | templates: { suggestion: suggestionTemplate }, 47 | source: function(query, sync) { 48 | const lcSearch = query.toLowerCase(); 49 | const results = searchIndex.query(function(q) { 50 | q.term(lcSearch, { boost: 100 }); 51 | q.term(lcSearch, { 52 | boost: 10, 53 | wildcard: lunr.Query.wildcard.TRAILING 54 | }); 55 | }).map(function(result) { 56 | var doc = searchData[result.ref]; 57 | doc.url = result.ref; 58 | return doc; 59 | }); 60 | sync(results); 61 | } 62 | } 63 | ); 64 | $form.removeClass('loading'); 65 | $typeahead.trigger('focus'); 66 | }); 67 | }); 68 | 69 | var baseURL = searchURL.slice(0, -"search.json".length); 70 | 71 | $typeahead.on('typeahead:select', function(e, result) { 72 | window.location = baseURL + result.url; 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/Documents/search.json: -------------------------------------------------------------------------------- 1 | {"Extensions/String.html#/s:SS8PunycodeE15punycodeEncodedSSSgvp":{"name":"punycodeEncoded","abstract":"\u003cp\u003eReturns new string in punycode encoding (RFC 3492)\u003c/p\u003e","parent_name":"String"},"Extensions/String.html#/s:SS8PunycodeE15punycodeDecodedSSSgvp":{"name":"punycodeDecoded","abstract":"\u003cp\u003eReturns new string decoded from punycode representation (RFC 3492)\u003c/p\u003e","parent_name":"String"},"Extensions/String.html#/s:SS8PunycodeE11idnaEncodedSSSgvp":{"name":"idnaEncoded","abstract":"\u003cp\u003eReturns new string containing IDNA-encoded hostname\u003c/p\u003e","parent_name":"String"},"Extensions/String.html#/s:SS8PunycodeE11idnaDecodedSSSgvp":{"name":"idnaDecoded","abstract":"\u003cp\u003eReturns new string containing hostname decoded from IDNA representation\u003c/p\u003e","parent_name":"String"},"Extensions/Substring.html#/s:Ss8PunycodeE15punycodeEncodedSSSgvp":{"name":"punycodeEncoded","abstract":"\u003cp\u003eReturns new string in punycode encoding (RFC 3492)\u003c/p\u003e","parent_name":"Substring"},"Extensions/Substring.html#/s:Ss8PunycodeE15punycodeDecodedSSSgvp":{"name":"punycodeDecoded","abstract":"\u003cp\u003eReturns new string decoded from punycode representation (RFC 3492)\u003c/p\u003e","parent_name":"Substring"},"Extensions/Substring.html#/s:Ss8PunycodeE11idnaEncodedSSSgvp":{"name":"idnaEncoded","abstract":"\u003cp\u003eReturns new string containing IDNA-encoded hostname\u003c/p\u003e","parent_name":"Substring"},"Extensions/Substring.html#/s:Ss8PunycodeE11idnaDecodedSSSgvp":{"name":"idnaDecoded","abstract":"\u003cp\u003eReturns new string containing hostname decoded from IDNA representation\u003c/p\u003e","parent_name":"Substring"},"Extensions/Substring.html":{"name":"Substring","abstract":"\u003cp\u003eThis extension provides methods for encoding and decoding strings using Punycode (RFC 3492)"},"Extensions/String.html":{"name":"String","abstract":"\u003cp\u003eThis extension provides methods for encoding and decoding strings using Punycode (RFC 3492)"},"Classes/Puny.html#/s:8Punycode4PunyC06decodeA0ySSSgSsF":{"name":"decodePunycode(_:)","abstract":"\u003cp\u003eDecodes a punycode encoded string to its original representation.\u003c/p\u003e","parent_name":"Puny"},"Classes/Puny.html#/s:8Punycode4PunyC06encodeA0ySSSgSsF":{"name":"encodePunycode(_:)","abstract":"\u003cp\u003eEncodes a substring to punycode (RFC 3492).\u003c/p\u003e","parent_name":"Puny"},"Classes/Puny.html#/s:8Punycode4PunyC10encodeIDNAySSSgSsF":{"name":"encodeIDNA(_:)","abstract":"\u003cp\u003eReturns new string containing IDNA-encoded hostname.\u003c/p\u003e","parent_name":"Puny"},"Classes/Puny.html#/s:8Punycode4PunyC11decodedIDNAySSSgSsF":{"name":"decodedIDNA(_:)","abstract":"\u003cp\u003eReturns a new string containing the hostname decoded from IDNA representation.\u003c/p\u003e","parent_name":"Puny"},"Classes/Puny.html":{"name":"Puny","abstract":"\u003cp\u003ePuny class provides methods to encode and decode strings using Punycode (RFC 3492)."},"Classes.html":{"name":"Classes","abstract":"\u003cp\u003eThe following classes are available globally.\u003c/p\u003e"},"Extensions.html":{"name":"Extensions","abstract":"\u003cp\u003eThe following extensions are available globally.\u003c/p\u003e"}} -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumob/PunycodeSwift/46aa59ec5262a994026b1b2c42a7a7f821dd45c8/docs/swiftdoc/docsets/Punycode.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/swiftdoc/docsets/Punycode.xml: -------------------------------------------------------------------------------- 1 | 3.0.0https://github.com/gumob/PunycodeSwift/tree/3.0.0/docs/docsets/Punycode.tgz 2 | -------------------------------------------------------------------------------- /docs/swiftdoc/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumob/PunycodeSwift/46aa59ec5262a994026b1b2c42a7a7f821dd45c8/docs/swiftdoc/img/carat.png -------------------------------------------------------------------------------- /docs/swiftdoc/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumob/PunycodeSwift/46aa59ec5262a994026b1b2c42a7a7f821dd45c8/docs/swiftdoc/img/dash.png -------------------------------------------------------------------------------- /docs/swiftdoc/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumob/PunycodeSwift/46aa59ec5262a994026b1b2c42a7a7f821dd45c8/docs/swiftdoc/img/gh.png -------------------------------------------------------------------------------- /docs/swiftdoc/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumob/PunycodeSwift/46aa59ec5262a994026b1b2c42a7a7f821dd45c8/docs/swiftdoc/img/spinner.gif -------------------------------------------------------------------------------- /docs/swiftdoc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Punycode Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

22 | 23 | Punycode 3.0.0 Docs 24 | 25 | 26 |

27 | 28 |
29 |
30 | 31 |
32 |
33 | 34 |

35 | 36 | GitHub 37 | View on GitHub 38 | 39 |

40 | 41 |

42 | 43 | Dash 44 | Install in Dash 45 | 46 |

47 |
48 | 49 | 52 | 53 |
54 | 77 |
78 | 79 |
80 |
81 | 82 |

Swift Package Manager compatible 83 | Carthage compatible 84 | Cocoapods Version 85 | Cocoapods Platform 86 | Build 87 | codecov 88 | Language 89 | Packagist

90 |

PunycodeSwift

91 | 92 |

PunycodeSwift is a pure Swift library to allows you to encode and decode punycoded strings by using String extension.

93 |

What is Punycode?

94 | 95 |

Punycode is a representation of Unicode with the limited ASCII character subset used for Internet host names. Using Punycode, host names containing Unicode characters are transcoded to a subset of ASCII consisting of letters, digits, and hyphen, which is called the Letter-Digit-Hyphen (LDH) subset. For example, München (German name for Munich) is encoded as Mnchen-3ya. (Wikipedia)

96 |

Requirements

97 | 98 |
    99 |
  • macOS 10.13 or later
  • 100 |
  • iOS 12.0 or later
  • 101 |
  • tvOS 12.0 or later
  • 102 |
  • watchOS 4.0 or later
  • 103 |
  • visionOS 1.0 or later
  • 104 |
  • Swift 5.0 or later
  • 105 |
106 |

Installation

107 |

Swift Package Manager

108 | 109 |

Add the following to your Package.swift file.

110 | 111 |
    112 |
  • macOS, iOS, tvOS, watchOS, visionOS, and Swift 5

    113 |
    dependencies: [
    114 |     .package(url: "https://github.com/gumob/PunycodeSwift.git", .upToNextMajor(from: "3.0.0"))
    115 | ]
    116 | 
  • 117 |
  • macOS, iOS, tvOS, and Swift 5

    118 |
    dependencies: [
    119 |     .package(url: "https://github.com/gumob/PunycodeSwift.git", .upToNextMajor(from: "2.1.1"))
    120 | ]
    121 | 
  • 122 |
123 |

Carthage

124 | 125 |

Add the following to your Cartfile and follow these instructions.

126 | 127 |
    128 |
  • macOS, iOS, tvOS, watchOS, visionOS, and Swift 5

    129 |
    github "gumob/PunycodeSwift" ~> 3.0
    130 | 
  • 131 |
  • macOS, iOS, tvOS, and Swift 5

    132 |
    github "gumob/PunycodeSwift" ~> 2.0
    133 | 
  • 134 |
  • macOS, iOS, tvOS, and Swift 4

    135 |
    github "gumob/PunycodeSwift" ~> 1.0
    136 | 
  • 137 |
138 |

CocoaPods

139 | 140 |

To integrate TLDExtract into your project, add the following to your Podfile.

141 | 142 |
    143 |
  • macOS, iOS, tvOS, watchOS, visionOS, and Swift 5.0

    144 |
    pod 'Punycode', '~> 3.0'
    145 | 
  • 146 |
  • macOS, iOS, tvOS, and Swift 5.0

    147 |
    pod 'Punycode', '~> 2.0'
    148 | 
  • 149 |
  • macOS, iOS, tvOS, and Swift 4.2

    150 |
    pod 'Punycode', '~> 1.0'
    151 | 
  • 152 |
153 |

Usage

154 | 155 |

Full documentation is available at https://gumob.github.io/PunycodeSwift/swiftdoc/.

156 |

Encode and decode IDNA:

157 |
import Punycode
158 | 
159 | var sushi: String = "寿司"
160 | 
161 | sushi = sushi.idnaEncoded!
162 | print(sushi)  // xn--sprr0q
163 | 
164 | sushi = sushi.idnaDecoded!
165 | print(sushi)  // "寿司"
166 | 
167 |

Encode and decode Punycode directly:

168 |
import Punycode
169 | 
170 | var sushi: String = "寿司"
171 | 
172 | sushi = sushi.punycodeEncoded!
173 | print(sushi)  // sprr0q
174 | 
175 | sushi = sushi.punycodeDecoded!
176 | print(sushi)  // "寿司"
177 | 
178 | 179 | 180 |

Punycode is released under MIT license, which means you can modify it, redistribute it or use it however you like.

181 | 182 |
183 |
184 | 185 | 186 |
187 |
188 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /docs/swiftdoc/js/jazzy.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | window.jazzy = {'docset': false} 6 | if (typeof window.dash != 'undefined') { 7 | document.documentElement.className += ' dash' 8 | window.jazzy.docset = true 9 | } 10 | if (navigator.userAgent.match(/xcode/i)) { 11 | document.documentElement.className += ' xcode' 12 | window.jazzy.docset = true 13 | } 14 | 15 | function toggleItem($link, $content) { 16 | var animationDuration = 300; 17 | $link.toggleClass('token-open'); 18 | $content.slideToggle(animationDuration); 19 | } 20 | 21 | function itemLinkToContent($link) { 22 | return $link.parent().parent().next(); 23 | } 24 | 25 | // On doc load + hash-change, open any targetted item 26 | function openCurrentItemIfClosed() { 27 | if (window.jazzy.docset) { 28 | return; 29 | } 30 | var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); 31 | $content = itemLinkToContent($link); 32 | if ($content.is(':hidden')) { 33 | toggleItem($link, $content); 34 | } 35 | } 36 | 37 | $(openCurrentItemIfClosed); 38 | $(window).on('hashchange', openCurrentItemIfClosed); 39 | 40 | // On item link ('token') click, toggle its discussion 41 | $('.token').on('click', function(event) { 42 | if (window.jazzy.docset) { 43 | return; 44 | } 45 | var $link = $(this); 46 | toggleItem($link, itemLinkToContent($link)); 47 | 48 | // Keeps the document from jumping to the hash. 49 | var href = $link.attr('href'); 50 | if (history.pushState) { 51 | history.pushState({}, '', href); 52 | } else { 53 | location.hash = href; 54 | } 55 | event.preventDefault(); 56 | }); 57 | 58 | // Clicks on links to the current, closed, item need to open the item 59 | $("a:not('.token')").on('click', function() { 60 | if (location == this.href) { 61 | openCurrentItemIfClosed(); 62 | } 63 | }); 64 | 65 | // KaTeX rendering 66 | if ("katex" in window) { 67 | $($('.math').each( (_, element) => { 68 | katex.render(element.textContent, element, { 69 | displayMode: $(element).hasClass('m-block'), 70 | throwOnError: false, 71 | trust: true 72 | }); 73 | })) 74 | } 75 | -------------------------------------------------------------------------------- /docs/swiftdoc/js/jazzy.search.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | $(function(){ 6 | var $typeahead = $('[data-typeahead]'); 7 | var $form = $typeahead.parents('form'); 8 | var searchURL = $form.attr('action'); 9 | 10 | function displayTemplate(result) { 11 | return result.name; 12 | } 13 | 14 | function suggestionTemplate(result) { 15 | var t = '
'; 16 | t += '' + result.name + ''; 17 | if (result.parent_name) { 18 | t += '' + result.parent_name + ''; 19 | } 20 | t += '
'; 21 | return t; 22 | } 23 | 24 | $typeahead.one('focus', function() { 25 | $form.addClass('loading'); 26 | 27 | $.getJSON(searchURL).then(function(searchData) { 28 | const searchIndex = lunr(function() { 29 | this.ref('url'); 30 | this.field('name'); 31 | this.field('abstract'); 32 | for (const [url, doc] of Object.entries(searchData)) { 33 | this.add({url: url, name: doc.name, abstract: doc.abstract}); 34 | } 35 | }); 36 | 37 | $typeahead.typeahead( 38 | { 39 | highlight: true, 40 | minLength: 3, 41 | autoselect: true 42 | }, 43 | { 44 | limit: 10, 45 | display: displayTemplate, 46 | templates: { suggestion: suggestionTemplate }, 47 | source: function(query, sync) { 48 | const lcSearch = query.toLowerCase(); 49 | const results = searchIndex.query(function(q) { 50 | q.term(lcSearch, { boost: 100 }); 51 | q.term(lcSearch, { 52 | boost: 10, 53 | wildcard: lunr.Query.wildcard.TRAILING 54 | }); 55 | }).map(function(result) { 56 | var doc = searchData[result.ref]; 57 | doc.url = result.ref; 58 | return doc; 59 | }); 60 | sync(results); 61 | } 62 | } 63 | ); 64 | $form.removeClass('loading'); 65 | $typeahead.trigger('focus'); 66 | }); 67 | }); 68 | 69 | var baseURL = searchURL.slice(0, -"search.json".length); 70 | 71 | $typeahead.on('typeahead:select', function(e, result) { 72 | window.location = baseURL + result.url; 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /docs/swiftdoc/search.json: -------------------------------------------------------------------------------- 1 | {"Extensions/String.html#/s:SS8PunycodeE15punycodeEncodedSSSgvp":{"name":"punycodeEncoded","abstract":"\u003cp\u003eReturns new string in punycode encoding (RFC 3492)\u003c/p\u003e","parent_name":"String"},"Extensions/String.html#/s:SS8PunycodeE15punycodeDecodedSSSgvp":{"name":"punycodeDecoded","abstract":"\u003cp\u003eReturns new string decoded from punycode representation (RFC 3492)\u003c/p\u003e","parent_name":"String"},"Extensions/String.html#/s:SS8PunycodeE11idnaEncodedSSSgvp":{"name":"idnaEncoded","abstract":"\u003cp\u003eReturns new string containing IDNA-encoded hostname\u003c/p\u003e","parent_name":"String"},"Extensions/String.html#/s:SS8PunycodeE11idnaDecodedSSSgvp":{"name":"idnaDecoded","abstract":"\u003cp\u003eReturns new string containing hostname decoded from IDNA representation\u003c/p\u003e","parent_name":"String"},"Extensions/Substring.html#/s:Ss8PunycodeE15punycodeEncodedSSSgvp":{"name":"punycodeEncoded","abstract":"\u003cp\u003eReturns new string in punycode encoding (RFC 3492)\u003c/p\u003e","parent_name":"Substring"},"Extensions/Substring.html#/s:Ss8PunycodeE15punycodeDecodedSSSgvp":{"name":"punycodeDecoded","abstract":"\u003cp\u003eReturns new string decoded from punycode representation (RFC 3492)\u003c/p\u003e","parent_name":"Substring"},"Extensions/Substring.html#/s:Ss8PunycodeE11idnaEncodedSSSgvp":{"name":"idnaEncoded","abstract":"\u003cp\u003eReturns new string containing IDNA-encoded hostname\u003c/p\u003e","parent_name":"Substring"},"Extensions/Substring.html#/s:Ss8PunycodeE11idnaDecodedSSSgvp":{"name":"idnaDecoded","abstract":"\u003cp\u003eReturns new string containing hostname decoded from IDNA representation\u003c/p\u003e","parent_name":"Substring"},"Extensions/Substring.html":{"name":"Substring","abstract":"\u003cp\u003eThis extension provides methods for encoding and decoding strings using Punycode (RFC 3492)"},"Extensions/String.html":{"name":"String","abstract":"\u003cp\u003eThis extension provides methods for encoding and decoding strings using Punycode (RFC 3492)"},"Classes/Puny.html#/s:8Punycode4PunyC06decodeA0ySSSgSsF":{"name":"decodePunycode(_:)","abstract":"\u003cp\u003eDecodes a punycode encoded string to its original representation.\u003c/p\u003e","parent_name":"Puny"},"Classes/Puny.html#/s:8Punycode4PunyC06encodeA0ySSSgSsF":{"name":"encodePunycode(_:)","abstract":"\u003cp\u003eEncodes a substring to punycode (RFC 3492).\u003c/p\u003e","parent_name":"Puny"},"Classes/Puny.html#/s:8Punycode4PunyC10encodeIDNAySSSgSsF":{"name":"encodeIDNA(_:)","abstract":"\u003cp\u003eReturns new string containing IDNA-encoded hostname.\u003c/p\u003e","parent_name":"Puny"},"Classes/Puny.html#/s:8Punycode4PunyC11decodedIDNAySSSgSsF":{"name":"decodedIDNA(_:)","abstract":"\u003cp\u003eReturns a new string containing the hostname decoded from IDNA representation.\u003c/p\u003e","parent_name":"Puny"},"Classes/Puny.html":{"name":"Puny","abstract":"\u003cp\u003ePuny class provides methods to encode and decode strings using Punycode (RFC 3492)."},"Classes.html":{"name":"Classes","abstract":"\u003cp\u003eThe following classes are available globally.\u003c/p\u003e"},"Extensions.html":{"name":"Extensions","abstract":"\u003cp\u003eThe following extensions are available globally.\u003c/p\u003e"}} -------------------------------------------------------------------------------- /docs/swiftdoc/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | 4 | ], 5 | "source_directory": "/Users/kojirof/Documents/Workspace/Projects/pj-github/PunycodeSwift/Sources" 6 | } -------------------------------------------------------------------------------- /fastlane/Appfile: -------------------------------------------------------------------------------- 1 | # app_identifier("[[APP_IDENTIFIER]]") # The bundle identifier of your app 2 | # apple_id("[[APPLE_ID]]") # Your Apple email address 3 | 4 | 5 | # For more information about the Appfile, see: 6 | # https://docs.fastlane.tools/advanced/#appfile 7 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | default_platform(:ios) 2 | 3 | # 4 | # Workaround for following error while executing `pod lib lint` and `pod trunk push` 5 | # 6 | # EXPANDED_CODE_SIGN_IDENTITY: unbound variable 7 | # Command PhaseScriptExecution failed with a nonzero exit code 8 | # 9 | # For more information is available at 10 | # https://github.com/CocoaPods/CocoaPods/issues/8000#issuecomment-434488071 11 | # 12 | ENV["EXPANDED_CODE_SIGN_IDENTITY"] = "" 13 | ENV["EXPANDED_CODE_SIGN_IDENTITY_NAME"] = "" 14 | ENV["EXPANDED_PROVISIONING_PROFILE"] = "" 15 | 16 | xcodeproj_file="Punycode.xcodeproj" 17 | podspec_file="Punycode.podspec" 18 | scheme = "Punycode" 19 | 20 | desc "Run all jobs" 21 | lane :run_all do 22 | lint_swift 23 | tests 24 | build_spm 25 | build_carthage 26 | lint_cocoapods 27 | gen_docs 28 | end 29 | 30 | ########################################## 31 | # Lint 32 | ########################################## 33 | 34 | desc "Lint codes with swift-format" 35 | lane :lint_swift do 36 | # sh("swift-format", "format", "--in-place", "--ignore-unparsable-files", "--configuration", "../.swift-format", "--recursive", "../Sources", "../Tests") 37 | sh("swift-format", "lint", "--ignore-unparsable-files", "--configuration", "../.swift-format", "--recursive", "../Sources", "../Tests") 38 | end 39 | 40 | ########################################## 41 | # Versioning 42 | ########################################## 43 | 44 | desc "Set version number" 45 | lane :set_version do 46 | current_app_version = get_version_number_from_xcodeproj(xcodeproj: xcodeproj_file) 47 | new_app_version = prompt( 48 | text: "Please enter version number (Current: #{current_app_version}): ", 49 | ci_input: current_app_version 50 | ) 51 | regexp = Regexp.new("[0-9]+\.[0-9]+\.[0-9]+") 52 | matched = regexp.match(new_app_version) 53 | if matched then 54 | # Set version number to project 55 | increment_version_number_in_xcodeproj(version_number: new_app_version) 56 | # Set version number to podspec 57 | version_bump_podspec(path: podspec_file, version_number: new_app_version) 58 | # Set version number to .jazzy.yml 59 | if File.exist?("../.jazzy.yml") 60 | sh("sed", "-i", "", "s/version: [0-9]*\\.[0-9]*\\.[0-9]*/version: #{new_app_version}/g", "../.jazzy.yml") 61 | sh("sed", "-i", "", "s|root_url: https://github.com/gumob/PunycodeSwift/tree/[0-9]*\\.[0-9]*\\.[0-9]*/docs/|root_url: https://github.com/gumob/PunycodeSwift/tree/#{new_app_version}/docs/|g", "../.jazzy.yml") 62 | else 63 | UI.error("No such file or directory: .jazzy.yml") 64 | end 65 | UI.message("Changed version from #{current_app_version} to #{new_app_version} ") 66 | else 67 | UI.error("Invalid version number. #{new_app_version}") 68 | end 69 | end 70 | 71 | desc "Bump version number" 72 | lane :bump_version do 73 | bump_type = UI.select("Select version position to be upgraded: ", ["patch", "minor", "major"]) 74 | current_app_version = get_version_number_from_xcodeproj(xcodeproj: xcodeproj_file) 75 | current_app_versions = current_app_version.split(".") 76 | current_app_version_patch = current_app_versions[2].to_i 77 | current_app_version_minor = current_app_versions[1].to_i 78 | current_app_version_major = current_app_versions[0].to_i 79 | UI.message(current_app_versions) 80 | if bump_type == "patch" then 81 | current_app_version_patch += 1 82 | elsif bump_type == "minor" then 83 | current_app_version_patch = 0 84 | current_app_version_minor += 1 85 | elsif bump_type == "major" then 86 | current_app_version_patch = 0 87 | current_app_version_minor = 0 88 | current_app_version_major += 1 89 | end 90 | new_app_version = [current_app_version_major, current_app_version_minor, current_app_version_patch].join(".") 91 | # Set version number to project 92 | increment_version_number_in_xcodeproj(version_number: new_app_version) 93 | # Set version number to podspec 94 | version_bump_podspec(path: podspec_file, version_number: new_app_version) 95 | # Set version number to .jazzy.yml 96 | if File.exist?("../.jazzy.yml") 97 | sh("sed", "-i", "", "s/version: [0-9]*\\.[0-9]*\\.[0-9]*/version: #{new_app_version}/g", "../.jazzy.yml") 98 | sh("sed", "-i", "", "s|root_url: https://github.com/gumob/PunycodeSwift/tree/[0-9]*\\.[0-9]*\\.[0-9]*/docs/|root_url: https://github.com/gumob/PunycodeSwift/tree/#{new_app_version}/docs/|g", "../.jazzy.yml") 99 | else 100 | UI.error("No such file or directory: .jazzy.yml") 101 | end 102 | UI.message("Changed version from #{current_app_version} to #{new_app_version} ") 103 | end 104 | 105 | ########################################## 106 | # Test 107 | ########################################## 108 | 109 | desc "Run all tests" 110 | lane :tests do 111 | xcclean 112 | 113 | desc "Run macOS Tests" 114 | run_tests( 115 | destination: "platform=macOS", 116 | scheme: scheme, 117 | force_quit_simulator: true, 118 | reset_simulator: true, 119 | prelaunch_simulator: false, 120 | code_coverage: true, 121 | open_report: false, 122 | output_files: "report-macos.html,report-macos.junit" 123 | ) 124 | slather( 125 | scheme: scheme, 126 | proj: xcodeproj_file, 127 | output_directory: "./fastlane/reports/macOS", 128 | html: true, 129 | show: false 130 | ) 131 | 132 | desc "Run iOS Tests" 133 | run_tests( 134 | destination: "platform=iOS Simulator,name=iPhone 15 Pro", 135 | scheme: scheme, 136 | force_quit_simulator: true, 137 | reset_simulator: true, 138 | prelaunch_simulator: false, 139 | code_coverage: true, 140 | open_report: false, 141 | output_files: "report-ios.html,report-ios.junit" 142 | ) 143 | slather( 144 | scheme: scheme, 145 | proj: xcodeproj_file, 146 | output_directory: "./fastlane/reports/iOS", 147 | html: true, 148 | show: false 149 | ) 150 | 151 | desc "Run tvOS Tests" 152 | run_tests( 153 | destination: "platform=tvOS Simulator,name=Apple TV 4K (3rd generation)", 154 | scheme: scheme, 155 | force_quit_simulator: true, 156 | reset_simulator: true, 157 | prelaunch_simulator: false, 158 | code_coverage: true, 159 | open_report: false, 160 | output_files: "report-tvos.html,report-tvos.junit" 161 | ) 162 | slather( 163 | scheme: scheme, 164 | proj: xcodeproj_file, 165 | output_directory: "./fastlane/reports/tvOS", 166 | html: true, 167 | show: false 168 | ) 169 | 170 | desc "Run watchOS Tests" 171 | run_tests( 172 | destination: "platform=watchOS Simulator,name=Apple Watch Series 9 (45mm)", 173 | scheme: scheme, 174 | force_quit_simulator: true, 175 | reset_simulator: true, 176 | prelaunch_simulator: false, 177 | code_coverage: true, 178 | open_report: false, 179 | output_files: "report-watchos.html,report-watchos.junit" 180 | ) 181 | slather( 182 | scheme: scheme, 183 | proj: xcodeproj_file, 184 | output_directory: "./fastlane/reports/watchOS", 185 | html: true, 186 | show: false 187 | ) 188 | 189 | desc "Run visionOS Tests" 190 | run_tests( 191 | destination: "platform=visionOS Simulator,name=Apple Vision Pro", 192 | scheme: scheme, 193 | force_quit_simulator: true, 194 | reset_simulator: true, 195 | prelaunch_simulator: false, 196 | code_coverage: true, 197 | open_report: false, 198 | output_files: "report-visionos.html,report-visionos.junit" 199 | ) 200 | slather( 201 | scheme: scheme, 202 | proj: xcodeproj_file, 203 | output_directory: "./fastlane/reports/visionOS", 204 | html: true, 205 | show: false 206 | ) 207 | 208 | end 209 | 210 | ########################################## 211 | # Package Manager 212 | ########################################## 213 | 214 | desc "Lint Swift Package Manager" 215 | lane :build_spm do |options| 216 | spm( 217 | command: "build", 218 | parallel: true 219 | ) 220 | spm( 221 | command: "test", 222 | parallel: true 223 | ) 224 | end 225 | 226 | desc "Build Carthage" 227 | lane :build_carthage do |options| 228 | carthage( 229 | command: "build", 230 | verbose: false, 231 | platform: "Mac", 232 | # use_xcframeworks: true, 233 | no_skip_current: true 234 | ) 235 | carthage( 236 | command: "build", 237 | verbose: false, 238 | platform: "iOS", 239 | use_xcframeworks: true, 240 | no_skip_current: true 241 | ) 242 | carthage( 243 | command: "build", 244 | verbose: false, 245 | platform: "tvOS", 246 | use_xcframeworks: true, 247 | no_skip_current: true 248 | ) 249 | carthage( 250 | command: "build", 251 | verbose: false, 252 | platform: "watchOS", 253 | use_xcframeworks: true, 254 | no_skip_current: true 255 | ) 256 | # carthage( 257 | # command: "build", 258 | # verbose: false, 259 | # platform: "visionOS", 260 | # use_xcframeworks: true, 261 | # no_skip_current: true 262 | # ) 263 | end 264 | 265 | desc "Lint Cocoapods" 266 | lane :lint_cocoapods do |options| 267 | pod_lib_lint(verbose: true) 268 | end 269 | 270 | desc "Push Cocoapods" 271 | lane :push_cocoapods do |options| 272 | pod_lib_lint(verbose: true) 273 | pod_push(path: podspec_file) 274 | end 275 | 276 | ########################################## 277 | # Swift Docs 278 | ########################################## 279 | 280 | desc "Generate Swift Docs" 281 | lane :gen_docs do 282 | jazzy( 283 | config: ".jazzy.yml" 284 | ) 285 | end -------------------------------------------------------------------------------- /fastlane/Pluginfile: -------------------------------------------------------------------------------- 1 | # Autogenerated by fastlane 2 | # 3 | # Ensure this file is checked in to source control! 4 | 5 | gem 'fastlane-plugin-versioning' 6 | -------------------------------------------------------------------------------- /fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ---- 3 | 4 | # Installation 5 | 6 | Make sure you have the latest version of the Xcode command line tools installed: 7 | 8 | ```sh 9 | xcode-select --install 10 | ``` 11 | 12 | For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane) 13 | 14 | # Available Actions 15 | 16 | ### Run all jobs 17 | 18 | ```sh 19 | bundle exec fastlane run_all 20 | ``` 21 | 22 | ### Set version number 23 | 24 | ```sh 25 | bundle exec fastlane set_version 26 | ``` 27 | 28 | ### Bump version number 29 | 30 | ```sh 31 | bundle exec fastlane bump_version 32 | ``` 33 | 34 | ### Run all tests 35 | 36 | ```sh 37 | bundle exec fastlane tests 38 | ``` 39 | 40 | ### Build SPM 41 | 42 | ```sh 43 | bundle exec fastlane build_spm 44 | ``` 45 | 46 | ### Build Carthage 47 | 48 | ```sh 49 | bundle exec fastlane build_carthage 50 | ``` 51 | 52 | ### Lint Cocoapods 53 | 54 | ```sh 55 | bundle exec fastlane lint_cocoapods 56 | ``` 57 | 58 | ### Push Cocoapods 59 | 60 | ```sh 61 | bundle exec fastlane push_cocoapods 62 | ``` 63 | 64 | ---- 65 | 66 | This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. 67 | 68 | More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools). 69 | 70 | The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 71 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Check if the 'fzf' command is available in the system 4 | if ! command -v fzf &> /dev/null; then 5 | tput setaf 1; echo "fzf is not installed."; tput sgr0; 6 | exit 1; 7 | fi 8 | 9 | local option_list=( 10 | "fastlane run_all" 11 | "fastlane lint_swift" 12 | "fastlane tests" 13 | "fastlane build_spm" 14 | "fastlane build_carthage" 15 | "fastlane lint_cocoapods" 16 | "fastlane push_cocoapods" 17 | "fastlane gen_docs" 18 | "fastlane set_version" 19 | "fastlane bump_version" 20 | " " 21 | "Xcode - Initialize project" 22 | "Xcode - Clean all build cache" 23 | " " 24 | "Carthage - Update all platforms" 25 | "Cocoapods - Clean all cache" 26 | "Cocoapods - Trunk push" 27 | " " 28 | "Github - Update tag" 29 | "Github - Fetch remote tag" 30 | " " 31 | "Public Suffix List - Download latest data" 32 | ) 33 | 34 | local fastlane_command() { 35 | bundle exec $1 36 | } 37 | 38 | local xcode_clean() { 39 | xcodebuild clean || \ 40 | xcodebuild -alltargets clean || \ 41 | xcrun --kill-cache || \ 42 | xcrun simctl erase all || \ 43 | rm -rf ~/Library/Developer/Xcode/DerivedData/; 44 | } 45 | local xcode_init() { 46 | bundle_init; 47 | xcode_clean; 48 | # rm -rf ./Carthage/*; 49 | # carthage_update; 50 | # psl_download; 51 | } 52 | 53 | local carthage_update() { 54 | carthage update --platform macos; 55 | carthage update --platform ios; 56 | carthage update --platform tvos; 57 | carthage update --platform watchos; 58 | carthage update --platform visionos; 59 | } 60 | 61 | local cocoapods_clean() { 62 | pod cache clean --all; 63 | } 64 | 65 | local cocoapods_trunk_push() { 66 | # Enable error handling and exit the script on pipe failures 67 | set -eo pipefail 68 | # Check if the current branch is 'main' 69 | if [[ $(git rev-parse --abbrev-ref HEAD) != "main" ]]; then 70 | echo "Warning: You are not on the main branch. Please switch to the main branch and run again." 71 | exit 1 72 | fi 73 | # Find the project name and podspec name 74 | project_name=$(find . -maxdepth 1 -name "*.xcodeproj" -exec basename {} .xcodeproj \;) 75 | podspec_name=$(find . -maxdepth 1 -name "*.podspec" -exec basename {} .podspec \;) 76 | # Retrieve the current version from the project file 77 | current_version=$(grep -m1 'MARKETING_VERSION' "${project_name}.xcodeproj/project.pbxproj" | sed 's/.*= //;s/;//') 78 | echo "Current version: $current_version" 79 | # Check if the current version is a valid semantic version 80 | if [[ ! "$current_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then 81 | echo "Error: Invalid version number" 82 | exit 1 83 | fi 84 | # Check if the current version already exists in the CocoaPods trunk 85 | if pod trunk info ${podspec_name} | grep -q "$current_version"; then 86 | echo "Start deleting $current_version" 87 | # Delete the existing version from the CocoaPods trunk 88 | echo "y" | pod trunk delete ${podspec_name} $current_version || true 89 | fi 90 | echo "Start pushing $current_version" 91 | # Push the new version to the CocoaPods trunk 92 | pod trunk push ${podspec_name}.podspec --allow-warnings 93 | } 94 | 95 | local github_update_tag() { 96 | # Enable error handling and exit the script on pipe failures 97 | set -eo pipefail 98 | # Check if the current branch is 'main' 99 | if [[ $(git rev-parse --abbrev-ref HEAD) != "main" ]]; then 100 | echo "Warning: You are not on the main branch. Please switch to the main branch and run again." 101 | exit 1 102 | fi 103 | # Find the project name and podspec name 104 | project_name=$(find . -maxdepth 1 -name "*.xcodeproj" -exec basename {} .xcodeproj) 105 | podspec_name=$(find . -maxdepth 1 -name "*.podspec" -exec basename {} .podspec) 106 | # Retrieve build settings and execute a command to filter MARKETING_VERSION 107 | current_version=$(grep -m1 'MARKETING_VERSION' "${project_name}.xcodeproj/project.pbxproj" | sed 's/.*= //;s/;//') 108 | echo "Current version: $current_version" 109 | # If the current version is found 110 | if [[ $current_version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then 111 | # Check if a tag for the current version already exists 112 | if git tag -l | grep -q "$current_version"; then 113 | # If the tag exists, delete it from both local and remote 114 | git tag -d "$current_version" 115 | git push origin ":refs/tags/$current_version" 116 | fi 117 | # Create a new tag for the current version and push it to the remote repository 118 | git tag "$current_version" 119 | git push origin "$current_version" 120 | else 121 | # If the version could not be retrieved, display an error message 122 | echo "Error: Could not retrieve the version." 123 | fi 124 | } 125 | 126 | local github_fetch_remote_tag() { 127 | git fetch --tags --force; 128 | } 129 | 130 | local psl_download() { 131 | python update-psl.py; 132 | } 133 | 134 | local bundle_init() { 135 | rm -rf .bundle; 136 | rm -rf Gemfile.lock; 137 | gem install bundler; 138 | bundle install; 139 | bundle exec fastlane add_plugin versioning; 140 | } 141 | 142 | local selected_option=$(printf "%s\n" "${option_list[@]}" | fzf --ansi --prompt="Select a job to execute > ") 143 | 144 | case "$selected_option" in 145 | fastlane*) fastlane_command $selected_option;; 146 | "Xcode - Initialize project") xcode_init;; 147 | "Xcode - Clean all build cache") xcode_clean;; 148 | "Carthage - Update all platforms") carthage_update;; 149 | "Cocoapods - Clean all cache") cocoapods_clean;; 150 | "Cocoapods - Trunk push") cocoapods_trunk_push;; 151 | "Github - Update tag") github_update_tag;; 152 | "Github - Fetch remote tag") github_fetch_remote_tag;; 153 | "Public Suffix List - Download latest data") psl_download;; 154 | *) echo "Invalid option $selected_option" && exit 1;; 155 | esac 156 | 157 | exit 0; --------------------------------------------------------------------------------