├── .github └── workflows │ ├── pr_title.yaml │ ├── scripts │ ├── install-flutter.bat │ ├── install-flutter.sh │ ├── install-tools.bat │ ├── install-tools.sh │ └── validate-formatting.sh │ └── validate.yaml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── all_lint_rules.yaml ├── analysis_options.yaml ├── melos.yaml └── packages ├── ansi_styles ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── example │ └── main.dart ├── lib │ ├── ansi_styles.dart │ ├── extension.dart │ └── src │ │ ├── supports_ansi.dart │ │ └── supports_ansi_io.dart ├── pubspec.yaml └── test │ └── ansi_styles_test.dart ├── ci ├── .gitignore ├── .pubignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── dart_test.yaml ├── example │ └── ci_example.dart ├── generator │ ├── generate_vendors.dart │ └── vendors.json ├── lib │ ├── ci.dart │ └── src │ │ ├── ci.dart │ │ └── vendor.g.dart ├── pubspec.yaml └── test │ └── ci_test.dart └── storagebox ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── dart_test.yaml ├── example └── storagebox_example.dart ├── lib ├── src │ ├── exception.dart │ ├── storagebox.dart │ ├── storagebox_base.dart │ ├── storagebox_js.dart │ └── storagebox_vm.dart └── storagebox.dart ├── pubspec.yaml └── test └── storagebox_test.dart /.github/workflows/pr_title.yaml: -------------------------------------------------------------------------------- 1 | name: 'PR Title is Conventional' 2 | on: 3 | pull_request_target: 4 | types: 5 | - opened 6 | - edited 7 | - synchronize 8 | 9 | jobs: 10 | main: 11 | name: Validate PR title 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: amannn/action-semantic-pull-request@v4.5.0 15 | env: 16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | -------------------------------------------------------------------------------- /.github/workflows/scripts/install-flutter.bat: -------------------------------------------------------------------------------- 1 | SET BRANCH=%1 2 | CD /D %systemdrive%%homepath% 3 | git clone https://github.com/flutter/flutter.git --depth 1 -b %BRANCH% _flutter 4 | 5 | ECHO "%systemdrive%%homepath%\\_flutter\\bin">> %GITHUB_PATH% 6 | ECHO "%systemdrive%%homepath%\\_flutter\\bin\\cache\\dart-sdk\\bin">> %GITHUB_PATH% 7 | ECHO "%systemdrive%%homepath%\\_flutter\\Pub\\Cache\\bin">> %GITHUB_PATH% 8 | ECHO "%LOCALAPPDATA%\\Pub\\Cache\\bin">> %GITHUB_PATH% 9 | -------------------------------------------------------------------------------- /.github/workflows/scripts/install-flutter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BRANCH=$1 4 | 5 | cd $HOME 6 | git clone https://github.com/flutter/flutter.git --depth 1 -b $BRANCH _flutter 7 | echo "$HOME/_flutter/bin" >> $GITHUB_PATH 8 | echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH 9 | echo "$HOME/_flutter/.pub-cache/bin" >> $GITHUB_PATH 10 | echo "$HOME/_flutter/bin/cache/dart-sdk/bin" >> $GITHUB_PATH -------------------------------------------------------------------------------- /.github/workflows/scripts/install-tools.bat: -------------------------------------------------------------------------------- 1 | CMD /K dart pub global activate melos 2 | melos bootstrap -------------------------------------------------------------------------------- /.github/workflows/scripts/install-tools.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dart pub global activate melos 4 | melos bootstrap 5 | -------------------------------------------------------------------------------- /.github/workflows/scripts/validate-formatting.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [[ $(git ls-files --modified) ]]; then 3 | echo "" 4 | echo "" 5 | echo "These files are not formatted correctly:" 6 | for f in $(git ls-files --modified); do 7 | echo "" 8 | echo "" 9 | echo "-----------------------------------------------------------------" 10 | echo "$f" 11 | echo "-----------------------------------------------------------------" 12 | echo "" 13 | git --no-pager diff --unified=0 --minimal $f 14 | echo "" 15 | echo "-----------------------------------------------------------------" 16 | echo "" 17 | echo "" 18 | done 19 | if [[ $GITHUB_WORKFLOW ]]; then 20 | git checkout . > /dev/null 2>&1 21 | fi 22 | echo "" 23 | echo "❌ Some files are incorrectly formatted, see above output." 24 | echo "" 25 | echo "To fix these locally, run: 'melos run format'." 26 | exit 1 27 | else 28 | echo "" 29 | echo "✅ All files are formatted correctly." 30 | fi 31 | -------------------------------------------------------------------------------- /.github/workflows/validate.yaml: -------------------------------------------------------------------------------- 1 | name: all_packages 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | analyze: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: subosito/flutter-action@v2 14 | with: 15 | channel: 'stable' 16 | - uses: bluefireteam/melos-action@v2 17 | - name: "Analyze" 18 | uses: invertase/github-action-dart-analyzer@v1 19 | with: 20 | fatal-infos: true 21 | fatal-warnings: true 22 | 23 | format: 24 | runs-on: ubuntu-latest 25 | timeout-minutes: 10 26 | steps: 27 | - uses: actions/checkout@v2 28 | - uses: subosito/flutter-action@v2 29 | with: 30 | channel: 'stable' 31 | - uses: bluefireteam/melos-action@v2 32 | - name: "Check formatting" 33 | run: melos run format-check 34 | 35 | test_linux: 36 | runs-on: ubuntu-latest 37 | timeout-minutes: 25 38 | steps: 39 | - uses: actions/checkout@v2 40 | - uses: subosito/flutter-action@v2 41 | with: 42 | channel: 'stable' 43 | - uses: bluefireteam/melos-action@v2 44 | - name: "Run Tests" 45 | run: melos run test --no-select 46 | 47 | test_macos: 48 | runs-on: macos-latest 49 | timeout-minutes: 25 50 | steps: 51 | - uses: actions/checkout@v2 52 | - uses: subosito/flutter-action@v2 53 | with: 54 | channel: 'stable' 55 | - uses: bluefireteam/melos-action@v2 56 | - name: "Run Tests" 57 | run: melos run test --no-select 58 | 59 | test_windows: 60 | runs-on: windows-latest 61 | timeout-minutes: 25 62 | steps: 63 | - uses: actions/checkout@v2 64 | - uses: subosito/flutter-action@v2 65 | with: 66 | channel: 'stable' 67 | - uses: bluefireteam/melos-action@v2 68 | - uses: actions/checkout@v2 69 | - name: "Run Tests" 70 | run: cmd /K melos run test --no-select 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .dart_tool/ 2 | .vscode 3 | .idea 4 | *.iml -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## 2022-04-28 7 | 8 | ### Changes 9 | 10 | --- 11 | 12 | Packages with breaking changes: 13 | 14 | - There are no breaking changes in this release. 15 | 16 | Packages with other changes: 17 | 18 | - [`storagebox` - `v0.1.0+3`](#storagebox---v0103) 19 | 20 | --- 21 | 22 | #### `storagebox` - `v0.1.0+3` 23 | 24 | - **FIX**: fix clearing storage (#4). ([bb512eec](https://github.com/invertase/dart-cli-utilities/commit/bb512eecf1f8ca9cad73e8f8b06cfd9edb4614f2)) 25 | 26 | 27 | ## 2022-04-27 28 | 29 | ### Changes 30 | 31 | --- 32 | 33 | Packages with breaking changes: 34 | 35 | - There are no breaking changes in this release. 36 | 37 | Packages with other changes: 38 | 39 | - [`storagebox` - `v0.1.0+2`](#storagebox---v0102) 40 | 41 | --- 42 | 43 | #### `storagebox` - `v0.1.0+2` 44 | 45 | - downgrade path to 1.8.0 46 | 47 | 48 | ## 2022-02-21 49 | 50 | ### Changes 51 | 52 | --- 53 | 54 | Packages with breaking changes: 55 | 56 | - There are no breaking changes in this release. 57 | 58 | Packages with other changes: 59 | 60 | - [`ansi_styles` - `v0.3.2+1`](#ansi_styles---v0321) 61 | 62 | --- 63 | 64 | #### `ansi_styles` - `v0.3.2+1` 65 | 66 | - **REFACTOR**: move extension implementation outside of ./src. ([b707dede](https://github.com/invertase/dart-cli-utilities/commit/b707dede95a4ec4cada1686cf947aa90ae09e4b8)) 67 | 68 | 69 | ## 2022-02-21 70 | 71 | ### Changes 72 | 73 | --- 74 | 75 | Packages with breaking changes: 76 | 77 | - There are no breaking changes in this release. 78 | 79 | Packages with other changes: 80 | 81 | - [`ansi_styles` - `v0.3.2`](#ansi_styles---v032) 82 | 83 | --- 84 | 85 | #### `ansi_styles` - `v0.3.2` 86 | 87 | - **REFACTOR**: update package homepage url to new repository. ([dc502ec1](https://github.com/invertase/dart-cli-utilities/commit/dc502ec1ae3b74f90cf1d43582026628ab1bfdda)) 88 | - **FEAT**: support styling via a Dart extension methods on String. ([13823280](https://github.com/invertase/dart-cli-utilities/commit/13823280123780df459a30f3dc5772ce500d9b40)) 89 | 90 | 91 | ## 2022-02-21 92 | 93 | ### Changes 94 | 95 | --- 96 | 97 | Packages with breaking changes: 98 | 99 | - There are no breaking changes in this release. 100 | 101 | Packages with other changes: 102 | 103 | - [`storagebox` - `v0.1.0+1`](#storagebox---v0101) 104 | 105 | --- 106 | 107 | #### `storagebox` - `v0.1.0+1` 108 | 109 | - **DOCS**: update readme. ([7d805aca](https://github.com/invertase/dart-cli-utilities/commit/7d805acae21f1594e98c34d3986e85ba452c1d65)) 110 | 111 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020 Invertase Limited 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

⚒️ Dart CLI Utilities

3 | A monorepo containing a collection of packages that provide useful functionality for building CLI applications in Dart. 4 |

5 | 6 | Melos 7 | docs.page 8 | 9 | Chat on Discord 10 | 11 | 12 | License 13 | 14 | --- 15 | 16 | ### Packages 17 | 18 | - [**🌈 AnsiStyles**](packages/ansi_styles) 19 | - Create colorful terminal output with ansi styled text in io environments. 20 | - [**☁️ CI**](packages/ci) 21 | - Detect whether you're running in a CI environment and retrieve information about the CI vendor. 22 | - [**📦 StorageBox**](packages/storagebox) 23 | - Easily store and persist configuration items for your CLI apps. 24 | 25 | 26 | --- 27 | 28 |

29 | 30 | 31 | 32 |

33 | Built and maintained by Invertase. 34 |

35 |

