mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
add-lints (#3356)
* test add lint as separate action * nicer logging * only detect changes in dart files * fix printV warnings being displayed when editing printV --------- Co-authored-by: Czarek Nakamoto <cyjan@mrcyjanek.net>
This commit is contained in:
co-authored by
Czarek Nakamoto
parent
031a117f2e
commit
01c977e82b
@@ -0,0 +1,109 @@
|
||||
name: Lint
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: [Linux, amd64, android]
|
||||
container:
|
||||
image: ghcr.io/cake-tech/cake_wallet:debian13-flutter3.41.9-ndkr28-go1.24.1-ruststablenightly
|
||||
env:
|
||||
STORE_PASS: test@cake_wallet
|
||||
KEY_PASS: test@cake_wallet
|
||||
MONEROC_CACHE_DIR_ROOT: /opt/generic_cache
|
||||
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||
ANDROID_AVD_HOME: /root/.android/avd
|
||||
volumes:
|
||||
- /opt/cw_cache_android/root/.cache:/root/.cache
|
||||
- /opt/cw_cache_android/root/.android/avd/:/root/.android/avd
|
||||
- /opt/cw_cache_android/root/.ccache:/root/.ccache
|
||||
- /opt/cw_cache_android/root/.pub-cache/:/root/.pub-cache
|
||||
- /opt/cw_cache_android/root/.gradle/:/root/.gradle
|
||||
- /opt/cw_cache_android/root/.android/:/root/.android
|
||||
- /opt/cw_cache_android/root/go/pkg:/root/go/pkg
|
||||
- /opt/cw_cache_android/opt/generic_cache:/opt/generic_cache
|
||||
- /dev/kvm:/dev/kvm
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
strategy:
|
||||
matrix:
|
||||
api-level: [ 29 ]
|
||||
|
||||
steps:
|
||||
- name: configure git
|
||||
run: |
|
||||
git config --global --add safe.directory '*'
|
||||
git config --global user.email "ci@cakewallet.com"
|
||||
git config --global user.name "CakeWallet CI"
|
||||
|
||||
- name: Fetch prebuilt Torch
|
||||
run: |
|
||||
set -x -e
|
||||
pushd scripts
|
||||
wget https://github.com/MrCyjaneK/torch_dart/releases/download/v1.0.17/torch_dart-v1.0.17.tar.gz -O torch_dart.tar.gz
|
||||
rm -rf torch_dart
|
||||
mkdir torch_dart
|
||||
pushd torch_dart
|
||||
tar -xzf ../torch_dart.tar.gz
|
||||
popd
|
||||
rm ./torch_dart.tar.gz
|
||||
popd
|
||||
|
||||
- name: Fetch prebuilt Reown
|
||||
run: |
|
||||
set -x -e
|
||||
pushd scripts
|
||||
# cleaning
|
||||
rm -rf reown_flutter
|
||||
rm -f reown_flutter.tar.gz
|
||||
|
||||
wget https://github.com/cake-tech/reown_flutter/releases/download/v0.0.4/reown_flutter-v0.0.4.tar.gz -O reown_flutter.tar.gz
|
||||
mkdir reown_flutter
|
||||
pushd reown_flutter
|
||||
tar -xzf ../reown_flutter.tar.gz
|
||||
popd
|
||||
rm ./reown_flutter.tar.gz
|
||||
popd
|
||||
|
||||
- name: Build Bitbox Flutter
|
||||
run: |
|
||||
set -x -e
|
||||
pushd scripts
|
||||
./build_bitbox_flutter.sh
|
||||
popd
|
||||
|
||||
- name: Prepare Zcash
|
||||
run: |
|
||||
set -x -e
|
||||
scripts/prepare_zcash.sh
|
||||
|
||||
- name: Execute Build and Setup Commands
|
||||
run: |
|
||||
pushd scripts/android
|
||||
source ./app_env.sh cakewallet
|
||||
export GITHUB_HUH=yeah
|
||||
./app_config.sh
|
||||
popd
|
||||
|
||||
- name: Install Flutter dependencies
|
||||
run: |
|
||||
flutter pub get
|
||||
|
||||
- name: Build generated code
|
||||
run: |
|
||||
flutter --version
|
||||
flutter clean
|
||||
rm -rf .dart_tool
|
||||
rm pubspec.lock
|
||||
flutter pub get
|
||||
./model_generator.sh async
|
||||
|
||||
- name: Generate localization
|
||||
run: |
|
||||
dart run tool/generate_localization.dart
|
||||
|
||||
- name: Lint
|
||||
run: |
|
||||
ABORT_ON_CHANGE=yeah scripts/lint.sh
|
||||
@@ -11,11 +11,10 @@ jobs:
|
||||
- name: Check for http package usage
|
||||
if: github.event_name == 'pull_request'
|
||||
run: |
|
||||
GIT_GREP_OUT="$(git grep package:http | (grep .dart: || test $? = 1) | (grep -v proxy_wrapper.dart || test $? = 1) | (grep -v very_insecure_http_do_not_use || test $? = 1) || true)"
|
||||
GIT_GREP_OUT="$(git grep package:http | (grep .dart: || test $? = 1) | (grep -v proxy_wrapper.dart || test $? = 1) | (grep -v very_insecure_http_do_not_use || test $? = 1) | (grep -v '^cw_custom_lints/' || test $? = 1) || true)"
|
||||
[[ "x$GIT_GREP_OUT" == "x" ]] && exit 0
|
||||
echo "$GIT_GREP_OUT"
|
||||
echo "There are .dart files which use http imports"
|
||||
echo "Using http package breaks proxy integration"
|
||||
echo "Please use ProxyWrapper.getHttpClient() from package:cw_core/utils/proxy_wrapper.dart"
|
||||
exit 1
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
- name: Check for print() statements in dart code (use printV() instead)
|
||||
if: github.event_name == 'pull_request'
|
||||
run: |
|
||||
GIT_GREP_OUT="$(git grep ' print(' | (grep .dart: || test $? = 1) | (grep -v print_verbose.dart || test $? = 1) | (grep -v print_verbose_dummy.dart || test $? = 1) || true)"
|
||||
GIT_GREP_OUT="$(git grep ' print(' | (grep .dart: || test $? = 1) | (grep -v print_verbose.dart || test $? = 1) | (grep -v print_verbose_dummy.dart || test $? = 1) | (grep -v '^tool/' || test $? = 1) | (grep -v '^cw_custom_lints/' || test $? = 1) || true)"
|
||||
[[ "x$GIT_GREP_OUT" == "x" ]] && exit 0
|
||||
echo "$GIT_GREP_OUT"
|
||||
echo "There are .dart files which use print() statements"
|
||||
|
||||
@@ -179,9 +179,6 @@ jobs:
|
||||
with:
|
||||
path: ${{ github.workspace }}/build/linux/x64/release/cakewallet_linux.zip
|
||||
name: cakewallet_linux
|
||||
- name: Verify lint
|
||||
run: |
|
||||
exec env ABORT_ON_CHANGE=true ./scripts/lint.sh
|
||||
|
||||
- name: Prepare virtual desktop
|
||||
if: ${{ contains(env.message, 'run tests') }}
|
||||
|
||||
+113
-54
@@ -1,4 +1,3 @@
|
||||
include: package:lints/recommended.yaml
|
||||
|
||||
|
||||
analyzer:
|
||||
@@ -9,6 +8,7 @@ analyzer:
|
||||
cw_core/lib/**.g.dart,
|
||||
cw_haven/lib/**.g.dart,
|
||||
cw_monero/lib/**.g.dart,
|
||||
cw_mweb/lib/**.g.dart,
|
||||
lib/generated/*.dart,
|
||||
cw_monero/ios/External/**,
|
||||
cw_shared_external/**,
|
||||
@@ -18,65 +18,124 @@ analyzer:
|
||||
strict-casts: true
|
||||
strict-raw-types: true
|
||||
|
||||
plugins:
|
||||
cw_custom_lints:
|
||||
path: cw_custom_lints
|
||||
|
||||
linter:
|
||||
rules:
|
||||
- cancel_subscriptions
|
||||
- always_declare_return_types
|
||||
- prefer_final_fields
|
||||
- always_put_control_body_on_new_line
|
||||
- always_put_required_named_parameters_first
|
||||
- always_use_package_imports
|
||||
- annotate_overrides
|
||||
- annotate_redeclares
|
||||
- avoid_empty_else
|
||||
- avoid_function_literals_in_foreach_calls
|
||||
- avoid_init_to_null
|
||||
- avoid_multiple_declarations_per_line
|
||||
- avoid_positional_boolean_parameters
|
||||
- avoid_relative_lib_imports
|
||||
- avoid_renaming_method_parameters
|
||||
- avoid_return_types_on_setters
|
||||
- avoid_returning_null_for_void
|
||||
- avoid_slow_async_io
|
||||
- avoid_types_as_parameter_names
|
||||
- avoid_types_on_closure_parameters
|
||||
- avoid_unnecessary_containers
|
||||
- avoid_unused_constructor_parameters
|
||||
- avoid_void_async
|
||||
- await_only_futures
|
||||
- camel_case_extensions
|
||||
- camel_case_types
|
||||
- cast_nullable_to_non_nullable
|
||||
- collection_methods_unrelated_type
|
||||
- constant_identifier_names
|
||||
- curly_braces_in_flow_control_structures
|
||||
- directives_ordering
|
||||
- empty_constructor_bodies
|
||||
- empty_statements
|
||||
- eol_at_end_of_file
|
||||
- flutter_style_todos
|
||||
- hash_and_equals
|
||||
- implicit_reopen
|
||||
- library_private_types_in_public_api
|
||||
- non_constant_identifier_names
|
||||
- only_throw_errors
|
||||
- package_names
|
||||
- prefer_asserts_with_message
|
||||
- prefer_conditional_assignment
|
||||
- prefer_const_constructors
|
||||
- prefer_const_constructors_in_immutables
|
||||
- prefer_const_declarations
|
||||
- prefer_constructors_over_static_methods
|
||||
- prefer_contains
|
||||
- prefer_double_quotes
|
||||
- prefer_expression_function_bodies
|
||||
- prefer_final_in_for_each
|
||||
- prefer_function_declarations_over_variables
|
||||
- prefer_if_null_operators
|
||||
- prefer_initializing_formals
|
||||
- prefer_inlined_adds
|
||||
- prefer_int_literals
|
||||
- prefer_is_empty
|
||||
- prefer_is_not_empty
|
||||
- prefer_is_not_operator
|
||||
- prefer_iterable_wheretype
|
||||
- prefer_null_aware_operators
|
||||
- prefer_spread_collections
|
||||
- prefer_typing_uninitialized_variables
|
||||
- recursive_getters
|
||||
- require_trailing_commas
|
||||
- sized_box_for_whitespace
|
||||
- sort_child_properties_last
|
||||
- sort_constructors_first
|
||||
- sort_unnamed_constructors_first
|
||||
- test_types_in_equals
|
||||
- unawaited_futures
|
||||
- unnecessary_async
|
||||
- unnecessary_await_in_return
|
||||
- unnecessary_const
|
||||
- unnecessary_constructor_name
|
||||
- unnecessary_lambdas
|
||||
- unnecessary_late
|
||||
- unnecessary_new
|
||||
- unnecessary_null_aware_assignments
|
||||
- unnecessary_null_checks
|
||||
- unnecessary_null_in_if_null_operators
|
||||
- unnecessary_nullable_for_final_variable_declarations
|
||||
- unnecessary_overrides
|
||||
- unnecessary_parenthesis
|
||||
- unnecessary_string_escapes
|
||||
- unnecessary_string_interpolations
|
||||
- unnecessary_this
|
||||
- unnecessary_to_list_in_spreads
|
||||
- unnecessary_underscores
|
||||
- unreachable_from_main
|
||||
- unrelated_type_equality_checks
|
||||
- use_build_context_synchronously
|
||||
- use_colored_box
|
||||
- use_full_hex_values_for_flutter_colors
|
||||
- use_function_type_syntax_for_parameters
|
||||
- use_is_even_rather_than_modulo
|
||||
- use_named_constants
|
||||
- use_null_aware_elements
|
||||
- use_raw_strings
|
||||
- use_rethrow_when_possible
|
||||
- use_string_buffers
|
||||
- use_super_parameters
|
||||
- use_truncating_division
|
||||
- valid_regexps
|
||||
- void_checks
|
||||
- prefer_final_locals
|
||||
- prefer_interpolation_to_compose_strings
|
||||
- null_closures
|
||||
- no_wildcard_variable_uses
|
||||
|
||||
|
||||
|
||||
|
||||
formatter:
|
||||
page_width: 100
|
||||
|
||||
|
||||
# analyzer:
|
||||
# strong-mode:
|
||||
# implicit-casts: false
|
||||
# implicit-dynamic: false
|
||||
# exclude: [build/**, lib/generated/*.dart, lib/**.g.dart, cw_monero/ios/External/**, cw_shared_external/**, shared_external/**]
|
||||
|
||||
# linter:
|
||||
# rules:
|
||||
# - always_declare_return_types
|
||||
# - annotate_overrides
|
||||
# - avoid_empty_else
|
||||
# - avoid_init_to_null
|
||||
# - avoid_return_types_on_setters
|
||||
# - await_only_futures
|
||||
# - camel_case_types
|
||||
# - cancel_subscriptions
|
||||
# - close_sinks
|
||||
# - comment_references
|
||||
# - constant_identifier_names
|
||||
# - control_flow_in_finally
|
||||
# - empty_catches
|
||||
# - empty_constructor_bodies
|
||||
# - empty_statements
|
||||
# - hash_and_equals
|
||||
# - invariant_booleans
|
||||
# - iterable_contains_unrelated_type
|
||||
# - library_names
|
||||
# - library_prefixes
|
||||
# - list_remove_unrelated_type
|
||||
# - literal_only_boolean_expressions
|
||||
# - non_constant_identifier_names
|
||||
# - one_member_abstracts
|
||||
# - only_throw_errors
|
||||
# - overridden_fields
|
||||
# - package_api_docs
|
||||
# - package_names
|
||||
# - package_prefixed_library_names
|
||||
# - parameter_assignments
|
||||
# - prefer_final_fields
|
||||
# - prefer_final_locals
|
||||
# - prefer_is_not_empty
|
||||
# - slash_for_doc_comments
|
||||
# - sort_constructors_first
|
||||
# - sort_unnamed_constructors_first
|
||||
# - test_types_in_equals
|
||||
# - throw_in_finally
|
||||
# - type_init_formals
|
||||
# - unawaited_futures
|
||||
# - unnecessary_getters_setters
|
||||
# - unrelated_type_equality_checks
|
||||
# - valid_regexps
|
||||
|
||||
@@ -6,7 +6,7 @@ author: Cake Wallet
|
||||
homepage: https://cakewallet.com
|
||||
|
||||
environment:
|
||||
sdk: ">=2.17.5 <3.0.0"
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
flutter: ">=1.20.0"
|
||||
|
||||
dependencies:
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -0,0 +1,62 @@
|
||||
import "package:analyzer/analysis_rule/analysis_rule.dart";
|
||||
import "package:analyzer/analysis_rule/rule_context.dart";
|
||||
import "package:analyzer/analysis_rule/rule_visitor_registry.dart";
|
||||
import "package:analyzer/dart/ast/ast.dart";
|
||||
import "package:analyzer/dart/ast/visitor.dart";
|
||||
import "package:analyzer/error/error.dart";
|
||||
|
||||
class HttpForceProxyRule extends AnalysisRule {
|
||||
HttpForceProxyRule()
|
||||
: super(
|
||||
name: "no_http_imports",
|
||||
description:
|
||||
"Using the http package breaks proxy integration. Please use ProxyWrapper or alias it as \"very_insecure_http_do_not_use\".",
|
||||
);
|
||||
|
||||
static const LintCode code = LintCode(
|
||||
"no_http_imports",
|
||||
"Using the http package breaks proxy integration. Please use ProxyWrapper or alias it as \"very_insecure_http_do_not_use\".",
|
||||
severity: DiagnosticSeverity.WARNING,
|
||||
);
|
||||
|
||||
@override
|
||||
LintCode get diagnosticCode => code;
|
||||
|
||||
@override
|
||||
void registerNodeProcessors(
|
||||
RuleVisitorRegistry registry,
|
||||
RuleContext context,
|
||||
) {
|
||||
final filePath = context.definingUnit.file.path;
|
||||
|
||||
if (filePath.endsWith("proxy_wrapper.dart")) {
|
||||
return;
|
||||
}
|
||||
|
||||
registry.addImportDirective(this, _Visitor(this));
|
||||
}
|
||||
}
|
||||
|
||||
class _Visitor extends SimpleAstVisitor<void> {
|
||||
_Visitor(this.rule);
|
||||
|
||||
final AnalysisRule rule;
|
||||
|
||||
@override
|
||||
void visitImportDirective(ImportDirective node) {
|
||||
final uriString = node.uri.stringValue;
|
||||
if (uriString == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (uriString.startsWith("package:http")) {
|
||||
final prefixNode = node.prefix;
|
||||
if (prefixNode != null &&
|
||||
prefixNode.name == "very_insecure_http_do_not_use") {
|
||||
return;
|
||||
}
|
||||
|
||||
rule.reportAtNode(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import "package:analysis_server_plugin/plugin.dart";
|
||||
import "package:analysis_server_plugin/registry.dart";
|
||||
import "package:cw_custom_lints/http_force_proxy/http_force_proxy_rule.dart";
|
||||
import "package:cw_custom_lints/print_verbose/print_verbose_fix.dart";
|
||||
import "package:cw_custom_lints/print_verbose/print_verbose_rule.dart";
|
||||
import "package:cw_custom_lints/restricted_imports/restricted_imports_rule.dart";
|
||||
|
||||
final plugin = CwCustomLintsPlugin();
|
||||
|
||||
class CwCustomLintsPlugin extends Plugin {
|
||||
@override
|
||||
String get name => "cw_custom_lints";
|
||||
|
||||
@override
|
||||
void register(PluginRegistry registry) {
|
||||
registry.registerWarningRule(PrintVerboseRule());
|
||||
registry.registerWarningRule(RestrictedImportsRule());
|
||||
registry.registerWarningRule(HttpForceProxyRule());
|
||||
|
||||
registry.registerFixForRule(PrintVerboseRule.code, ReplaceWithPrintV.new);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import "package:analysis_server_plugin/edit/dart/correction_producer.dart";
|
||||
import "package:analysis_server_plugin/edit/dart/dart_fix_kind_priority.dart";
|
||||
import "package:analyzer/dart/ast/ast.dart";
|
||||
import "package:analyzer_plugin/utilities/change_builder/change_builder_core.dart";
|
||||
import "package:analyzer_plugin/utilities/fixes/fixes.dart";
|
||||
import "package:analyzer_plugin/utilities/range_factory.dart";
|
||||
|
||||
class ReplaceWithPrintV extends ResolvedCorrectionProducer {
|
||||
ReplaceWithPrintV({required super.context});
|
||||
|
||||
static const _importString = "package:cw_core/utils/print_verbose.dart";
|
||||
|
||||
static const _fixKind = FixKind(
|
||||
"dart.fix.replaceWithPrintV",
|
||||
DartFixKindPriority.standard,
|
||||
"Replace with printV()",
|
||||
);
|
||||
|
||||
@override
|
||||
CorrectionApplicability get applicability =>
|
||||
CorrectionApplicability.singleLocation;
|
||||
|
||||
@override
|
||||
FixKind get fixKind => _fixKind;
|
||||
|
||||
@override
|
||||
Future<void> compute(ChangeBuilder builder) async {
|
||||
final invocation = node.thisOrAncestorOfType<MethodInvocation>();
|
||||
if (invocation == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final root = invocation.root;
|
||||
final hasImport = root is CompilationUnit &&
|
||||
root.directives.whereType<ImportDirective>().any(
|
||||
(directive) => directive.uri.stringValue == _importString,
|
||||
);
|
||||
|
||||
await builder.addDartFileEdit(file, (builder) {
|
||||
builder.addSimpleReplacement(
|
||||
range.node(invocation.methodName),
|
||||
"printV",
|
||||
);
|
||||
|
||||
if (!hasImport) {
|
||||
builder.importLibrary(Uri.parse(_importString));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import "package:analyzer/analysis_rule/analysis_rule.dart";
|
||||
import "package:analyzer/analysis_rule/rule_context.dart";
|
||||
import "package:analyzer/analysis_rule/rule_visitor_registry.dart";
|
||||
import "package:analyzer/dart/ast/ast.dart";
|
||||
import "package:analyzer/dart/ast/visitor.dart";
|
||||
import "package:analyzer/error/error.dart";
|
||||
|
||||
class PrintVerboseRule extends AnalysisRule {
|
||||
PrintVerboseRule()
|
||||
: super(
|
||||
name: "use_print_v",
|
||||
description: "Use printV() from cw_core instead of print().",
|
||||
);
|
||||
|
||||
static const LintCode code = LintCode(
|
||||
"use_print_v",
|
||||
"Use printV() from cw_core instead",
|
||||
correctionMessage: "Replace print with printV",
|
||||
severity: DiagnosticSeverity.WARNING,
|
||||
);
|
||||
|
||||
@override
|
||||
LintCode get diagnosticCode => code;
|
||||
|
||||
@override
|
||||
void registerNodeProcessors(
|
||||
RuleVisitorRegistry registry,
|
||||
RuleContext context,
|
||||
) {
|
||||
final filePath = context.definingUnit.file.path;
|
||||
|
||||
if (filePath.contains("/tool/") || filePath.contains("print_verbose.dart")) {
|
||||
// tool/ is allowed to use print as it never makes its way into the app
|
||||
return;
|
||||
}
|
||||
|
||||
registry.addMethodInvocation(this, _Visitor(this));
|
||||
}
|
||||
}
|
||||
|
||||
class _Visitor extends SimpleAstVisitor<void> {
|
||||
_Visitor(this.rule);
|
||||
|
||||
final AnalysisRule rule;
|
||||
|
||||
@override
|
||||
void visitMethodInvocation(MethodInvocation node) {
|
||||
if (node.methodName.name == "print" && node.target == null) {
|
||||
rule.reportAtNode(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import "package:analyzer/analysis_rule/analysis_rule.dart";
|
||||
import "package:analyzer/analysis_rule/rule_context.dart";
|
||||
import "package:analyzer/analysis_rule/rule_visitor_registry.dart";
|
||||
import "package:analyzer/dart/ast/ast.dart";
|
||||
import "package:analyzer/dart/ast/visitor.dart";
|
||||
import "package:analyzer/error/error.dart";
|
||||
|
||||
class RestrictedImportsRule extends AnalysisRule {
|
||||
RestrictedImportsRule()
|
||||
: super(
|
||||
name: "no_restricted_imports_in_lib",
|
||||
description:
|
||||
"Do not import from coin-specific packages. If necessary, wire your logic through configure.dart",
|
||||
);
|
||||
|
||||
static const LintCode code = LintCode(
|
||||
"no_restricted_imports_in_lib",
|
||||
"Do not import from coin-specific packages. If necessary, wire your logic through configure.dart",
|
||||
severity: DiagnosticSeverity.ERROR,
|
||||
);
|
||||
|
||||
static const _restrictedPackages = {
|
||||
"cw_bitcoin",
|
||||
"cw_bitcoin_cash",
|
||||
"cw_electrum",
|
||||
"cw_litecoin",
|
||||
"cw_evm",
|
||||
"cw_mweb",
|
||||
"cw_nano",
|
||||
"cw_solana",
|
||||
"cw_tron",
|
||||
"cw_zano",
|
||||
};
|
||||
|
||||
@override
|
||||
LintCode get diagnosticCode => code;
|
||||
|
||||
@override
|
||||
void registerNodeProcessors(
|
||||
RuleVisitorRegistry registry,
|
||||
RuleContext context,
|
||||
) {
|
||||
final filePath = context.definingUnit.file.path;
|
||||
final fileName = filePath.split("/").last;
|
||||
|
||||
// ignore cw_something folders
|
||||
if (filePath.contains("cw_")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// allow ex. cw_bitcoin in bitcoin.dart
|
||||
if (_restrictedPackages.contains("cw_" + fileName.replaceAll(".dart", ""))) {
|
||||
return;
|
||||
}
|
||||
|
||||
registry.addImportDirective(this, _Visitor(this));
|
||||
}
|
||||
}
|
||||
|
||||
class _Visitor extends SimpleAstVisitor<void> {
|
||||
_Visitor(this.rule);
|
||||
|
||||
final AnalysisRule rule;
|
||||
|
||||
@override
|
||||
void visitImportDirective(ImportDirective node) {
|
||||
final uriString = node.uri.stringValue;
|
||||
if (uriString == null || !uriString.startsWith("package:")) {
|
||||
return;
|
||||
}
|
||||
|
||||
final pathWithoutScheme = uriString.replaceFirst("package:", "");
|
||||
final packageName = pathWithoutScheme.split("/").first;
|
||||
|
||||
if (RestrictedImportsRule._restrictedPackages.contains(packageName)) {
|
||||
rule.reportAtNode(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
name: cw_custom_lints
|
||||
version: 0.0.1
|
||||
environment:
|
||||
sdk: '>=3.9.0 <4.0.0'
|
||||
|
||||
|
||||
dependencies:
|
||||
analysis_server_plugin: 0.3.15
|
||||
analyzer: 13.0.0
|
||||
analyzer_plugin: 0.14.9
|
||||
|
||||
dev_dependencies:
|
||||
analyzer_testing: 0.2.6
|
||||
test_reflective_loader: 0.4.0
|
||||
test: 1.31.2
|
||||
@@ -1,4 +0,0 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -1,4 +0,0 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -1,4 +0,0 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -1,4 +0,0 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -1,4 +0,0 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -6,7 +6,7 @@ author: Cake Wallet
|
||||
homepage: https://cakewallet.com
|
||||
|
||||
environment:
|
||||
sdk: '>=2.18.2 <3.0.0'
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
dependencies:
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -1,4 +0,0 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -1,4 +0,0 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -5,7 +5,7 @@ publish_to: none
|
||||
homepage: https://cakewallet.com
|
||||
|
||||
environment:
|
||||
sdk: ">=2.19.0 <3.0.0"
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
flutter: ">=1.20.0"
|
||||
|
||||
dependencies:
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
analyzer:
|
||||
errors:
|
||||
implementation_imports: ignore
|
||||
must_be_immutable: ignore
|
||||
overridden_fields: ignore
|
||||
exclude:
|
||||
- "**.g.dart"
|
||||
- "external/**"
|
||||
|
||||
linter:
|
||||
rules:
|
||||
unawaited_futures: true
|
||||
avoid_print: false
|
||||
parameter_assignments: true
|
||||
prefer_const_declarations: true
|
||||
prefer_final_fields: true
|
||||
prefer_final_in_for_each: true
|
||||
prefer_final_locals: true
|
||||
prefer_final_parameters: true
|
||||
avoid_void_async: true
|
||||
require_trailing_commas: true
|
||||
sort_child_properties_last: true
|
||||
sort_constructors_first: true
|
||||
sort_unnamed_constructors_first: true
|
||||
unnecessary_async: true
|
||||
unnecessary_await_in_return: true
|
||||
unnecessary_string_interpolations: true
|
||||
always_declare_return_types: true
|
||||
|
||||
formatter:
|
||||
page_width: 100
|
||||
@@ -177,7 +177,7 @@ class CWBitcoin extends Bitcoin {
|
||||
List<ElectrumSubAddress> getSubAddresses(Object wallet) {
|
||||
final electrumWallet = wallet as ElectrumWallet;
|
||||
return electrumWallet.walletAddresses.addressesByReceiveType
|
||||
.map((BaseBitcoinAddressRecord addr) => ElectrumSubAddress(
|
||||
.map<ElectrumSubAddress>((addr) => ElectrumSubAddress(
|
||||
id: addr.index,
|
||||
name: addr.name,
|
||||
address: addr.address,
|
||||
|
||||
+22
-10
@@ -1,17 +1,29 @@
|
||||
#!/bin/bash
|
||||
set -x -e
|
||||
cd $(dirname $0)
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
cd ..
|
||||
|
||||
for i in cw_zcash;
|
||||
for i in cw_bitcoin cw_bitcoin_cash cw_core cw_decred cw_dogecoin cw_evm cw_monero cw_mweb cw_nano cw_solana cw_tron cw_zano cw_zcash lib;
|
||||
do
|
||||
dart fix --apply $i/
|
||||
dart format --line-length=100 $i/
|
||||
if [[ ! "x$ABORT_ON_CHANGE" == "x" ]];
|
||||
then
|
||||
if [[ ! -z "$(git status --porcelain -- $(find $i))" ]];
|
||||
then
|
||||
echo "Please run scripts/lint.sh ($i has changes)"
|
||||
{
|
||||
# files modified after the lints got enabled and committed
|
||||
git log --since="2026-07-14 23:59:59" --name-only --diff-filter=d --format="" -- "$i"
|
||||
# uncommitted files (assumed to have been modified after the 29th)
|
||||
git diff --name-only --diff-filter=d HEAD -- "$i"
|
||||
} | grep '\.dart$' | sort -u | while IFS= read -r file; do
|
||||
echo $file
|
||||
if [[ -f "$file" ]]; then
|
||||
dart fix --apply "$file" && dart format --line-length=100 "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -n "$ABORT_ON_CHANGE" ]]; then
|
||||
DART_CHANGES=$(git status --porcelain -- "$i" | grep '\.dart$' || true)
|
||||
|
||||
if [[ -n "$DART_CHANGES" ]]; then
|
||||
echo "Please run scripts/lint.sh"
|
||||
echo "changes in $i:"
|
||||
echo "$DART_CHANGES"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -15,7 +15,7 @@ void main(List<String> args) async {
|
||||
final text = args[1];
|
||||
final force = args.last == "--force";
|
||||
|
||||
printV('Appending "$name": "$text"');
|
||||
print('Appending "$name": "$text"');
|
||||
|
||||
// add translation to all languages:
|
||||
for (var lang in langs) {
|
||||
@@ -25,12 +25,12 @@ void main(List<String> args) async {
|
||||
appendStringToArbFile(fileName, name, translation, force: force);
|
||||
}
|
||||
|
||||
printV('Alphabetizing all files...');
|
||||
print('Alphabetizing all files...');
|
||||
|
||||
for (var lang in langs) {
|
||||
final fileName = getArbFileName(lang);
|
||||
alphabetizeArbFile(fileName);
|
||||
}
|
||||
|
||||
printV('Done!');
|
||||
print('Done!');
|
||||
}
|
||||
@@ -31,7 +31,7 @@ Future<void> main() async {
|
||||
final resp = await _dio.get("https://api.github.com/repos/mrcyjanek/monero_c/releases");
|
||||
final data = resp.data[0];
|
||||
final tagName = data['tag_name'];
|
||||
printV("Downloading artifacts for: ${tagName}");
|
||||
print("Downloading artifacts for: ${tagName}");
|
||||
final assets = data['assets'] as List<dynamic>;
|
||||
for (var i = 0; i < assets.length; i++) {
|
||||
for (var triplet in triplets) {
|
||||
@@ -42,10 +42,10 @@ Future<void> main() async {
|
||||
String localFilename = filename.replaceAll("${coin}_${triplet}_", "");
|
||||
localFilename = "scripts/monero_c/release/${coin}/${triplet}_${localFilename}";
|
||||
final url = asset["browser_download_url"] as String;
|
||||
printV("- downloading $localFilename");
|
||||
print("- downloading $localFilename");
|
||||
await _dio.download(url, localFilename);
|
||||
if (localFilename.endsWith(".xz")) {
|
||||
printV(" extracting $localFilename");
|
||||
print(" extracting $localFilename");
|
||||
final inputStream = InputFileStream(localFilename);
|
||||
final archive = XZDecoder().decodeBytes(inputStream.toUint8List());
|
||||
final outputStream = OutputFileStream(localFilename.replaceAll(".xz", ""));
|
||||
@@ -54,11 +54,11 @@ Future<void> main() async {
|
||||
}
|
||||
}
|
||||
if (Platform.isMacOS) {
|
||||
printV("Generating ios framework");
|
||||
print("Generating ios framework");
|
||||
final result = Process.runSync("bash", [
|
||||
"-c",
|
||||
"cd scripts/ios && ./gen_framework.sh && cd ../.."
|
||||
]);
|
||||
printV((result.stdout+result.stderr).toString().trim());
|
||||
print((result.stdout+result.stderr).toString().trim());
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ void main() {
|
||||
// --- B. Run App in a Zone to Capture Prints ---
|
||||
runZoned(
|
||||
() async {
|
||||
printV('--- Starting Verified Price Check ---');
|
||||
print('--- Starting Verified Price Check ---');
|
||||
|
||||
final Map<String, List<String>> workingPairs = {};
|
||||
final Map<String, List<String>> failedPairs = {};
|
||||
@@ -130,7 +130,7 @@ void main() {
|
||||
}
|
||||
|
||||
// Print immediate status (Captured by Zone)
|
||||
printV('$logPrefix $logMessage');
|
||||
print('$logPrefix $logMessage');
|
||||
|
||||
// Aggregate
|
||||
if (isSuccess) {
|
||||
@@ -148,25 +148,25 @@ void main() {
|
||||
}
|
||||
|
||||
// --- FINAL SUMMARY ---
|
||||
printV('\n\n=== SUMMARY ===\n');
|
||||
print('\n\n=== SUMMARY ===\n');
|
||||
|
||||
// Print Successful
|
||||
workingPairs.forEach((crypto, fiats) {
|
||||
if (fiats.isNotEmpty) {
|
||||
printV('✅ ${crypto.toUpperCase()}: ${fiats.join(", ")}');
|
||||
print('✅ ${crypto.toUpperCase()}: ${fiats.join(", ")}');
|
||||
}
|
||||
});
|
||||
|
||||
printV('\n--------------------------------------------------\n');
|
||||
print('\n--------------------------------------------------\n');
|
||||
|
||||
// Print Failed
|
||||
failedPairs.forEach((crypto, fiats) {
|
||||
if (fiats.isNotEmpty) {
|
||||
printV('❌ ${crypto.toUpperCase()}: ${fiats.join(", ")}');
|
||||
print('❌ ${crypto.toUpperCase()}: ${fiats.join(", ")}');
|
||||
}
|
||||
});
|
||||
|
||||
printV('\n=== DONE ===');
|
||||
print('\n=== DONE ===');
|
||||
},
|
||||
|
||||
// --- C. The Interceptor ---
|
||||
|
||||
@@ -37,7 +37,7 @@ Future<void> main(List<String> args) async {
|
||||
|
||||
extraInfo.forEach((key, dynamic value) async {
|
||||
if (key != srcDir) {
|
||||
printV('Wrong key: $key');
|
||||
print('Wrong key: $key');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ Future<void> main(List<String> args) async {
|
||||
final dir = Directory(dirPath);
|
||||
|
||||
if (!await dir.exists()) {
|
||||
printV('Wrong directory path: $dirPath');
|
||||
print('Wrong directory path: $dirPath');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ Future<void> main(List<String> args) async {
|
||||
// normalizing the case so keys match LanguageService.supportedLocales.
|
||||
final fileName = element.uri.pathSegments.last;
|
||||
if (!fileName.startsWith('strings_') || !fileName.endsWith('.arb')) {
|
||||
printV('Wrong file: ${element.path}');
|
||||
print('Wrong file: ${element.path}');
|
||||
return;
|
||||
}
|
||||
final parts =
|
||||
@@ -67,7 +67,7 @@ Future<void> main(List<String> args) async {
|
||||
});
|
||||
|
||||
if (!localePath.keys.contains(defaultLocale)) {
|
||||
printV("Locale list doesn't contain $defaultLocale");
|
||||
print("Locale list doesn't contain $defaultLocale");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ Future<void> main(List<String> args) async {
|
||||
|
||||
await File(outputPath + localeListFileName).writeAsString(locales);
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
print(e.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
void printV(dynamic content) => print(content);
|
||||
@@ -46,7 +46,7 @@ void main() async {
|
||||
});
|
||||
|
||||
currentItem++;
|
||||
printV(
|
||||
print(
|
||||
"\r$currentLang/${langs.length} langs done, $currentItem/${defaultLangChangelog.length} items done");
|
||||
}
|
||||
currentLang++;
|
||||
|
||||
@@ -25,18 +25,18 @@ class TranslationChecker {
|
||||
final sourceMap = json.decode(sourceContent) as Map<String, dynamic>;
|
||||
final destinationMap = json.decode(destinationContent) as Map<String, dynamic>;
|
||||
|
||||
printV('Found ${sourceMap.length} keys in source, ${destinationMap.length} in destination');
|
||||
print('Found ${sourceMap.length} keys in source, ${destinationMap.length} in destination');
|
||||
|
||||
final keysToProcess = specificKey != null
|
||||
? (sourceMap.containsKey(specificKey) ? [specificKey] : <String>[])
|
||||
: sourceMap.keys.toList();
|
||||
|
||||
if (specificKey != null && keysToProcess.isEmpty) {
|
||||
printV('Error: Key "$specificKey" not found in source file');
|
||||
print('Error: Key "$specificKey" not found in source file');
|
||||
return;
|
||||
}
|
||||
|
||||
printV('Processing ${keysToProcess.length} translations...');
|
||||
print('Processing ${keysToProcess.length} translations...');
|
||||
|
||||
int processed = 0;
|
||||
int corrected = 0;
|
||||
@@ -57,16 +57,16 @@ class TranslationChecker {
|
||||
if (correctedTranslation != destinationValue) {
|
||||
destinationMap[key] = correctedTranslation;
|
||||
corrected++;
|
||||
printV('Processed: "$key" -> CORRECTED');
|
||||
printV(' - eng : "$sourceValue"');
|
||||
printV(' - dst orig: "$destinationValue"');
|
||||
printV(' - dst new : "$correctedTranslation"');
|
||||
print('Processed: "$key" -> CORRECTED');
|
||||
print(' - eng : "$sourceValue"');
|
||||
print(' - dst orig: "$destinationValue"');
|
||||
print(' - dst new : "$correctedTranslation"');
|
||||
await _writeArbFile(destinationArbPath, destinationMap);
|
||||
} else {
|
||||
printV('Processed: "$key" -> VERIFIED');
|
||||
print('Processed: "$key" -> VERIFIED');
|
||||
}
|
||||
} else {
|
||||
printV('Processed: "$key" -> SKIPPED (non-string)');
|
||||
print('Processed: "$key" -> SKIPPED (non-string)');
|
||||
}
|
||||
|
||||
processed++;
|
||||
@@ -74,11 +74,11 @@ class TranslationChecker {
|
||||
|
||||
await _writeArbFile(destinationArbPath, destinationMap);
|
||||
|
||||
printV('');
|
||||
printV('Summary:');
|
||||
printV('Processed: $processed keys');
|
||||
printV('Corrected: $corrected keys');
|
||||
printV('Updated: $destinationArbPath');
|
||||
print('');
|
||||
print('Summary:');
|
||||
print('Processed: $processed keys');
|
||||
print('Corrected: $corrected keys');
|
||||
print('Updated: $destinationArbPath');
|
||||
}
|
||||
|
||||
Future<String> _checkSingleTranslation({
|
||||
@@ -108,7 +108,7 @@ class TranslationChecker {
|
||||
|
||||
return currentTranslation;
|
||||
} catch (e) {
|
||||
printV('Error checking translation for key "$key": $e');
|
||||
print('Error checking translation for key "$key": $e');
|
||||
return currentTranslation;
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,7 @@ IMPORTANT: Respond with a JSON object in the exact format, you must think about
|
||||
final jsonEnd = response.lastIndexOf('}');
|
||||
|
||||
if (jsonStart == -1 || jsonEnd == -1 || jsonStart >= jsonEnd) {
|
||||
printV('No valid JSON found in LLM response');
|
||||
print('No valid JSON found in LLM response');
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ IMPORTANT: Respond with a JSON object in the exact format, you must think about
|
||||
|
||||
return parsed['corrected_translation'] as String?;
|
||||
} catch (e) {
|
||||
printV('Error extracting JSON from LLM response: $e');
|
||||
print('Error extracting JSON from LLM response: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -228,7 +228,7 @@ void main(List<String> args) async {
|
||||
final results = parser.parse(args);
|
||||
|
||||
if (results['help'] as bool) {
|
||||
printV(parser.usage);
|
||||
print(parser.usage);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -239,24 +239,24 @@ void main(List<String> args) async {
|
||||
final model = results['model'] as String;
|
||||
|
||||
if (!File(sourcePath).existsSync()) {
|
||||
printV('Error: Source ARB file not found: $sourcePath');
|
||||
print('Error: Source ARB file not found: $sourcePath');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!File(destinationPath).existsSync()) {
|
||||
printV('Error: Destination ARB file not found: $destinationPath');
|
||||
print('Error: Destination ARB file not found: $destinationPath');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printV('Translation Checker');
|
||||
printV('Source: $sourcePath');
|
||||
printV('Destination: $destinationPath');
|
||||
printV('Ollama URL: $ollamaUrl');
|
||||
printV('Model: $model');
|
||||
print('Translation Checker');
|
||||
print('Source: $sourcePath');
|
||||
print('Destination: $destinationPath');
|
||||
print('Ollama URL: $ollamaUrl');
|
||||
print('Model: $model');
|
||||
if (specificKey != null) {
|
||||
printV('Key: $specificKey');
|
||||
print('Key: $specificKey');
|
||||
}
|
||||
printV('');
|
||||
print('');
|
||||
|
||||
final checker = TranslationChecker(
|
||||
ollamaBaseUrl: ollamaUrl,
|
||||
@@ -270,8 +270,8 @@ void main(List<String> args) async {
|
||||
);
|
||||
|
||||
} catch (e) {
|
||||
printV('Error: $e');
|
||||
printV('Run with --help for more information.');
|
||||
print('Error: $e');
|
||||
print('Run with --help for more information.');
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,5 +34,5 @@ void main(List<String> args) async {
|
||||
}
|
||||
|
||||
appendStringsToArbFile(targetFileName, translations);
|
||||
printV("Success! Please add your Language Code to lib/entities/language_service.dart");
|
||||
print("Success! Please add your Language Code to lib/entities/language_service.dart");
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@ import 'utils/translation/translation_constants.dart';
|
||||
import 'utils/translation/translation_utils.dart';
|
||||
|
||||
void main(List<String> args) async {
|
||||
printV('Checking Consistency of all arb-files. Default: $defaultLang');
|
||||
print('Checking Consistency of all arb-files. Default: $defaultLang');
|
||||
|
||||
final doFix = args.contains("--fix");
|
||||
|
||||
if (doFix)
|
||||
printV('Auto fixing enabled!\n');
|
||||
print('Auto fixing enabled!\n');
|
||||
else
|
||||
printV('Auto fixing disabled!\nRun with arg "--fix" to enable autofix\n');
|
||||
print('Auto fixing disabled!\nRun with arg "--fix" to enable autofix\n');
|
||||
|
||||
final fileName = getArbFileName(defaultLang);
|
||||
final file = File(fileName);
|
||||
@@ -27,7 +27,7 @@ void main(List<String> args) async {
|
||||
final missingDefaults = <String, String>{};
|
||||
|
||||
missingKeys.forEach((key) {
|
||||
printV('Missing in "$lang": "$key"');
|
||||
print('Missing in "$lang": "$key"');
|
||||
if (doFix)
|
||||
missingDefaults[key] = arbObj[key] as String;
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ void appendStringToArbFile(String fileName, String name, String text, {bool forc
|
||||
final arbObj = readArbFile(file);
|
||||
|
||||
if (arbObj.containsKey(name) && !force) {
|
||||
printV("String $name already exists in $fileName!");
|
||||
print("String $name already exists in $fileName!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ Future<String> getTranslation(String text, String lang) async {
|
||||
try {
|
||||
translation = (await translator.translate(text, from: defaultLang, to: lang)).text;
|
||||
} catch (e) {
|
||||
printV("$lang, $text, $e");
|
||||
print("$lang, $text, $e");
|
||||
}
|
||||
placeholder.forEach((index, value) {
|
||||
final translatedPlaceholder = regExp.allMatches(translation).toList()[index];
|
||||
|
||||
Reference in New Issue
Block a user