From 8445bd74a50f9002facffa8299578b12888941d9 Mon Sep 17 00:00:00 2001 From: pq Date: Fri, 4 Jan 2019 07:49:28 -0800 Subject: [PATCH 1/4] since linter scoring --- tool/crawl.dart | 78 ++++++++++++++++++++++++++ tool/scorecard.dart | 12 +++- tool/since.dart | 47 ++++++++++++++++ tool/since.yaml | 134 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 268 insertions(+), 3 deletions(-) create mode 100644 tool/since.dart create mode 100644 tool/since.yaml diff --git a/tool/crawl.dart b/tool/crawl.dart index 4c2aebd45..370a47285 100644 --- a/tool/crawl.dart +++ b/tool/crawl.dart @@ -2,8 +2,18 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'dart:io'; + import 'package:analyzer/src/lint/config.dart'; +import 'package:analyzer/src/lint/registry.dart'; import 'package:http/http.dart' as http; +import 'package:linter/src/analyzer.dart'; +import 'package:linter/src/rules.dart'; +import 'package:yaml/yaml.dart'; + +const _allPathSuffix = '/example/all.yaml'; +const _repoPathPrefix = 'https://raw.githubusercontent.com/dart-lang/linter/'; +const _rulePathPrefix = 'https://raw.githubusercontent.com/dart-lang/linter'; const _flutterOptionsUrl = 'https://raw.githubusercontent.com/flutter/flutter/master/packages/flutter/lib/analysis_options_user.yaml'; @@ -14,6 +24,10 @@ const _pedanticOptionsUrl = const _stagehandOptionsUrl = 'https://raw.githubusercontent.com/dart-lang/stagehand/master/templates/analysis_options.yaml'; +int _latestMinor; + +Map> _sinceMap = >{}; + List _flutterRules; List _flutterRepoRules; List _pedanticRules; @@ -31,6 +45,70 @@ Future> get pedanticRules async => Future> get stagehandRules async => _stagehandRules ??= await _fetchRules(_stagehandOptionsUrl); +Future get latestMinor async => + _latestMinor ??= await _readLatestMinorVersion(); + +Iterable _registeredLints; + +Iterable get registeredLints { + if (_registeredLints == null) { + registerLintRules(); + _registeredLints = Registry.ruleRegistry; + } + return _registeredLints; +} + +Future findSinceLinter(LintRule lint) async { + // History recorded in `all.yaml` starts in minor 31. + var rules_31 = await rulesForVersion(31); + if (rules_31.contains(lint.name)) { + var version = await _crawlForVersion(lint); + if (version != null) { + return version; + } + } + + var latest = await latestMinor; + for (var minor = 31; minor <= latest; ++minor) { + var rules = await rulesForVersion(minor); + if (rules != null) { + if (rules.contains(lint.name)) { + return '0.1.$minor'; + } + } + } + + return null; +} + +Future _readLatestMinorVersion() async { + var contents = await new File('pubspec.yaml').readAsString(); + YamlMap pubspec = loadYamlNode(contents); + return int.parse(pubspec['version'].split('.').last); +} + +Future _crawlForVersion(LintRule lint) async { + var client = new http.Client(); + for (int minor = 1; minor < 31; ++minor) { + var version = '0.1.$minor'; + var req = await client + .get('$_rulePathPrefix/$version/lib/src/rules/${lint.name}.dart'); + if (req.statusCode == 200) { + return version; + } + } + return null; +} + +Future> rulesForVersion(int minor) async { + var version = '0.1.$minor'; + if (minor >= 31) { + return _sinceMap[version] ??= + await _fetchRules('$_repoPathPrefix$version$_allPathSuffix'); + } + return null; +} + Future _fetchConfig(String url) async { var client = new http.Client(); var req = await client.get(url); diff --git a/tool/scorecard.dart b/tool/scorecard.dart index 160efdfdf..a4a215f07 100644 --- a/tool/scorecard.dart +++ b/tool/scorecard.dart @@ -11,6 +11,7 @@ import 'package:linter/src/analyzer.dart'; import 'package:linter/src/rules.dart'; import 'crawl.dart'; +import 'since.dart'; const bulb = '💡'; const checkMark = '✅'; @@ -39,10 +40,11 @@ void printAll(ScoreCard scorecard) { void printMarkdownTable(ScoreCard scorecard) { print( - '| name | fix | flutter user | flutter repo | pedantic | stagehand | status | bug refs |'); - print('| :--- | :---: | :---:| :---: | :---: | :---: | :---: | :--- |'); + '| name | since | fix | flutter user | flutter repo | pedantic | stagehand | status | bug refs |'); + print('| :--- | :---: | :---: | :---:| :---: | :---: | :---: | :---: | :--- |'); scorecard.forEach((lint) { var sb = StringBuffer('| `${lint.name}` |'); + sb.write(' ${lint.since.sinceLinter} |'); sb.write('${lint.hasFix ? " $bulb" : ""} |'); sb.write('${lint.ruleSets.contains('flutter') ? " $checkMark" : ""} |'); sb.write( @@ -100,6 +102,7 @@ class ScoreCard { var issues = await _getIssues(); var bugs = issues.where(_isBug).toList(); + var sinceInfo = await sinceMap; var scorecard = ScoreCard(); for (var lint in registeredLints) { @@ -128,6 +131,7 @@ class ScoreCard { hasFix: lintsWithFixes.contains(lint.name), maturity: lint.maturity.name, ruleSets: ruleSets, + since: sinceInfo[lint.name], bugReferences: bugReferences)); } @@ -141,6 +145,7 @@ class LintScore { String name; bool hasFix; String maturity; + SinceInfo since; List ruleSets; List bugReferences; @@ -150,7 +155,8 @@ class LintScore { this.hasFix, this.maturity, this.ruleSets, - this.bugReferences}); + this.bugReferences, + this.since}); String get _ruleSets => ruleSets.isNotEmpty ? ' ${ruleSets.toString()}' : ''; diff --git a/tool/since.dart b/tool/since.dart new file mode 100644 index 000000000..44c819263 --- /dev/null +++ b/tool/since.dart @@ -0,0 +1,47 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:yaml/yaml.dart'; + +import 'crawl.dart'; + +main() async { + // Print for caching in since.yaml. +// for (var lint in registeredLints) { +// var since = await findSinceLinter(lint); +// if (since != null) { +// print('${lint.name}: $since'); +// } +// } + + await sinceMap.then((m) => m.entries.forEach(print)); +} + +Map _sinceMap; + +Future> get sinceMap async => + _sinceMap ??= await _getSinceInfo(); + +Future> _getSinceInfo() async { + var cache = await new File('tool/since.yaml').readAsString(); + YamlMap yaml = loadYamlNode(cache); + Map sinceMap = {}; + for (var lint in registeredLints) { + var linterVersion = yaml[lint.name]; + sinceMap[lint.name] = + new SinceInfo(linterVersion ?? await findSinceLinter(lint)); + } + return sinceMap; +} + +class SinceInfo { + // todo (pq): add sinceSdk + String sinceLinter; + SinceInfo(this.sinceLinter); + + @override + String toString() => 'linter: $sinceLinter'; +} diff --git a/tool/since.yaml b/tool/since.yaml new file mode 100644 index 000000000..321952fd9 --- /dev/null +++ b/tool/since.yaml @@ -0,0 +1,134 @@ +always_declare_return_types: 0.1.4 +always_put_control_body_on_new_line: 0.1.31 +always_put_required_named_parameters_first: 0.1.33 +always_require_non_null_named_parameters: 0.1.31 +always_specify_types: 0.1.4 +annotate_overrides: 0.1.11 +avoid_annotating_with_dynamic: 0.1.31 +avoid_bool_literals_in_conditional_expressions: 0.1.46 +avoid_types_on_closure_parameters: 0.1.31 +avoid_as: 0.1.5 +avoid_catching_errors: 0.1.31 +avoid_catches_without_on_clauses: 0.1.31 +avoid_classes_with_only_static_members: 0.1.31 +avoid_double_and_int_checks: 0.1.47 +avoid_empty_else: 0.1.8 +avoid_field_initializers_in_const_classes: 0.1.48 +avoid_function_literals_in_foreach_calls: 0.1.30 +avoid_implementing_value_types: 0.1.62 +avoid_init_to_null: 0.1.11 +avoid_js_rounded_ints: 0.1.48 +avoid_null_checks_in_equality_operators: 0.1.31 +avoid_positional_boolean_parameters: 0.1.31 +avoid_private_typedef_functions: 0.1.46 +avoid_relative_lib_imports: 0.1.44 +avoid_renaming_method_parameters: 0.1.45 +avoid_returning_null: 0.1.31 +avoid_returning_null_for_future: 0.1.72 +avoid_returning_null_for_void: 0.1.69 +avoid_return_types_on_setters: 0.1.11 +avoid_returning_this: 0.1.31 +avoid_setters_without_getters: 0.1.31 +avoid_shadowing_type_parameters: 0.1.72 +avoid_single_cascade_in_expression_statements: 0.1.46 +avoid_slow_async_io: 0.1.30 +avoid_types_as_parameter_names: 0.1.45 +avoid_unused_constructor_parameters: 0.1.36 +avoid_void_async: 0.1.60 +await_only_futures: 0.1.16 +camel_case_types: 0.1.1 +cancel_subscriptions: 0.1.20 +cascade_invocations: 0.1.29 +close_sinks: 0.1.19 +comment_references: 0.1.17 +control_flow_in_finally: 0.1.16 +constant_identifier_names: 0.1.1 +curly_braces_in_flow_control_structures: 0.1.57 +directives_ordering: 0.1.30 +empty_catches: 0.1.22 +empty_constructor_bodies: 0.1.1 +empty_statements: 0.1.21 +file_names: 0.1.54 +flutter_style_todos: 0.1.61 +hash_and_equals: 0.1.11 +implementation_imports: 0.1.4 +invariant_booleans: 0.1.25 +iterable_contains_unrelated_type: 0.1.17 +join_return_with_assignment: 0.1.31 +library_names: 0.1.1 +library_prefixes: 0.1.1 +lines_longer_than_80_chars: 0.1.56 +list_remove_unrelated_type: 0.1.22 +literal_only_boolean_expressions: 0.1.25 +no_adjacent_strings_in_list: 0.1.30 +no_duplicate_case_values: 0.1.30 +non_constant_identifier_names: 0.1.1 +null_closures: 0.1.56 +one_member_abstracts: 0.1.1 +omit_local_variable_types: 0.1.30 +only_throw_errors: 0.1.21 +overridden_fields: 0.1.18 +package_api_docs: 0.1.1 +package_prefixed_library_names: 0.1.1 +parameter_assignments: 0.1.27 +prefer_adjacent_string_concatenation: 0.1.30 +prefer_bool_in_asserts: 0.1.36 +prefer_collection_literals: 0.1.30 +prefer_conditional_assignment: 0.1.31 +prefer_const_constructors: 0.1.30 +prefer_const_constructors_in_immutables: 0.1.33 +prefer_const_declarations: 0.1.43 +prefer_const_literals_to_create_immutables: 0.1.43 +prefer_asserts_in_initializer_lists: 0.1.33 +prefer_constructors_over_static_methods: 0.1.31 +prefer_contains: 0.1.30 +prefer_equal_for_default_values: 0.1.46 +prefer_expression_function_bodies: 0.1.30 +prefer_final_fields: 0.1.27 +prefer_final_locals: 0.1.27 +prefer_foreach: 0.1.31 +prefer_function_declarations_over_variables: 0.1.30 +prefer_generic_function_type_aliases: 0.1.47 +prefer_initializing_formals: 0.1.30 +prefer_int_literals: 0.1.71 +prefer_interpolation_to_compose_strings: 0.1.30 +prefer_iterable_whereType: 0.1.47 +prefer_is_empty: 0.1.30 +prefer_is_not_empty: 0.1.5 +prefer_mixin: 0.1.62 +prefer_single_quotes: 0.1.33 +prefer_typing_uninitialized_variables: 0.1.36 +prefer_void_to_null: 0.1.59 +public_member_api_docs: 0.1.11 +package_names: 0.1.31 +recursive_getters: 0.1.30 +slash_for_doc_comments: 0.1.1 +sort_constructors_first: 0.1.11 +sort_pub_dependencies: 0.1.63 +sort_unnamed_constructors_first: 0.1.11 +super_goes_last: 0.1.1 +test_types_in_equals: 0.1.16 +throw_in_finally: 0.1.16 +type_annotate_public_apis: 0.1.5 +type_init_formals: 0.1.1 +unawaited_futures: 0.1.19 +unnecessary_await_in_return: 0.1.73 +unnecessary_brace_in_string_interps: 0.1.30 +unnecessary_const: 0.1.54 +unnecessary_new: 0.1.54 +unnecessary_null_aware_assignments: 0.1.30 +unnecessary_null_in_if_null_operators: 0.1.30 +unnecessary_getters_setters: 0.1.1 +unnecessary_lambdas: 0.1.30 +unnecessary_overrides: 0.1.31 +unnecessary_parenthesis: 0.1.44 +unnecessary_statements: 0.1.36 +unnecessary_this: 0.1.30 +unrelated_type_equality_checks: 0.1.16 +use_function_type_syntax_for_parameters: 0.1.72 +use_rethrow_when_possible: 0.1.31 +use_setters_to_change_properties: 0.1.31 +use_string_buffers: 0.1.31 +use_to_and_as_if_applicable: 0.1.31 +valid_regexps: 0.1.22 +void_checks: 0.1.49 From 89e293a89d742f46e2ec45a605a551a375e9c342 Mon Sep 17 00:00:00 2001 From: pq Date: Fri, 4 Jan 2019 07:52:16 -0800 Subject: [PATCH 2/4] left-justify version strings --- tool/scorecard.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/scorecard.dart b/tool/scorecard.dart index a4a215f07..d0b69a111 100644 --- a/tool/scorecard.dart +++ b/tool/scorecard.dart @@ -41,7 +41,7 @@ void printAll(ScoreCard scorecard) { void printMarkdownTable(ScoreCard scorecard) { print( '| name | since | fix | flutter user | flutter repo | pedantic | stagehand | status | bug refs |'); - print('| :--- | :---: | :---: | :---:| :---: | :---: | :---: | :---: | :--- |'); + print('| :--- | :--- | :---: | :---:| :---: | :---: | :---: | :---: | :--- |'); scorecard.forEach((lint) { var sb = StringBuffer('| `${lint.name}` |'); sb.write(' ${lint.since.sinceLinter} |'); From d2658b8b61f0ac4945efe2b773ab01569507f1db Mon Sep 17 00:00:00 2001 From: pq Date: Fri, 4 Jan 2019 07:55:25 -0800 Subject: [PATCH 3/4] fmt --- tool/scorecard.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tool/scorecard.dart b/tool/scorecard.dart index d0b69a111..a0ce014dd 100644 --- a/tool/scorecard.dart +++ b/tool/scorecard.dart @@ -41,7 +41,8 @@ void printAll(ScoreCard scorecard) { void printMarkdownTable(ScoreCard scorecard) { print( '| name | since | fix | flutter user | flutter repo | pedantic | stagehand | status | bug refs |'); - print('| :--- | :--- | :---: | :---:| :---: | :---: | :---: | :---: | :--- |'); + print( + '| :--- | :--- | :---: | :---:| :---: | :---: | :---: | :---: | :--- |'); scorecard.forEach((lint) { var sb = StringBuffer('| `${lint.name}` |'); sb.write(' ${lint.since.sinceLinter} |'); From 38b2e3ae28cefad30297d38cc8df6d6a1fcb206f Mon Sep 17 00:00:00 2001 From: pq Date: Fri, 4 Jan 2019 09:32:59 -0800 Subject: [PATCH 4/4] update comment --- tool/since.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/since.dart b/tool/since.dart index 44c819263..1d3870e17 100644 --- a/tool/since.dart +++ b/tool/since.dart @@ -9,7 +9,7 @@ import 'package:yaml/yaml.dart'; import 'crawl.dart'; main() async { - // Print for caching in since.yaml. + // Uncomment to (re)generate since.yaml contents. // for (var lint in registeredLints) { // var since = await findSinceLinter(lint); // if (since != null) {