36 | -------------------------------------------------------------------------------- /all_lint_rules.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016-present Invertase Limited & Contributors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this library except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | linter: 18 | rules: 19 | - always_declare_return_types 20 | - always_put_control_body_on_new_line 21 | - always_put_required_named_parameters_first 22 | - always_require_non_null_named_parameters 23 | - always_specify_types 24 | - always_use_package_imports 25 | - annotate_overrides 26 | - avoid_annotating_with_dynamic 27 | - avoid_bool_literals_in_conditional_expressions 28 | - avoid_catches_without_on_clauses 29 | - avoid_catching_errors 30 | - avoid_classes_with_only_static_members 31 | - avoid_double_and_int_checks 32 | - avoid_dynamic_calls 33 | - avoid_empty_else 34 | - avoid_equals_and_hash_code_on_mutable_classes 35 | - avoid_escaping_inner_quotes 36 | - avoid_field_initializers_in_const_classes 37 | - avoid_function_literals_in_foreach_calls 38 | - avoid_implementing_value_types 39 | - avoid_init_to_null 40 | - avoid_js_rounded_ints 41 | - avoid_multiple_declarations_per_line 42 | - avoid_null_checks_in_equality_operators 43 | - avoid_positional_boolean_parameters 44 | - avoid_print 45 | - avoid_private_typedef_functions 46 | - avoid_redundant_argument_values 47 | - avoid_relative_lib_imports 48 | - avoid_renaming_method_parameters 49 | - avoid_return_types_on_setters 50 | - avoid_returning_null 51 | - avoid_returning_null_for_future 52 | - avoid_returning_null_for_void 53 | - avoid_returning_this 54 | - avoid_setters_without_getters 55 | - avoid_shadowing_type_parameters 56 | - avoid_single_cascade_in_expression_statements 57 | - avoid_slow_async_io 58 | - avoid_type_to_string 59 | - avoid_types_as_parameter_names 60 | - avoid_types_on_closure_parameters 61 | - avoid_unnecessary_containers 62 | - avoid_unused_constructor_parameters 63 | - avoid_void_async 64 | - avoid_web_libraries_in_flutter 65 | - await_only_futures 66 | - camel_case_extensions 67 | - camel_case_types 68 | - cancel_subscriptions 69 | - cascade_invocations 70 | - cast_nullable_to_non_nullable 71 | - close_sinks 72 | - comment_references 73 | - constant_identifier_names 74 | - control_flow_in_finally 75 | - curly_braces_in_flow_control_structures 76 | - deprecated_consistency 77 | - diagnostic_describe_all_properties 78 | - directives_ordering 79 | - do_not_use_environment 80 | - empty_catches 81 | - empty_constructor_bodies 82 | - empty_statements 83 | - exhaustive_cases 84 | - file_names 85 | - flutter_style_todos 86 | - hash_and_equals 87 | - implementation_imports 88 | - invariant_booleans 89 | - iterable_contains_unrelated_type 90 | - join_return_with_assignment 91 | - leading_newlines_in_multiline_strings 92 | - library_names 93 | - library_prefixes 94 | - library_private_types_in_public_api 95 | - lines_longer_than_80_chars 96 | - list_remove_unrelated_type 97 | - literal_only_boolean_expressions 98 | - missing_whitespace_between_adjacent_strings 99 | - no_adjacent_strings_in_list 100 | - no_default_cases 101 | - no_duplicate_case_values 102 | - no_logic_in_create_state 103 | - no_runtimeType_toString 104 | - non_constant_identifier_names 105 | - null_check_on_nullable_type_parameter 106 | - null_closures 107 | - omit_local_variable_types 108 | - one_member_abstracts 109 | - only_throw_errors 110 | - overridden_fields 111 | - package_api_docs 112 | - package_names 113 | - package_prefixed_library_names 114 | - parameter_assignments 115 | - prefer_adjacent_string_concatenation 116 | - prefer_asserts_in_initializer_lists 117 | - prefer_asserts_with_message 118 | - prefer_collection_literals 119 | - prefer_conditional_assignment 120 | - prefer_const_constructors 121 | - prefer_const_constructors_in_immutables 122 | - prefer_const_declarations 123 | - prefer_const_literals_to_create_immutables 124 | - prefer_constructors_over_static_methods 125 | - prefer_contains 126 | - prefer_double_quotes 127 | - prefer_equal_for_default_values 128 | - prefer_expression_function_bodies 129 | - prefer_final_fields 130 | - prefer_final_in_for_each 131 | - prefer_final_locals 132 | - prefer_for_elements_to_map_fromIterable 133 | - prefer_foreach 134 | - prefer_function_declarations_over_variables 135 | - prefer_generic_function_type_aliases 136 | - prefer_if_elements_to_conditional_expressions 137 | - prefer_if_null_operators 138 | - prefer_initializing_formals 139 | - prefer_inlined_adds 140 | - prefer_int_literals 141 | - prefer_interpolation_to_compose_strings 142 | - prefer_is_empty 143 | - prefer_is_not_empty 144 | - prefer_is_not_operator 145 | - prefer_iterable_whereType 146 | - prefer_mixin 147 | - prefer_null_aware_method_calls 148 | - prefer_null_aware_operators 149 | - prefer_relative_imports 150 | - prefer_single_quotes 151 | - prefer_spread_collections 152 | - prefer_typing_uninitialized_variables 153 | - prefer_void_to_null 154 | - provide_deprecation_message 155 | - public_member_api_docs 156 | - recursive_getters 157 | - require_trailing_commas 158 | - sized_box_for_whitespace 159 | - slash_for_doc_comments 160 | - sort_child_properties_last 161 | - sort_constructors_first 162 | - sort_pub_dependencies 163 | - sort_unnamed_constructors_first 164 | - test_types_in_equals 165 | - throw_in_finally 166 | - tighten_type_of_initializing_formals 167 | - type_annotate_public_apis 168 | - type_init_formals 169 | - unawaited_futures 170 | - unnecessary_await_in_return 171 | - unnecessary_brace_in_string_interps 172 | - unnecessary_const 173 | - unnecessary_final 174 | - unnecessary_getters_setters 175 | - unnecessary_lambdas 176 | - unnecessary_new 177 | - unnecessary_null_aware_assignments 178 | - unnecessary_null_checks 179 | - unnecessary_null_in_if_null_operators 180 | - unnecessary_nullable_for_final_variable_declarations 181 | - unnecessary_overrides 182 | - unnecessary_parenthesis 183 | - unnecessary_raw_strings 184 | - unnecessary_statements 185 | - unnecessary_string_escapes 186 | - unnecessary_string_interpolations 187 | - unnecessary_this 188 | - unrelated_type_equality_checks 189 | - unsafe_html 190 | - use_build_context_synchronously 191 | - use_full_hex_values_for_flutter_colors 192 | - use_function_type_syntax_for_parameters 193 | - use_if_null_to_convert_nulls_to_bools 194 | - use_is_even_rather_than_modulo 195 | - use_key_in_widget_constructors 196 | - use_late_for_private_fields_and_variables 197 | - use_named_constants 198 | - use_raw_strings 199 | - use_rethrow_when_possible 200 | - use_setters_to_change_properties 201 | - use_string_buffers 202 | - use_to_and_as_if_applicable 203 | - valid_regexps 204 | - void_checks -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016-present Invertase Limited & Contributors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this library except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | include: all_lint_rules.yaml 18 | analyzer: 19 | strong-mode: 20 | implicit-casts: false 21 | implicit-dynamic: false 22 | errors: 23 | # Otherwise cause the import of all_lint_rules to warn because of some rules conflicts. 24 | # We explicitly enabled even conflicting rules and are fixing the conflict 25 | # in this file 26 | included_file_warning: ignore 27 | 28 | linter: 29 | rules: 30 | # TODO(Salakar) re-enable documentation rule and fix issues. 31 | public_member_api_docs: false 32 | 33 | always_put_control_body_on_new_line: false 34 | comment_references: true 35 | prefer_constructors_over_static_methods: true 36 | prefer_final_fields: true 37 | omit_local_variable_types: true 38 | avoid_equals_and_hash_code_on_mutable_classes: false 39 | 40 | ############# 41 | # Conflicts with 'unecessary_final' 42 | prefer_final_locals: true 43 | 44 | cascade_invocations: false 45 | 46 | # Conflicts with `prefer_single_quotes` 47 | # Single quotes are easier to type and don't compromise on readability. 48 | prefer_double_quotes: false 49 | 50 | # Conflicts with `omit_local_variable_types` and other rules. 51 | # As per Dart guidelines, we want to avoid unnecessary types to make the code 52 | # more readable. 53 | # See https://dart.dev/guides/language/effective-dart/design#avoid-type-annotating-initialized-local-variables 54 | always_specify_types: false 55 | 56 | # Incompatible with `prefer_final_locals` 57 | # Having immutable local variables makes larger functions more predictible 58 | # so we will use `prefer_final_locals` instead. 59 | unnecessary_final: false 60 | 61 | # Not quite suitable for Flutter, which may have a `build` method with a single 62 | # return, but that return is still complex enough that a "body" is worth it. 63 | prefer_expression_function_bodies: false 64 | 65 | # Conflicts with the convention used by flutter, which puts `Key key` 66 | # and `@required Widget child` last. 67 | always_put_required_named_parameters_first: false 68 | 69 | # `as` is not that bad (especially with the upcoming non-nullable types). 70 | # Explicit exceptions is better than implicit exceptions. 71 | avoid_as: false 72 | 73 | # This project doesn't use Flutter-style todos 74 | flutter_style_todos: false 75 | 76 | # There are situations where we voluntarily want to catch everything, 77 | # especially as a library. 78 | avoid_catches_without_on_clauses: false 79 | 80 | # Boring as it sometimes force a line of 81 characters to be split in two. 81 | # As long as we try to respect that 80 characters limit, going slightly 82 | # above is fine. 83 | lines_longer_than_80_chars: false 84 | 85 | # Conflicts with disabling `implicit-dynamic` 86 | avoid_annotating_with_dynamic: false 87 | 88 | # conflicts with `prefer_relative_imports` 89 | always_use_package_imports: false 90 | 91 | # Disabled for now until NNBD as it otherwise conflicts with `missing_return` 92 | no_default_cases: false 93 | 94 | # False positive, null checks don't need a message 95 | prefer_asserts_with_message: false 96 | 97 | # Cumbersome with `context.select` 98 | avoid_types_on_closure_parameters: false 99 | 100 | # Too many false positive (builders) 101 | diagnostic_describe_all_properties: false 102 | 103 | # false positives (setter-like functions) 104 | avoid_positional_boolean_parameters: false 105 | 106 | # Does not apply to providers 107 | prefer_const_constructors_in_immutables: false -------------------------------------------------------------------------------- /melos.yaml: -------------------------------------------------------------------------------- 1 | name: dart_cli_utilities 2 | repository: https://github.com/invertase/dart-cli-utilities 3 | packages: 4 | - "packages/**" 5 | 6 | command: 7 | version: 8 | # Generate commit links in package changelogs. 9 | linkToCommits: true 10 | # Only allow versioning to happen on main branch. 11 | branch: main 12 | workspaceChangelog: true 13 | 14 | ide: 15 | intellij: false 16 | 17 | scripts: 18 | analyze: 19 | run: melos exec -c 1 -- "dart analyze . --fatal-infos" 20 | description: Run dart analyzer in a specific package. 21 | 22 | test: 23 | description: Run tests in a specific package. 24 | # TODO(Salakar) 'dart pub get' is necessary for the 'melos' package as we're using it on itself 25 | run: melos exec --concurrency=1 -- "dart pub get && dart pub run test --reporter expanded" 26 | select-package: 27 | dir-exists: 28 | - "test/" 29 | 30 | format: dart format -o write . 31 | 32 | format-check: 33 | run: melos exec dart format . --set-exit-if-changed 34 | description: Run `dart format` checks for all packages. 35 | 36 | -------------------------------------------------------------------------------- /packages/ansi_styles/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub. 2 | .dart_tool/ 3 | .packages 4 | 5 | # Conventional directory for build outputs. 6 | build/ 7 | 8 | # Omit committing pubspec.lock for library packages; see 9 | # https://dart.dev/guides/libraries/private-files#pubspeclock. 10 | pubspec.lock 11 | .vscode 12 | .idea 13 | *.iml -------------------------------------------------------------------------------- /packages/ansi_styles/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.3.2+1 2 | 3 | - **REFACTOR**: move extension implementation outside of ./src. ([b707dede](https://github.com/invertase/dart-cli-utilities/commit/b707dede95a4ec4cada1686cf947aa90ae09e4b8)) 4 | 5 | ## 0.3.2 6 | 7 | - **REFACTOR**: update package homepage url to new repository. ([dc502ec1](https://github.com/invertase/dart-cli-utilities/commit/dc502ec1ae3b74f90cf1d43582026628ab1bfdda)) 8 | - **FEAT**: support styling via a Dart extension methods on String. ([13823280](https://github.com/invertase/dart-cli-utilities/commit/13823280123780df459a30f3dc5772ce500d9b40)) 9 | 10 | ## 0.3.1 11 | 12 | - Graduate package to a stable release. See pre-releases prior to this version for changelog entries. 13 | 14 | ## 0.3.1-dev.1 15 | 16 | - **DOCS**: fix a few things and expand page for `melos.yaml` (#200). 17 | 18 | ## 0.3.1-dev.0 19 | 20 | - **FEAT**: added config validation and type-safe Dart API (#139) (#140). 21 | 22 | ## 0.3.0 23 | 24 | > Note: This release has breaking changes. 25 | 26 | - **BREAKING** **FEAT**: migrate ansi_styles to null-safety (#113). 27 | 28 | ## 0.2.0 29 | 30 | > Note: This release has breaking changes. 31 | 32 | - **BREAKING** **REFACTOR**: rework bootstrap behaviour (see #51 for more info). 33 | 34 | ## 0.1.1+1 35 | 36 | - **REFACTOR**: break out conventional_commit package. 37 | 38 | ## 0.1.1 39 | 40 | - **REFACTOR**: code cleanup. 41 | - **REFACTOR**: remove commited .iml files. 42 | - **FEAT**: semver & conventional commits (#10). 43 | 44 | -------------------------------------------------------------------------------- /packages/ansi_styles/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020 Invertase Limited 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /packages/ansi_styles/README.md: -------------------------------------------------------------------------------- 1 |

2 |

🌈 AnsiStyles

3 | Create colorful terminal output with ansi styled text in io environments. 4 |

5 | 6 | Melos 7 | docs.page 8 | 9 | Documentation • 10 | License 11 | 12 | --- 13 | 14 | ## Usage 15 | 16 | Import the package: 17 | 18 | ```dart 19 | import 'package:ansi_styles/ansi_styles.dart'; 20 | ``` 21 | 22 | Use the `AnsiStyle` export to create styled text by chaining properties. For example: 23 | 24 | ```dart 25 | void main() { 26 | print(AnsiStyles.red.underline('Underlined red text')); 27 | print(AnsiStyles.inverse.italic.green('Inverted italic green text')); 28 | print(AnsiStyles.cyan('Cyan text')); 29 | print(AnsiStyles.bgYellowBright.bold('Bold text with a yellow background')); 30 | print(AnsiStyles.bold.rgb(255,192,203)('Bold pink text')); 31 | print(AnsiStyles.strikethrough.bgRgb(255,165,0)('Strikethrough text with an orange background')); 32 | } 33 | ``` 34 | 35 | **Output preview**: 36 | 37 | ![ansi_styles_preview](https://static.invertase.io/assets/ansi_styles_example.png) 38 | 39 | To remove any ansi styling from text, call the `strip()` method: 40 | 41 | ```dart 42 | String styledText = AnsiStyles.red.underline('Underlined red text'); 43 | String cleanText = AnsiStyles.strip(styledText); 44 | ``` 45 | 46 | ### String Extension 47 | 48 | This package also provides a String Extension which can be imported: 49 | 50 | ```dart 51 | import 'package:ansi_styles/extension.dart'; 52 | ``` 53 | 54 | Styling methods are now available on Strings: 55 | 56 | ```dart 57 | void main() { 58 | print('hello'.bold.red); 59 | print('hello'.bold.red.underline.bgBlack); 60 | } 61 | ``` 62 | 63 | ## License 64 | 65 | - See [LICENSE](/LICENSE) 66 | 67 | --- 68 | 69 |

70 | 71 | 72 | 73 |

74 | Built and maintained by Invertase. 75 |

76 |

77 | -------------------------------------------------------------------------------- /packages/ansi_styles/example/main.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_print 2 | import 'package:ansi_styles/ansi_styles.dart'; 3 | import 'package:ansi_styles/extension.dart'; 4 | 5 | void main() { 6 | print(AnsiStyles.red.underline('Underlined red text')); 7 | print(AnsiStyles.inverse.italic.green('Inverted italic green text')); 8 | print(AnsiStyles.cyan('Cyan text')); 9 | print(AnsiStyles.bgYellowBright.bold('Bold text with a yellow background')); 10 | print(AnsiStyles.bold.rgb(255, 192, 203)('Bold pink text')); 11 | print( 12 | AnsiStyles.strikethrough 13 | .bgRgb(255, 165, 0)('Strikethrough text with an orange background'), 14 | ); 15 | // Using string extension 16 | print('hello'.bold.red); 17 | print('hello'.bold.red.underline.bgBlack); 18 | } 19 | -------------------------------------------------------------------------------- /packages/ansi_styles/lib/ansi_styles.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-present Invertase Limited & Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this library except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | import 'src/supports_ansi.dart' 19 | if (dart.library.io) 'src/supports_ansi_io.dart'; 20 | 21 | final RegExp _stripRegex = RegExp( 22 | [ 23 | r'[\u001B\u009B][[\]()#;?]*(?:(?:(?:[a-zA-Z\d]*(?:;[-a-zA-Z\d\/#&.:=?%@~_]*)*)?\u0007)', 24 | r'(?:(?:\d{1,4}(?:;\\d{0,4})*)?[\dA-PR-TZcf-ntqry=><~]))' 25 | ].join('|'), 26 | ); 27 | 28 | void _assertRGBValue(num value) { 29 | assert(value >= 0); 30 | assert(value <= 255); 31 | } 32 | 33 | num _getRGBColor({num r = 255, num g = 255, num b = 255}) { 34 | _assertRGBValue(r); 35 | _assertRGBValue(g); 36 | _assertRGBValue(b); 37 | return (((r.clamp(0, 255) / 255) * 5).toInt() * 36 + 38 | ((g.clamp(0, 255) / 255) * 5).toInt() * 6 + 39 | ((b.clamp(0, 255) / 255) * 5).toInt() + 40 | 16) 41 | .clamp(0, 256); 42 | } 43 | 44 | class _AnsiStyles { 45 | factory _AnsiStyles(List> styles) { 46 | return _AnsiStyles._(styles); 47 | } 48 | const _AnsiStyles._(this.styles); 49 | final List> styles; 50 | 51 | /// Removes any ANSI styling from any input. 52 | String strip(String input) { 53 | return input.replaceAll(_stripRegex, ''); 54 | } 55 | 56 | _AnsiStyles _cloneWithStyles(int openCode, int closeCode) { 57 | return _AnsiStyles( 58 | List.from(styles)..add(['\u001B[${openCode}m', '\u001B[${closeCode}m']), 59 | ); 60 | } 61 | 62 | // Modifiers. 63 | _AnsiStyles get reset => _cloneWithStyles(0, 0); 64 | _AnsiStyles get bold => _cloneWithStyles(1, 22); 65 | _AnsiStyles get dim => _cloneWithStyles(2, 22); 66 | _AnsiStyles get italic => _cloneWithStyles(3, 23); 67 | _AnsiStyles get underline => _cloneWithStyles(4, 24); 68 | _AnsiStyles get blink => _cloneWithStyles(5, 25); 69 | _AnsiStyles get inverse => _cloneWithStyles(7, 27); 70 | _AnsiStyles get hidden => _cloneWithStyles(8, 28); 71 | _AnsiStyles get strikethrough => _cloneWithStyles(9, 29); 72 | 73 | // Text colors. 74 | _AnsiStyles get black => _cloneWithStyles(30, 39); 75 | _AnsiStyles get red => _cloneWithStyles(31, 39); 76 | _AnsiStyles get green => _cloneWithStyles(32, 39); 77 | _AnsiStyles get yellow => _cloneWithStyles(33, 39); 78 | _AnsiStyles get blue => _cloneWithStyles(34, 39); 79 | _AnsiStyles get magenta => _cloneWithStyles(35, 39); 80 | _AnsiStyles get cyan => _cloneWithStyles(36, 39); 81 | _AnsiStyles get white => _cloneWithStyles(37, 39); 82 | _AnsiStyles get blackBright => _cloneWithStyles(90, 39); 83 | _AnsiStyles get redBright => _cloneWithStyles(91, 39); 84 | _AnsiStyles get greenBright => _cloneWithStyles(92, 39); 85 | _AnsiStyles get yellowBright => _cloneWithStyles(93, 39); 86 | _AnsiStyles get blueBright => _cloneWithStyles(94, 39); 87 | _AnsiStyles get magentaBright => _cloneWithStyles(95, 39); 88 | _AnsiStyles get cyanBright => _cloneWithStyles(96, 39); 89 | _AnsiStyles get whiteBright => _cloneWithStyles(97, 39); 90 | 91 | // Background colors. 92 | _AnsiStyles get bgBlack => _cloneWithStyles(40, 49); 93 | _AnsiStyles get bgRed => _cloneWithStyles(41, 49); 94 | _AnsiStyles get bgGreen => _cloneWithStyles(42, 49); 95 | _AnsiStyles get bgYellow => _cloneWithStyles(43, 49); 96 | _AnsiStyles get bgBlue => _cloneWithStyles(44, 49); 97 | _AnsiStyles get bgMagenta => _cloneWithStyles(45, 49); 98 | _AnsiStyles get bgCyan => _cloneWithStyles(46, 49); 99 | _AnsiStyles get bgWhite => _cloneWithStyles(47, 49); 100 | _AnsiStyles get bgBlackBright => _cloneWithStyles(100, 49); 101 | _AnsiStyles get bgRedBright => _cloneWithStyles(101, 49); 102 | _AnsiStyles get bgGreenBright => _cloneWithStyles(102, 49); 103 | _AnsiStyles get bgYellowBright => _cloneWithStyles(103, 49); 104 | _AnsiStyles get bgBlueBright => _cloneWithStyles(104, 49); 105 | _AnsiStyles get bgMagentaBright => _cloneWithStyles(105, 49); 106 | _AnsiStyles get bgCyanBright => _cloneWithStyles(106, 49); 107 | _AnsiStyles get bgWhiteBright => _cloneWithStyles(107, 49); 108 | 109 | // Aliases. 110 | _AnsiStyles get grey => blackBright; 111 | _AnsiStyles get bgGrey => bgBlackBright; 112 | _AnsiStyles get gray => blackBright; 113 | _AnsiStyles get bgGray => bgBlackBright; 114 | 115 | _AnsiStyles rgb(num? r, num? g, num? b) { 116 | final color = _getRGBColor(r: r ?? 255, g: g ?? 255, b: b ?? 255); 117 | return _AnsiStyles( 118 | List.from(styles)..add(['\x1B[38;5;${color}m', '\x1B[0m']), 119 | ); 120 | } 121 | 122 | _AnsiStyles bgRgb(num? r, num? g, num? b) { 123 | final color = _getRGBColor(r: r ?? 255, g: g ?? 255, b: b ?? 255); 124 | return _AnsiStyles( 125 | List.from(styles)..add(['\x1B[48;5;${color}m', '\x1B[0m']), 126 | ); 127 | } 128 | 129 | String get bullet => call(!ansiStylesDisabled ? '•' : '-'); 130 | 131 | String call(String? input) { 132 | if (input != null && styles.isNotEmpty && !ansiStylesDisabled) { 133 | var output = input; 134 | for (final style in styles) { 135 | output = '${style[0]}$output${style[1]}'; 136 | } 137 | return output; 138 | } 139 | 140 | return input ?? ''; 141 | } 142 | } 143 | 144 | /// The entry point to using ansi styling. 145 | /// 146 | /// Different styles can be chained successively, and once satisfied called: 147 | /// 148 | /// ```dart 149 | /// print(AnsiStyles.red.underline('Underlined red text')); 150 | /// print(AnsiStyles.inverse.italic.green('Inverted italic green text')); 151 | /// print(AnsiStyles.cyan('Cyan text')); 152 | /// print(AnsiStyles.bgYellowBright.bold('Text bold with a yellow background')); 153 | /// ``` 154 | // ignore: constant_identifier_names 155 | const AnsiStyles = _AnsiStyles._([]); 156 | 157 | /// Flag used to enabled/disable styling support. 158 | /// 159 | /// This is mainly used for environments where the raw output is required but is 160 | /// not supported (e.g. testing). 161 | bool ansiStylesDisabled = !supportsAnsiColor; 162 | -------------------------------------------------------------------------------- /packages/ansi_styles/lib/extension.dart: -------------------------------------------------------------------------------- 1 | import 'ansi_styles.dart'; 2 | 3 | extension AnsiStylesStringExtension on String { 4 | String get reset => AnsiStyles.reset(this); 5 | String get bold => AnsiStyles.bold(this); 6 | String get dim => AnsiStyles.dim(this); 7 | String get italic => AnsiStyles.italic(this); 8 | String get underline => AnsiStyles.underline(this); 9 | String get blink => AnsiStyles.blink(this); 10 | String get inverse => AnsiStyles.inverse(this); 11 | String get hidden => AnsiStyles.hidden(this); 12 | String get strikethrough => AnsiStyles.strikethrough(this); 13 | String get black => AnsiStyles.black(this); 14 | String get red => AnsiStyles.red(this); 15 | String get green => AnsiStyles.green(this); 16 | String get yellow => AnsiStyles.yellow(this); 17 | String get blue => AnsiStyles.blue(this); 18 | String get magenta => AnsiStyles.magenta(this); 19 | String get cyan => AnsiStyles.cyan(this); 20 | String get white => AnsiStyles.white(this); 21 | String get blackBright => AnsiStyles.blackBright(this); 22 | String get redBright => AnsiStyles.redBright(this); 23 | String get greenBright => AnsiStyles.greenBright(this); 24 | String get yellowBright => AnsiStyles.yellowBright(this); 25 | String get blueBright => AnsiStyles.blueBright(this); 26 | String get magentaBright => AnsiStyles.magentaBright(this); 27 | String get cyanBright => AnsiStyles.cyanBright(this); 28 | String get whiteBright => AnsiStyles.whiteBright(this); 29 | String get bgBlack => AnsiStyles.bgBlack(this); 30 | String get bgRed => AnsiStyles.bgRed(this); 31 | String get bgGreen => AnsiStyles.bgGreen(this); 32 | String get bgYellow => AnsiStyles.bgYellow(this); 33 | String get bgBlue => AnsiStyles.bgBlue(this); 34 | String get bgMagenta => AnsiStyles.bgMagenta(this); 35 | String get bgCyan => AnsiStyles.bgCyan(this); 36 | String get bgWhite => AnsiStyles.bgWhite(this); 37 | String get bgBlackBright => AnsiStyles.bgBlackBright(this); 38 | String get bgRedBright => AnsiStyles.bgRedBright(this); 39 | String get bgGreenBright => AnsiStyles.bgGreenBright(this); 40 | String get bgYellowBright => AnsiStyles.bgYellowBright(this); 41 | String get bgBlueBright => AnsiStyles.bgBlueBright(this); 42 | String get bgMagentaBright => AnsiStyles.bgMagentaBright(this); 43 | String get bgCyanBright => AnsiStyles.bgCyanBright(this); 44 | String get bgWhiteBright => AnsiStyles.bgWhiteBright(this); 45 | String get grey => AnsiStyles.grey(this); 46 | String get bgGrey => AnsiStyles.bgGrey(this); 47 | String get gray => AnsiStyles.gray(this); 48 | String get bgGray => AnsiStyles.bgGray(this); 49 | String get strip => AnsiStyles.strip(this); 50 | String rgb(num? r, num? g, num? b) => AnsiStyles.rgb(r, g, b).call(this); 51 | String bgRgb(num? r, num? g, num? b) => AnsiStyles.bgRgb(r, g, b).call(this); 52 | } 53 | -------------------------------------------------------------------------------- /packages/ansi_styles/lib/src/supports_ansi.dart: -------------------------------------------------------------------------------- 1 | /// Whether the current environment supports styling via ansi escapes. 2 | bool get supportsAnsiColor => true; 3 | -------------------------------------------------------------------------------- /packages/ansi_styles/lib/src/supports_ansi_io.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io' as io; 2 | 3 | /// Whether the current environment supports styling via ansi escapes. 4 | bool get supportsAnsiColor => io.stdout.supportsAnsiEscapes; 5 | -------------------------------------------------------------------------------- /packages/ansi_styles/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ansi_styles 2 | description: ANSI escape codes for styling strings in the terminal. 3 | version: 0.3.2+1 4 | homepage: https://github.com/invertase/dart-cli-utilities/tree/main/packages/ansi_styles 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | 9 | dev_dependencies: 10 | test: ^1.17.5 11 | -------------------------------------------------------------------------------- /packages/ansi_styles/test/ansi_styles_test.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-present Invertase Limited & Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this library except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | import 'package:ansi_styles/ansi_styles.dart'; 19 | import 'package:test/test.dart'; 20 | 21 | String getOutput(String input, int open, int close) { 22 | return '\u001B[${open}m$input\u001B[${close}m'; 23 | } 24 | 25 | void main() { 26 | setUpAll(() { 27 | ansiStylesDisabled = false; 28 | }); 29 | 30 | group('Colors', () { 31 | test('black', () { 32 | expect(AnsiStyles.black('foo'), equals(getOutput('foo', 30, 39))); 33 | }); 34 | test('red', () { 35 | expect(AnsiStyles.red('foo'), equals(getOutput('foo', 31, 39))); 36 | }); 37 | test('green', () { 38 | expect(AnsiStyles.green('foo'), equals(getOutput('foo', 32, 39))); 39 | }); 40 | test('yellow', () { 41 | expect(AnsiStyles.yellow('foo'), equals(getOutput('foo', 33, 39))); 42 | }); 43 | test('blue', () { 44 | expect(AnsiStyles.blue('foo'), equals(getOutput('foo', 34, 39))); 45 | }); 46 | test('magenta', () { 47 | expect(AnsiStyles.magenta('foo'), equals(getOutput('foo', 35, 39))); 48 | }); 49 | test('cyan', () { 50 | expect(AnsiStyles.cyan('foo'), equals(getOutput('foo', 36, 39))); 51 | }); 52 | test('white', () { 53 | expect(AnsiStyles.white('foo'), equals(getOutput('foo', 37, 39))); 54 | }); 55 | test('blackBright', () { 56 | expect(AnsiStyles.blackBright('foo'), equals(getOutput('foo', 90, 39))); 57 | expect(AnsiStyles.grey('foo'), equals(getOutput('foo', 90, 39))); 58 | expect(AnsiStyles.gray('foo'), equals(getOutput('foo', 90, 39))); 59 | }); 60 | test('redBright', () { 61 | expect(AnsiStyles.redBright('foo'), equals(getOutput('foo', 91, 39))); 62 | }); 63 | test('greenBright', () { 64 | expect(AnsiStyles.greenBright('foo'), equals(getOutput('foo', 92, 39))); 65 | }); 66 | test('yellowBright', () { 67 | expect(AnsiStyles.yellowBright('foo'), equals(getOutput('foo', 93, 39))); 68 | }); 69 | test('blueBright', () { 70 | expect(AnsiStyles.blueBright('foo'), equals(getOutput('foo', 94, 39))); 71 | }); 72 | test('magentaBright', () { 73 | expect(AnsiStyles.magentaBright('foo'), equals(getOutput('foo', 95, 39))); 74 | }); 75 | 76 | test('whiteBright', () { 77 | expect(AnsiStyles.whiteBright('foo'), equals(getOutput('foo', 97, 39))); 78 | }); 79 | 80 | test('bgBlack', () { 81 | expect(AnsiStyles.bgBlack('foo'), equals(getOutput('foo', 40, 49))); 82 | }); 83 | test('bgRed', () { 84 | expect(AnsiStyles.bgRed('foo'), equals(getOutput('foo', 41, 49))); 85 | }); 86 | test('bgGreen', () { 87 | expect(AnsiStyles.bgGreen('foo'), equals(getOutput('foo', 42, 49))); 88 | }); 89 | test('bgYellow', () { 90 | expect(AnsiStyles.bgYellow('foo'), equals(getOutput('foo', 43, 49))); 91 | }); 92 | test('bgBlue', () { 93 | expect(AnsiStyles.bgBlue('foo'), equals(getOutput('foo', 44, 49))); 94 | }); 95 | test('bgMagenta', () { 96 | expect(AnsiStyles.bgMagenta('foo'), equals(getOutput('foo', 45, 49))); 97 | }); 98 | test('bgCyan', () { 99 | expect(AnsiStyles.bgCyan('foo'), equals(getOutput('foo', 46, 49))); 100 | }); 101 | test('bgWhite', () { 102 | expect(AnsiStyles.bgWhite('foo'), equals(getOutput('foo', 47, 49))); 103 | }); 104 | test('bgBlackBright', () { 105 | expect( 106 | AnsiStyles.bgBlackBright('foo'), 107 | equals(getOutput('foo', 100, 49)), 108 | ); 109 | expect(AnsiStyles.bgGrey('foo'), equals(getOutput('foo', 100, 49))); 110 | expect(AnsiStyles.bgGray('foo'), equals(getOutput('foo', 100, 49))); 111 | }); 112 | test('bgRedBright', () { 113 | expect(AnsiStyles.bgRedBright('foo'), equals(getOutput('foo', 101, 49))); 114 | }); 115 | test('bgGreenBright', () { 116 | expect( 117 | AnsiStyles.bgGreenBright('foo'), 118 | equals(getOutput('foo', 102, 49)), 119 | ); 120 | }); 121 | test('bgYellowBright', () { 122 | expect( 123 | AnsiStyles.bgYellowBright('foo'), 124 | equals(getOutput('foo', 103, 49)), 125 | ); 126 | }); 127 | test('bgBlueBright', () { 128 | expect(AnsiStyles.bgBlueBright('foo'), equals(getOutput('foo', 104, 49))); 129 | }); 130 | test('bgMagentaBright', () { 131 | expect( 132 | AnsiStyles.bgMagentaBright('foo'), 133 | equals(getOutput('foo', 105, 49)), 134 | ); 135 | }); 136 | test('bgCyanBright', () { 137 | expect(AnsiStyles.bgCyanBright('foo'), equals(getOutput('foo', 106, 49))); 138 | }); 139 | test('bgWhiteBright', () { 140 | expect( 141 | AnsiStyles.bgWhiteBright('foo'), 142 | equals(getOutput('foo', 107, 49)), 143 | ); 144 | }); 145 | }); 146 | 147 | group('Modifiers', () { 148 | test('reset', () { 149 | expect(AnsiStyles.reset('foo'), equals(getOutput('foo', 0, 0))); 150 | }); 151 | test('bold', () { 152 | expect(AnsiStyles.bold('foo'), equals(getOutput('foo', 1, 22))); 153 | }); 154 | test('dim', () { 155 | expect(AnsiStyles.dim('foo'), equals(getOutput('foo', 2, 22))); 156 | }); 157 | test('italic', () { 158 | expect(AnsiStyles.italic('foo'), equals(getOutput('foo', 3, 23))); 159 | }); 160 | test('underline', () { 161 | expect(AnsiStyles.underline('foo'), equals(getOutput('foo', 4, 24))); 162 | }); 163 | test('inverse', () { 164 | expect(AnsiStyles.inverse('foo'), equals(getOutput('foo', 7, 27))); 165 | }); 166 | test('inverse', () { 167 | expect(AnsiStyles.hidden('foo'), equals(getOutput('foo', 8, 28))); 168 | }); 169 | test('strikethrough', () { 170 | expect(AnsiStyles.strikethrough('foo'), equals(getOutput('foo', 9, 29))); 171 | }); 172 | }); 173 | 174 | test('bullet', () { 175 | expect( 176 | AnsiStyles.bgWhiteBright.bullet, 177 | equals(getOutput(AnsiStyles.bullet, 107, 49)), 178 | ); 179 | }); 180 | test('strip', () { 181 | expect(AnsiStyles.bgWhiteBright.underline.strip('foo'), equals('foo')); 182 | }); 183 | 184 | test('chaining', () { 185 | expect( 186 | AnsiStyles.red.underline('foo'), 187 | equals(getOutput(getOutput('foo', 31, 39), 4, 24)), 188 | ); 189 | }); 190 | } 191 | -------------------------------------------------------------------------------- /packages/ci/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub. 2 | .dart_tool/ 3 | .packages 4 | 5 | # Conventional directory for build outputs. 6 | build/ 7 | 8 | # Omit committing pubspec.lock for library packages; see 9 | # https://dart.dev/guides/libraries/private-files#pubspeclock. 10 | pubspec.lock 11 | .vscode 12 | .idea 13 | *.iml -------------------------------------------------------------------------------- /packages/ci/.pubignore: -------------------------------------------------------------------------------- 1 | generator -------------------------------------------------------------------------------- /packages/ci/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0 2 | 3 | - Initial version. 4 | -------------------------------------------------------------------------------- /packages/ci/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 Invertase Limited 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /packages/ci/README.md: -------------------------------------------------------------------------------- 1 |

2 |

☁️ CI

3 | Detect whether you're running in a CI environment and retrieve information about the CI vendor. 4 |

5 | 6 | Melos 7 | docs.page 8 | 9 | Documentation • 10 | License 11 | 12 | --- 13 | 14 | ### About 15 | 16 | **Example:** 17 | 18 | ```dart 19 | import 'package:ci/ci.dart' as ci; 20 | 21 | Future main() async { 22 | print(ci.isCI); 23 | print(ci.isPullRequest); 24 | print(ci.currentVendor); 25 | print(ci.currentVendor?.name); 26 | print(ci.currentVendor?.isPullRequest); 27 | print(ci.Vendor.IS_GITHUB_ACTIONS); 28 | } 29 | ``` 30 | 31 | #### Adding support for a new CI vendor 32 | 33 | The default CI vendors list is sourced from [watson/ci-info](https://github.com/watson/ci-info/blob/master/vendors.json), with an additional local [`vendors.json`](tools/vendors.json) file that allows adding new vendors or overriding vendors from the default CI vendors list. 34 | 35 | In most cases, you should make changes to the local [`vendors.json`](tools/vendors.json) file and send a PR to add in support. Run `dart generator/generate_vendors.dart` before submitting your PR to update the generated `vendor.g.dart` file. 36 | 37 | --- 38 | 39 |

40 | 41 | 42 | 43 |

44 | Built and maintained by Invertase. 45 |

46 |

47 | -------------------------------------------------------------------------------- /packages/ci/dart_test.yaml: -------------------------------------------------------------------------------- 1 | platforms: 2 | - vm 3 | -------------------------------------------------------------------------------- /packages/ci/example/ci_example.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_print 2 | 3 | /* 4 | * Copyright (c) 2020-present Invertase Limited & Contributors 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this library except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | import 'package:ci/ci.dart' as ci; 21 | 22 | Future main() async { 23 | print(ci.isCI); 24 | print(ci.isPullRequest); 25 | print(ci.currentVendor); 26 | print(ci.currentVendor?.name); 27 | print(ci.currentVendor?.isPullRequest); 28 | print(ci.Vendor.IS_GITHUB_ACTIONS); 29 | } 30 | -------------------------------------------------------------------------------- /packages/ci/generator/generate_vendors.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_print 2 | 3 | /* 4 | * Copyright (c) 2020-present Invertase Limited & Contributors 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this library except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | import 'dart:convert'; 20 | import 'dart:io'; 21 | 22 | import 'package:http/http.dart' as http; 23 | 24 | Future>> getSharedVendorsJson() async { 25 | final response = await http.get( 26 | Uri.parse( 27 | 'https://github.com/watson/ci-info/blob/master/vendors.json?raw=true', 28 | ), 29 | ); 30 | 31 | return List.from(jsonDecode(response.body) as List); 32 | } 33 | 34 | Future>> getLocalVendorsJson() async { 35 | final jsonString = await File('tools/vendors.json').readAsString(); 36 | return List.from(jsonDecode(jsonString) as List); 37 | } 38 | 39 | Future>> getAllVendors() async { 40 | final sharedVendors = await getSharedVendorsJson(); 41 | final localVendors = await getLocalVendorsJson(); 42 | final allVendors = List>.from(sharedVendors); 43 | allVendors.retainWhere( 44 | (sharedVendor) => 45 | localVendors.indexWhere( 46 | (localVendor) => localVendor['name'] == sharedVendor['name'], 47 | ) == 48 | -1, 49 | ); 50 | allVendors.addAll(localVendors); 51 | allVendors 52 | .sort((a, b) => (a['name']! as String).compareTo(b['name']! as String)); 53 | return allVendors; 54 | } 55 | 56 | void _writeGeneratedHead(StringBuffer buffer) { 57 | buffer.writeln('// GENERATED CODE - DO NOT MODIFY BY HAND'); 58 | buffer.writeln('// GENERATED BY CI PACKAGE'); 59 | buffer.writeln('// ignore_for_file: type=lint'); 60 | buffer.writeln("import 'dart:io';"); 61 | } 62 | 63 | void _writeGeneratedVendorStaticGetter( 64 | StringBuffer buffer, 65 | Map vendor, 66 | ) { 67 | buffer.writeln( 68 | ' /// Returns true if ${vendor['name']} is the current CI vendor.', 69 | ); 70 | buffer.writeln(' static bool get IS_${vendor['constant']} {'); 71 | buffer.write(' return '); 72 | final env = vendor['env']; 73 | if (env is String) { 74 | buffer.write("Platform.environment.containsKey('$env')"); 75 | } else if (env is Map) { 76 | final entries = []; 77 | for (final entry in env.entries) { 78 | entries.add( 79 | "Platform.environment['${entry.key}'] == '${entry.value}'", 80 | ); 81 | } 82 | buffer.write(entries.join(' && ')); 83 | } else if (env is List) { 84 | buffer.write( 85 | env 86 | .map((dynamic e) => 'Platform.environment.containsKey("$e")') 87 | .join(' && '), 88 | ); 89 | } 90 | 91 | buffer.writeln(';'); 92 | buffer.writeln(' }'); 93 | buffer.writeln(); 94 | } 95 | 96 | void _writeGeneratedVendorClass( 97 | StringBuffer buffer, 98 | List> vendors, 99 | ) { 100 | buffer.writeAll( 101 | [ 102 | 'class Vendor {', 103 | ' Vendor._(this.name, this.isPullRequest);', 104 | '', 105 | ' /// The name of the CI vendor.', 106 | ' final String name;', 107 | '', 108 | ' /// Whether this CI run is for a Pull Request.', 109 | ' final bool isPullRequest;', 110 | '', 111 | '', 112 | ], 113 | '\n', 114 | ); 115 | for (final vendor in vendors) { 116 | _writeGeneratedVendorStaticGetter(buffer, vendor); 117 | } 118 | _writeGeneratedVendorClassCurrentVendorInstance(buffer, vendors); 119 | buffer.writeln('}'); 120 | } 121 | 122 | void _writeGeneratedVendorClassCurrentVendorInstance( 123 | StringBuffer buffer, 124 | List> vendors, 125 | ) { 126 | buffer.writeln( 127 | ' /// Returns the current CI [Vendor] or [null] if no CI vendor detected (e.g. not running on CI).', 128 | ); 129 | buffer.writeln(' static Vendor? get current {'); 130 | for (final vendor in vendors) { 131 | buffer.writeln(' if (IS_${vendor['constant']}) {'); 132 | buffer.write(" return Vendor._('${vendor['name']}', "); 133 | final pr = vendor['pr']; 134 | if (pr == null) { 135 | buffer.write('false'); 136 | } else if (pr is String) { 137 | buffer.write("Platform.environment.containsKey('$pr')"); 138 | } else if (pr is Map) { 139 | if (pr['any'] != null && pr['any'] is List) { 140 | buffer.write( 141 | (pr['any'] as List) 142 | .map( 143 | (dynamic e) => 'Platform.environment.containsKey("$e")', 144 | ) 145 | .join(' || '), 146 | ); 147 | } else if (pr['env'] != null && pr['ne'] != null) { 148 | buffer.write("Platform.environment['${pr['env']}'] != '${pr['ne']}'"); 149 | } else { 150 | buffer.write( 151 | (pr.entries) 152 | .map( 153 | (MapEntry e) => 154 | 'Platform.environment["${e.key}"] == "${e.value}"', 155 | ) 156 | .join(' && '), 157 | ); 158 | } 159 | } 160 | buffer.writeln(',);'); 161 | buffer.writeln(' }'); 162 | buffer.writeln(); 163 | } 164 | buffer.writeln(' return null;'); 165 | buffer.writeln(' }'); 166 | } 167 | 168 | Future generateVendorsDart(List> vendors) async { 169 | final file = File('lib/src/vendor.g.dart'); 170 | final buffer = StringBuffer(); 171 | _writeGeneratedHead(buffer); 172 | _writeGeneratedVendorClass(buffer, vendors); 173 | await file.writeAsString(buffer.toString()); 174 | await Process.run('dart', [ 175 | 'format', 176 | file.path, 177 | ]); 178 | } 179 | 180 | Future main() async { 181 | final vendors = await getAllVendors(); 182 | await generateVendorsDart(vendors); 183 | } 184 | -------------------------------------------------------------------------------- /packages/ci/generator/vendors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Codemagic", 4 | "constant": "CODEMAGIC", 5 | "env": "FCI_BUILD_ID", 6 | "pr": { 7 | "env": "FCI_PULL_REQUEST", 8 | "ne": "false" 9 | } 10 | } 11 | ] 12 | -------------------------------------------------------------------------------- /packages/ci/lib/ci.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-present Invertase Limited & Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this library except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | export 'src/ci.dart'; 19 | export 'src/vendor.g.dart'; 20 | -------------------------------------------------------------------------------- /packages/ci/lib/src/ci.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-present Invertase Limited & Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this library except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | import 'dart:io'; 19 | 20 | import 'vendor.g.dart'; 21 | 22 | /// Whether the current process is running in a CI environment. 23 | bool get isCI { 24 | return Platform.environment.containsKey('CI') || 25 | Platform.environment.containsKey('CONTINUOUS_INTEGRATION') || 26 | Platform.environment.containsKey('BUILD_NUMBER') || 27 | Vendor.current != null; 28 | } 29 | 30 | /// Whether the current process is running in a CI and is for a Pull Request. 31 | bool get isPullRequest { 32 | return Vendor.current?.isPullRequest ?? false; 33 | } 34 | 35 | /// The current CI [Vendor] or null if no CI vendor detected (e.g. not running on CI). 36 | Vendor? get currentVendor { 37 | return Vendor.current; 38 | } 39 | -------------------------------------------------------------------------------- /packages/ci/lib/src/vendor.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | // GENERATED BY CI PACKAGE 3 | // ignore_for_file: type=lint 4 | import 'dart:io'; 5 | 6 | class Vendor { 7 | Vendor._(this.name, this.isPullRequest); 8 | 9 | /// The name of the CI vendor. 10 | final String name; 11 | 12 | /// Whether this CI run is for a Pull Request. 13 | final bool isPullRequest; 14 | 15 | /// Returns true if AWS CodeBuild is the current CI vendor. 16 | static bool get IS_CODEBUILD { 17 | return Platform.environment.containsKey('CODEBUILD_BUILD_ARN'); 18 | } 19 | 20 | /// Returns true if AppVeyor is the current CI vendor. 21 | static bool get IS_APPVEYOR { 22 | return Platform.environment.containsKey('APPVEYOR'); 23 | } 24 | 25 | /// Returns true if Appcircle is the current CI vendor. 26 | static bool get IS_APPCIRCLE { 27 | return Platform.environment.containsKey('AC_APPCIRCLE'); 28 | } 29 | 30 | /// Returns true if Azure Pipelines is the current CI vendor. 31 | static bool get IS_AZURE_PIPELINES { 32 | return Platform.environment 33 | .containsKey('SYSTEM_TEAMFOUNDATIONCOLLECTIONURI'); 34 | } 35 | 36 | /// Returns true if Bamboo is the current CI vendor. 37 | static bool get IS_BAMBOO { 38 | return Platform.environment.containsKey('bamboo_planKey'); 39 | } 40 | 41 | /// Returns true if Bitbucket Pipelines is the current CI vendor. 42 | static bool get IS_BITBUCKET { 43 | return Platform.environment.containsKey('BITBUCKET_COMMIT'); 44 | } 45 | 46 | /// Returns true if Bitrise is the current CI vendor. 47 | static bool get IS_BITRISE { 48 | return Platform.environment.containsKey('BITRISE_IO'); 49 | } 50 | 51 | /// Returns true if Buddy is the current CI vendor. 52 | static bool get IS_BUDDY { 53 | return Platform.environment.containsKey('BUDDY_WORKSPACE_ID'); 54 | } 55 | 56 | /// Returns true if Buildkite is the current CI vendor. 57 | static bool get IS_BUILDKITE { 58 | return Platform.environment.containsKey('BUILDKITE'); 59 | } 60 | 61 | /// Returns true if CircleCI is the current CI vendor. 62 | static bool get IS_CIRCLE { 63 | return Platform.environment.containsKey('CIRCLECI'); 64 | } 65 | 66 | /// Returns true if Cirrus CI is the current CI vendor. 67 | static bool get IS_CIRRUS { 68 | return Platform.environment.containsKey('CIRRUS_CI'); 69 | } 70 | 71 | /// Returns true if Codefresh is the current CI vendor. 72 | static bool get IS_CODEFRESH { 73 | return Platform.environment.containsKey('CF_BUILD_ID'); 74 | } 75 | 76 | /// Returns true if Codemagic is the current CI vendor. 77 | static bool get IS_CODEMAGIC { 78 | return Platform.environment.containsKey('FCI_BUILD_ID'); 79 | } 80 | 81 | /// Returns true if Codeship is the current CI vendor. 82 | static bool get IS_CODESHIP { 83 | return Platform.environment['CI_NAME'] == 'codeship'; 84 | } 85 | 86 | /// Returns true if Drone is the current CI vendor. 87 | static bool get IS_DRONE { 88 | return Platform.environment.containsKey('DRONE'); 89 | } 90 | 91 | /// Returns true if Expo Application Services is the current CI vendor. 92 | static bool get IS_EAS { 93 | return Platform.environment.containsKey('EAS_BUILD'); 94 | } 95 | 96 | /// Returns true if GitHub Actions is the current CI vendor. 97 | static bool get IS_GITHUB_ACTIONS { 98 | return Platform.environment.containsKey('GITHUB_ACTIONS'); 99 | } 100 | 101 | /// Returns true if GitLab CI is the current CI vendor. 102 | static bool get IS_GITLAB { 103 | return Platform.environment.containsKey('GITLAB_CI'); 104 | } 105 | 106 | /// Returns true if GoCD is the current CI vendor. 107 | static bool get IS_GOCD { 108 | return Platform.environment.containsKey('GO_PIPELINE_LABEL'); 109 | } 110 | 111 | /// Returns true if Hudson is the current CI vendor. 112 | static bool get IS_HUDSON { 113 | return Platform.environment.containsKey('HUDSON_URL'); 114 | } 115 | 116 | /// Returns true if Jenkins is the current CI vendor. 117 | static bool get IS_JENKINS { 118 | return Platform.environment.containsKey("JENKINS_URL") && 119 | Platform.environment.containsKey("BUILD_ID"); 120 | } 121 | 122 | /// Returns true if LayerCI is the current CI vendor. 123 | static bool get IS_LAYERCI { 124 | return Platform.environment.containsKey('LAYERCI'); 125 | } 126 | 127 | /// Returns true if Magnum CI is the current CI vendor. 128 | static bool get IS_MAGNUM { 129 | return Platform.environment.containsKey('MAGNUM'); 130 | } 131 | 132 | /// Returns true if Netlify CI is the current CI vendor. 133 | static bool get IS_NETLIFY { 134 | return Platform.environment.containsKey('NETLIFY'); 135 | } 136 | 137 | /// Returns true if Nevercode is the current CI vendor. 138 | static bool get IS_NEVERCODE { 139 | return Platform.environment.containsKey('NEVERCODE'); 140 | } 141 | 142 | /// Returns true if Render is the current CI vendor. 143 | static bool get IS_RENDER { 144 | return Platform.environment.containsKey('RENDER'); 145 | } 146 | 147 | /// Returns true if Sail CI is the current CI vendor. 148 | static bool get IS_SAIL { 149 | return Platform.environment.containsKey('SAILCI'); 150 | } 151 | 152 | /// Returns true if Screwdriver is the current CI vendor. 153 | static bool get IS_SCREWDRIVER { 154 | return Platform.environment.containsKey('SCREWDRIVER'); 155 | } 156 | 157 | /// Returns true if Semaphore is the current CI vendor. 158 | static bool get IS_SEMAPHORE { 159 | return Platform.environment.containsKey('SEMAPHORE'); 160 | } 161 | 162 | /// Returns true if Shippable is the current CI vendor. 163 | static bool get IS_SHIPPABLE { 164 | return Platform.environment.containsKey('SHIPPABLE'); 165 | } 166 | 167 | /// Returns true if Solano CI is the current CI vendor. 168 | static bool get IS_SOLANO { 169 | return Platform.environment.containsKey('TDDIUM'); 170 | } 171 | 172 | /// Returns true if Strider CD is the current CI vendor. 173 | static bool get IS_STRIDER { 174 | return Platform.environment.containsKey('STRIDER'); 175 | } 176 | 177 | /// Returns true if TaskCluster is the current CI vendor. 178 | static bool get IS_TASKCLUSTER { 179 | return Platform.environment.containsKey("TASK_ID") && 180 | Platform.environment.containsKey("RUN_ID"); 181 | } 182 | 183 | /// Returns true if TeamCity is the current CI vendor. 184 | static bool get IS_TEAMCITY { 185 | return Platform.environment.containsKey('TEAMCITY_VERSION'); 186 | } 187 | 188 | /// Returns true if Travis CI is the current CI vendor. 189 | static bool get IS_TRAVIS { 190 | return Platform.environment.containsKey('TRAVIS'); 191 | } 192 | 193 | /// Returns true if Vercel is the current CI vendor. 194 | static bool get IS_VERCEL { 195 | return Platform.environment.containsKey('NOW_BUILDER'); 196 | } 197 | 198 | /// Returns true if Visual Studio App Center is the current CI vendor. 199 | static bool get IS_APPCENTER { 200 | return Platform.environment.containsKey('APPCENTER_BUILD_ID'); 201 | } 202 | 203 | /// Returns true if dsari is the current CI vendor. 204 | static bool get IS_DSARI { 205 | return Platform.environment.containsKey('DSARI'); 206 | } 207 | 208 | /// Returns the current CI [Vendor] or [null] if no CI vendor detected (e.g. not running on CI). 209 | static Vendor? get current { 210 | if (IS_CODEBUILD) { 211 | return Vendor._( 212 | 'AWS CodeBuild', 213 | false, 214 | ); 215 | } 216 | 217 | if (IS_APPVEYOR) { 218 | return Vendor._( 219 | 'AppVeyor', 220 | Platform.environment.containsKey('APPVEYOR_PULL_REQUEST_NUMBER'), 221 | ); 222 | } 223 | 224 | if (IS_APPCIRCLE) { 225 | return Vendor._( 226 | 'Appcircle', 227 | false, 228 | ); 229 | } 230 | 231 | if (IS_AZURE_PIPELINES) { 232 | return Vendor._( 233 | 'Azure Pipelines', 234 | Platform.environment.containsKey('SYSTEM_PULLREQUEST_PULLREQUESTID'), 235 | ); 236 | } 237 | 238 | if (IS_BAMBOO) { 239 | return Vendor._( 240 | 'Bamboo', 241 | false, 242 | ); 243 | } 244 | 245 | if (IS_BITBUCKET) { 246 | return Vendor._( 247 | 'Bitbucket Pipelines', 248 | Platform.environment.containsKey('BITBUCKET_PR_ID'), 249 | ); 250 | } 251 | 252 | if (IS_BITRISE) { 253 | return Vendor._( 254 | 'Bitrise', 255 | Platform.environment.containsKey('BITRISE_PULL_REQUEST'), 256 | ); 257 | } 258 | 259 | if (IS_BUDDY) { 260 | return Vendor._( 261 | 'Buddy', 262 | Platform.environment.containsKey('BUDDY_EXECUTION_PULL_REQUEST_ID'), 263 | ); 264 | } 265 | 266 | if (IS_BUILDKITE) { 267 | return Vendor._( 268 | 'Buildkite', 269 | Platform.environment['BUILDKITE_PULL_REQUEST'] != 'false', 270 | ); 271 | } 272 | 273 | if (IS_CIRCLE) { 274 | return Vendor._( 275 | 'CircleCI', 276 | Platform.environment.containsKey('CIRCLE_PULL_REQUEST'), 277 | ); 278 | } 279 | 280 | if (IS_CIRRUS) { 281 | return Vendor._( 282 | 'Cirrus CI', 283 | Platform.environment.containsKey('CIRRUS_PR'), 284 | ); 285 | } 286 | 287 | if (IS_CODEFRESH) { 288 | return Vendor._( 289 | 'Codefresh', 290 | Platform.environment.containsKey("CF_PULL_REQUEST_NUMBER") || 291 | Platform.environment.containsKey("CF_PULL_REQUEST_ID"), 292 | ); 293 | } 294 | 295 | if (IS_CODEMAGIC) { 296 | return Vendor._( 297 | 'Codemagic', 298 | Platform.environment['FCI_PULL_REQUEST'] != 'false', 299 | ); 300 | } 301 | 302 | if (IS_CODESHIP) { 303 | return Vendor._( 304 | 'Codeship', 305 | false, 306 | ); 307 | } 308 | 309 | if (IS_DRONE) { 310 | return Vendor._( 311 | 'Drone', 312 | Platform.environment["DRONE_BUILD_EVENT"] == "pull_request", 313 | ); 314 | } 315 | 316 | if (IS_EAS) { 317 | return Vendor._( 318 | 'Expo Application Services', 319 | false, 320 | ); 321 | } 322 | 323 | if (IS_GITHUB_ACTIONS) { 324 | return Vendor._( 325 | 'GitHub Actions', 326 | Platform.environment["GITHUB_EVENT_NAME"] == "pull_request", 327 | ); 328 | } 329 | 330 | if (IS_GITLAB) { 331 | return Vendor._( 332 | 'GitLab CI', 333 | Platform.environment.containsKey('CI_MERGE_REQUEST_ID'), 334 | ); 335 | } 336 | 337 | if (IS_GOCD) { 338 | return Vendor._( 339 | 'GoCD', 340 | false, 341 | ); 342 | } 343 | 344 | if (IS_HUDSON) { 345 | return Vendor._( 346 | 'Hudson', 347 | false, 348 | ); 349 | } 350 | 351 | if (IS_JENKINS) { 352 | return Vendor._( 353 | 'Jenkins', 354 | Platform.environment.containsKey("ghprbPullId") || 355 | Platform.environment.containsKey("CHANGE_ID"), 356 | ); 357 | } 358 | 359 | if (IS_LAYERCI) { 360 | return Vendor._( 361 | 'LayerCI', 362 | Platform.environment.containsKey('LAYERCI_PULL_REQUEST'), 363 | ); 364 | } 365 | 366 | if (IS_MAGNUM) { 367 | return Vendor._( 368 | 'Magnum CI', 369 | false, 370 | ); 371 | } 372 | 373 | if (IS_NETLIFY) { 374 | return Vendor._( 375 | 'Netlify CI', 376 | Platform.environment['PULL_REQUEST'] != 'false', 377 | ); 378 | } 379 | 380 | if (IS_NEVERCODE) { 381 | return Vendor._( 382 | 'Nevercode', 383 | Platform.environment['NEVERCODE_PULL_REQUEST'] != 'false', 384 | ); 385 | } 386 | 387 | if (IS_RENDER) { 388 | return Vendor._( 389 | 'Render', 390 | Platform.environment["IS_PULL_REQUEST"] == "true", 391 | ); 392 | } 393 | 394 | if (IS_SAIL) { 395 | return Vendor._( 396 | 'Sail CI', 397 | Platform.environment.containsKey('SAIL_PULL_REQUEST_NUMBER'), 398 | ); 399 | } 400 | 401 | if (IS_SCREWDRIVER) { 402 | return Vendor._( 403 | 'Screwdriver', 404 | Platform.environment['SD_PULL_REQUEST'] != 'false', 405 | ); 406 | } 407 | 408 | if (IS_SEMAPHORE) { 409 | return Vendor._( 410 | 'Semaphore', 411 | Platform.environment.containsKey('PULL_REQUEST_NUMBER'), 412 | ); 413 | } 414 | 415 | if (IS_SHIPPABLE) { 416 | return Vendor._( 417 | 'Shippable', 418 | Platform.environment["IS_PULL_REQUEST"] == "true", 419 | ); 420 | } 421 | 422 | if (IS_SOLANO) { 423 | return Vendor._( 424 | 'Solano CI', 425 | Platform.environment.containsKey('TDDIUM_PR_ID'), 426 | ); 427 | } 428 | 429 | if (IS_STRIDER) { 430 | return Vendor._( 431 | 'Strider CD', 432 | false, 433 | ); 434 | } 435 | 436 | if (IS_TASKCLUSTER) { 437 | return Vendor._( 438 | 'TaskCluster', 439 | false, 440 | ); 441 | } 442 | 443 | if (IS_TEAMCITY) { 444 | return Vendor._( 445 | 'TeamCity', 446 | false, 447 | ); 448 | } 449 | 450 | if (IS_TRAVIS) { 451 | return Vendor._( 452 | 'Travis CI', 453 | Platform.environment['TRAVIS_PULL_REQUEST'] != 'false', 454 | ); 455 | } 456 | 457 | if (IS_VERCEL) { 458 | return Vendor._( 459 | 'Vercel', 460 | false, 461 | ); 462 | } 463 | 464 | if (IS_APPCENTER) { 465 | return Vendor._( 466 | 'Visual Studio App Center', 467 | false, 468 | ); 469 | } 470 | 471 | if (IS_DSARI) { 472 | return Vendor._( 473 | 'dsari', 474 | false, 475 | ); 476 | } 477 | 478 | return null; 479 | } 480 | } 481 | -------------------------------------------------------------------------------- /packages/ci/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | description: Detect whether you're running in a CI environment and information about the CI vendor. 3 | version: 0.1.0 4 | repository: https://github.com/invertase/dart-cli-utilities/tree/main/packages/ci 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | 9 | dev_dependencies: 10 | http: ^0.13.4 11 | test: ^1.16.0 12 | -------------------------------------------------------------------------------- /packages/ci/test/ci_test.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-present Invertase Limited & Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this library except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | import 'dart:io'; 19 | 20 | import 'package:ci/ci.dart' as ci; 21 | import 'package:test/test.dart'; 22 | 23 | void main() { 24 | group( 25 | 'test on github actions', 26 | () { 27 | test('[isCI] returns true if running on GH actions', () { 28 | expect(ci.isCI, isTrue); 29 | }); 30 | 31 | test('generated vendor flags correctly return true/false', () { 32 | expect(ci.Vendor.IS_GITHUB_ACTIONS, isTrue); 33 | expect(ci.Vendor.IS_CIRRUS, isFalse); 34 | }); 35 | 36 | test('generated current vendor should return GitHub', () { 37 | expect(ci.currentVendor, isNotNull); 38 | expect(ci.Vendor.current, isNotNull); 39 | expect(ci.currentVendor?.name, equals('GitHub Actions')); 40 | }); 41 | }, 42 | skip: !Platform.environment.containsKey('GITHUB_ACTIONS'), 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /packages/storagebox/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub. 2 | .dart_tool/ 3 | .packages 4 | 5 | # Conventional directory for build outputs. 6 | build/ 7 | 8 | # Omit committing pubspec.lock for library packages; see 9 | # https://dart.dev/guides/libraries/private-files#pubspeclock. 10 | pubspec.lock 11 | .vscode 12 | .idea 13 | *.iml -------------------------------------------------------------------------------- /packages/storagebox/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0+3 2 | 3 | - **FIX**: fix clearing storage (#4). ([bb512eec](https://github.com/invertase/dart-cli-utilities/commit/bb512eecf1f8ca9cad73e8f8b06cfd9edb4614f2)) 4 | 5 | ## 0.1.0+2 6 | 7 | - downgrade path to 1.8.0 8 | 9 | ## 0.1.0+1 10 | 11 | - **DOCS**: update readme. ([7d805aca](https://github.com/invertase/dart-cli-utilities/commit/7d805acae21f1594e98c34d3986e85ba452c1d65)) 12 | 13 | ## 0.1.0 14 | 15 | - Initial version. 16 | -------------------------------------------------------------------------------- /packages/storagebox/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 Invertase Limited 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /packages/storagebox/README.md: -------------------------------------------------------------------------------- 1 |

2 |

📦 StorageBox

3 | Easily store and persist configuration items for your Dart CLIs and Web apps. 4 |

5 | 6 | Melos 7 | docs.page 8 | 9 | Documentation • 10 | License 11 | 12 | --- 13 | 14 | ### About 15 | 16 | Storagebox is a lightweight configuration storage API for Dart CLI apps with a familiar `Map`-like API. 17 | 18 | It maintains some compatibility with [`configstore`](https://github.com/yeoman/configstore) from the Node.js ecosystem via `configPathPrefix`, allowing you to migrate away from it or use existing configuration items that exist from Node.js based CLIs. 19 | 20 | **Example:** 21 | 22 | ```dart 23 | import 'package:storagebox/storagebox.dart'; 24 | 25 | Future main() async { 26 | final config = StorageBox('my_awesome_cli'); 27 | config['foo'] = 'bar'; 28 | print(config['foo']); 29 | config['bar'] = 'foo'; 30 | print(config['bar']); 31 | 32 | // Config is a Map so Map methods can be used; 33 | config.forEach((key, value) { 34 | print('$key : $value'); 35 | }); 36 | print(config.containsKey('foo')); 37 | print(config.remove('bar')); 38 | } 39 | ``` 40 | 41 | --- 42 | 43 |

44 | 45 | 46 | 47 |

48 | Built and maintained by Invertase. 49 |

50 |

51 | -------------------------------------------------------------------------------- /packages/storagebox/dart_test.yaml: -------------------------------------------------------------------------------- 1 | platforms: 2 | - chrome 3 | - vm 4 | -------------------------------------------------------------------------------- /packages/storagebox/example/storagebox_example.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_print 2 | 3 | /* 4 | * Copyright (c) 2020-present Invertase Limited & Contributors 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this library except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | import 'package:storagebox/storagebox.dart'; 21 | 22 | Future main() async { 23 | final config = StorageBox('my_awesome_cli'); 24 | config['foo'] = 'bar'; 25 | print(config['foo']); 26 | config['bar'] = 'foo'; 27 | print(config['bar']); 28 | 29 | // Config is a Map so Map methods can be used; 30 | config.forEach((key, value) { 31 | print('$key : $value'); 32 | }); 33 | print(config.containsKey('foo')); 34 | print(config.remove('bar')); 35 | 36 | // Unserializable JSON values are detected and a StorageBoxException thrown. 37 | config['error'] = const Duration(milliseconds: 500); 38 | } 39 | -------------------------------------------------------------------------------- /packages/storagebox/lib/src/exception.dart: -------------------------------------------------------------------------------- 1 | /// A base class for all StorageBox exceptions. 2 | class StorageBoxException implements Exception { 3 | StorageBoxException(this.message); 4 | final String message; 5 | @override 6 | String toString() { 7 | return 'StorageBoxException: $message'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/storagebox/lib/src/storagebox.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-present Invertase Limited & Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this library except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | import 'storagebox_vm.dart' 19 | if (dart.library.io) 'storagebox_vm.dart' 20 | if (dart.library.html) 'storagebox_js.dart'; 21 | 22 | class StorageBox extends StorageBoxImplementation { 23 | StorageBox( 24 | String id, { 25 | Map? defaults, 26 | String configPathPrefix = 'storagebox-dart', 27 | }) : super( 28 | id, 29 | defaults: defaults, 30 | configPathPrefix: configPathPrefix, 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /packages/storagebox/lib/src/storagebox_base.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-present Invertase Limited & Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this library except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | import 'package:collection/collection.dart' as collection; 19 | 20 | class StorageBoxImplementationBase 21 | implements collection.DelegatingMap { 22 | StorageBoxImplementationBase( 23 | this.id, { 24 | Map? defaults, 25 | }) { 26 | this.defaults = defaults ?? {}; 27 | } 28 | 29 | final String id; 30 | 31 | late Map defaults; 32 | 33 | Map get delegate { 34 | throw UnimplementedError(); 35 | } 36 | 37 | set delegate(Map updatedMap) { 38 | throw UnimplementedError(); 39 | } 40 | 41 | @override 42 | T? operator [](Object? key) { 43 | return delegate[key]; 44 | } 45 | 46 | @override 47 | void operator []=(K key, T value) { 48 | delegate = { 49 | ...delegate, 50 | key: value, 51 | }; 52 | } 53 | 54 | @override 55 | void addAll(Map other) { 56 | delegate = Map.from(delegate)..addAll(other); 57 | } 58 | 59 | @override 60 | void addEntries(Iterable> entries) { 61 | delegate = Map.from(delegate)..addEntries(entries); 62 | } 63 | 64 | @override 65 | Map cast() { 66 | return delegate.cast(); 67 | } 68 | 69 | @override 70 | void clear() { 71 | delegate = {}; 72 | } 73 | 74 | @override 75 | bool containsKey(Object? key) { 76 | return delegate.containsKey(key); 77 | } 78 | 79 | @override 80 | bool containsValue(Object? value) { 81 | return delegate.containsValue(value); 82 | } 83 | 84 | @override 85 | Iterable> get entries => delegate.entries; 86 | 87 | @override 88 | void forEach(void Function(K key, T value) f) { 89 | delegate.forEach(f); 90 | } 91 | 92 | @override 93 | bool get isEmpty => delegate.isEmpty; 94 | 95 | @override 96 | bool get isNotEmpty => delegate.isNotEmpty; 97 | 98 | @override 99 | Iterable get keys => delegate.keys; 100 | 101 | @override 102 | int get length => delegate.length; 103 | 104 | @override 105 | Map map(MapEntry Function(K key, T value) transform) { 106 | return delegate.map(transform); 107 | } 108 | 109 | @override 110 | T putIfAbsent(K key, T Function() ifAbsent) { 111 | final updatedMap = { 112 | ...delegate, 113 | }; 114 | final returnedValue = updatedMap.putIfAbsent( 115 | key, 116 | ifAbsent, 117 | ); 118 | delegate = updatedMap; 119 | return returnedValue; 120 | } 121 | 122 | @override 123 | T? remove(Object? key) { 124 | final updatedMap = { 125 | ...delegate, 126 | }; 127 | final removedValue = updatedMap.remove( 128 | key, 129 | ); 130 | delegate = updatedMap; 131 | return removedValue; 132 | } 133 | 134 | @override 135 | void removeWhere(bool Function(K key, T value) test) { 136 | delegate = delegate..removeWhere(test); 137 | } 138 | 139 | @override 140 | Map retype() { 141 | return cast(); 142 | } 143 | 144 | @override 145 | T update(K key, T Function(T value) update, {T Function()? ifAbsent}) { 146 | final updatedMap = { 147 | ...delegate, 148 | }; 149 | final updatedValue = updatedMap.update( 150 | key, 151 | update, 152 | ifAbsent: ifAbsent, 153 | ); 154 | delegate = updatedMap; 155 | return updatedValue; 156 | } 157 | 158 | @override 159 | void updateAll(T Function(K key, T value) update) { 160 | delegate = delegate..updateAll(update); 161 | } 162 | 163 | @override 164 | Iterable get values => delegate.values; 165 | 166 | @override 167 | String toString() { 168 | return delegate.toString(); 169 | } 170 | 171 | @override 172 | bool operator ==(Object other) { 173 | return other is StorageBoxImplementationBase && other.id == id; 174 | } 175 | 176 | @override 177 | int get hashCode => id.hashCode; 178 | } 179 | -------------------------------------------------------------------------------- /packages/storagebox/lib/src/storagebox_js.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-present Invertase Limited & Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this library except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | import 'dart:convert' as convert; 19 | import 'dart:html' as html; 20 | 21 | import 'package:meta/meta.dart' as meta; 22 | 23 | import 'exception.dart'; 24 | import 'storagebox_base.dart'; 25 | 26 | class StorageBoxImplementation 27 | extends StorageBoxImplementationBase { 28 | StorageBoxImplementation( 29 | String id, { 30 | Map? defaults, 31 | required String configPathPrefix, 32 | }) : super(id, defaults: defaults) { 33 | storageKey = '.$configPathPrefix/$id'; 34 | } 35 | 36 | @meta.visibleForTesting 37 | late String storageKey; 38 | 39 | @meta.visibleForTesting 40 | @override 41 | Map get delegate { 42 | try { 43 | final contents = html.window.localStorage[storageKey]; 44 | final configMap = 45 | const convert.JsonDecoder().convert(contents ?? '{}') as Map; 46 | return { 47 | ...defaults, 48 | ...Map.from(configMap), 49 | }; 50 | } on FormatException { 51 | // The file is empty or contains invalid JSON. 52 | // Next time the map is modified the file will be reset. 53 | return { 54 | ...defaults, 55 | }; 56 | } catch (e) { 57 | rethrow; 58 | } 59 | } 60 | 61 | @meta.visibleForTesting 62 | @override 63 | set delegate(Map updatedMap) { 64 | try { 65 | final updatedConfigMapString = 66 | const convert.JsonEncoder.withIndent('\t').convert(updatedMap); 67 | html.window.localStorage[storageKey] = updatedConfigMapString; 68 | return; 69 | // ignore: avoid_catching_errors 70 | } on convert.JsonUnsupportedObjectError catch (error) { 71 | final key = updatedMap.keys 72 | .firstWhere((key) => updatedMap[key] == error.unsupportedObject); 73 | throw StorageBoxException( 74 | 'Value for key "$key" for "$id" storagebox is not a JSON serializable value.', 75 | ); 76 | } catch (e) { 77 | rethrow; 78 | } 79 | } 80 | 81 | @override 82 | bool operator ==(Object other) { 83 | return other is StorageBoxImplementation && other.storageKey == storageKey; 84 | } 85 | 86 | @override 87 | int get hashCode => storageKey.hashCode; 88 | } 89 | -------------------------------------------------------------------------------- /packages/storagebox/lib/src/storagebox_vm.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-present Invertase Limited & Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this library except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | import 'dart:convert' as convert; 19 | import 'dart:io' as io; 20 | 21 | import 'package:meta/meta.dart' as meta; 22 | import 'package:path/path.dart' as path; 23 | import 'package:xdg_directories/xdg_directories.dart' as xdg; 24 | 25 | import 'exception.dart'; 26 | import 'storagebox_base.dart'; 27 | 28 | class StorageBoxImplementation 29 | extends StorageBoxImplementationBase { 30 | StorageBoxImplementation( 31 | String id, { 32 | Map? defaults, 33 | required String configPathPrefix, 34 | }) : super( 35 | id, 36 | defaults: defaults, 37 | ) { 38 | final pathSuffix = path.joinAll([configPathPrefix, '$id.json']); 39 | if (io.Platform.isWindows) { 40 | final homeDir = io.Platform.environment['HOME'] ?? 41 | io.Platform.environment['USERPROFILE']; 42 | file = io.File( 43 | path.joinAll([homeDir!, '.config', configPathPrefix, '$id.json']), 44 | ); 45 | } else { 46 | file = io.File(path.joinAll([xdg.configHome.path, pathSuffix])); 47 | } 48 | } 49 | 50 | @meta.visibleForTesting 51 | late io.File file; 52 | 53 | @meta.visibleForTesting 54 | @override 55 | Map get delegate { 56 | try { 57 | final fileContents = file.readAsStringSync(); 58 | final configMap = 59 | const convert.JsonDecoder().convert(fileContents) as Map; 60 | return { 61 | ...defaults, 62 | ...Map.from(configMap), 63 | }; 64 | } on io.FileSystemException catch (exception) { 65 | // ENOENT - file or directory does not exist. 66 | // We don't create until a value is set. 67 | if (exception.osError?.errorCode == 2 || 68 | exception.osError?.errorCode == 3) { 69 | return { 70 | ...defaults, 71 | }; 72 | } 73 | 74 | // EACCES - no permission to access the file. 75 | // Throw a nicer error message. 76 | if (exception.osError?.errorCode == 13) { 77 | throw Exception( 78 | 'Access denied when attempting to read the "$id" storagebox at path "${file.path}".', 79 | ); 80 | } 81 | 82 | rethrow; 83 | } on FormatException { 84 | // The file is empty or contains invalid JSON. 85 | // Next time the map is modified the file will be reset. 86 | return { 87 | ...defaults, 88 | }; 89 | } catch (e) { 90 | rethrow; 91 | } 92 | } 93 | 94 | @meta.visibleForTesting 95 | @override 96 | set delegate(Map updatedMap) { 97 | try { 98 | final updatedConfigMapString = 99 | const convert.JsonEncoder.withIndent('\t').convert(updatedMap); 100 | file.createSync(recursive: true); 101 | file.writeAsStringSync( 102 | updatedConfigMapString, 103 | flush: true, 104 | ); 105 | return; 106 | } on io.FileSystemException catch (exception) { 107 | // EACCES - no permission to access the file. 108 | // Throw a helpful error message. 109 | if (exception.osError?.errorCode == 13) { 110 | throw StorageBoxException( 111 | 'Access denied when attempting to write to the "$id" storagebox at path "${file.path}".', 112 | ); 113 | } 114 | rethrow; 115 | // ignore: avoid_catching_errors 116 | } on convert.JsonUnsupportedObjectError catch (error) { 117 | final key = updatedMap.keys 118 | .firstWhere((key) => updatedMap[key] == error.unsupportedObject); 119 | throw StorageBoxException( 120 | 'Value for key "$key" for "$id" storagebox at path "${file.path}" is not a JSON serializable value.', 121 | ); 122 | } catch (e) { 123 | rethrow; 124 | } 125 | } 126 | 127 | @override 128 | bool operator ==(Object other) { 129 | return other is StorageBoxImplementation && other.file.path == file.path; 130 | } 131 | 132 | @override 133 | int get hashCode => file.path.hashCode; 134 | } 135 | -------------------------------------------------------------------------------- /packages/storagebox/lib/storagebox.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-present Invertase Limited & Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this library except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | library storagebox; 19 | 20 | export 'src/storagebox.dart'; 21 | -------------------------------------------------------------------------------- /packages/storagebox/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: storagebox 2 | description: Easily store configuration keys and values for your CLI and web apps. 3 | version: 0.1.0+3 4 | repository: https://github.com/invertase/dart-cli-utilities/tree/main/packages/storagebox 5 | 6 | environment: 7 | sdk: '>=2.15.0 <3.0.0' 8 | 9 | dev_dependencies: 10 | test: ^1.16.0 11 | dependencies: 12 | collection: ^1.15.0 13 | meta: ^1.7.0 14 | path: ^1.8.0 15 | xdg_directories: ^0.2.0 16 | -------------------------------------------------------------------------------- /packages/storagebox/test/storagebox_test.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-present Invertase Limited & Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this library except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | import 'package:storagebox/storagebox.dart'; 19 | import 'package:test/test.dart'; 20 | 21 | void main() { 22 | group('sets values', () { 23 | final store = StorageBox('testing'); 24 | 25 | test('using equal assigment operator', () { 26 | store['hello'] = 'world'; 27 | expect(store['hello'], equals('world')); 28 | }); 29 | 30 | // TODO more tests 31 | }); 32 | } 33 | --------------------------------------------------------------------------------