|  | // Copyright (c) 2020, 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:convert'; | 
|  | import 'dart:io'; | 
|  |  | 
|  | import 'package:analyzer/src/lint/registry.dart'; | 
|  | import 'package:analyzer/src/lint/state.dart'; | 
|  | import 'package:args/args.dart'; | 
|  | import 'package:linter/src/analyzer.dart'; | 
|  | import 'package:linter/src/rules.dart'; | 
|  | import 'package:linter/src/utils.dart'; | 
|  | import 'package:yaml/yaml.dart'; | 
|  |  | 
|  | import '../tool/util/path_utils.dart'; | 
|  | import 'since.dart'; | 
|  | import 'util/score_utils.dart' as score_utils; | 
|  |  | 
|  | /// Generates a list of lint rules in machine format suitable for consumption by | 
|  | /// other tools. | 
|  | void main(List<String> args) async { | 
|  | var parser = ArgParser() | 
|  | ..addFlag('write', abbr: 'w', help: 'Write `rules.json` file.') | 
|  | ..addFlag('pretty', | 
|  | abbr: 'p', help: 'Pretty-print output.', defaultsTo: true) | 
|  | ..addFlag('sets', abbr: 's', help: 'Include rule sets', defaultsTo: true); | 
|  | var options = parser.parse(args); | 
|  |  | 
|  | var json = await generateRulesJson( | 
|  | pretty: options['pretty'] == true, | 
|  | includeSetInfo: options['sets'] == true); | 
|  |  | 
|  | if (options['write'] == true) { | 
|  | var outFile = machineJsonFile(); | 
|  | printToConsole('Writing to ${outFile.path}'); | 
|  | outFile.writeAsStringSync(json); | 
|  | } else { | 
|  | printToConsole(json); | 
|  | } | 
|  | } | 
|  |  | 
|  | Future<String> generateRulesJson({ | 
|  | bool pretty = true, | 
|  | bool includeSetInfo = true, | 
|  | }) async { | 
|  | registerLintRules(); | 
|  | var fixStatusMap = readFixStatusMap(); | 
|  | return await getMachineListing(Registry.ruleRegistry, | 
|  | fixStatusMap: fixStatusMap, sinceInfo: sinceMap, pretty: pretty); | 
|  | } | 
|  |  | 
|  | Future<String> getMachineListing( | 
|  | Iterable<LintRule> ruleRegistry, { | 
|  | Map<String, String>? fixStatusMap, | 
|  | bool pretty = true, | 
|  | bool includeSetInfo = true, | 
|  | Map<String, SinceInfo>? sinceInfo, | 
|  | }) async { | 
|  | var rules = List<LintRule>.of(ruleRegistry, growable: false) | 
|  | ..sort((a, b) => a.name.compareTo(b.name)); | 
|  | var encoder = pretty ? JsonEncoder.withIndent('  ') : JsonEncoder(); | 
|  | fixStatusMap ??= {}; | 
|  |  | 
|  | var ( | 
|  | coreRules: coreRules, | 
|  | recommendedRules: recommendedRules, | 
|  | flutterRules: flutterRules | 
|  | ) = await _fetchSetRules(fetch: includeSetInfo); | 
|  |  | 
|  | var json = encoder.convert([ | 
|  | for (var rule in rules.where((rule) => !rule.state.isInternal)) | 
|  | { | 
|  | 'name': rule.name, | 
|  | 'description': rule.description, | 
|  | 'categories': rule.categories.toList(), | 
|  | 'group': rule.categories.firstOrNull ?? '', | 
|  | 'state': rule.state.label, | 
|  | 'incompatible': rule.incompatibleRules, | 
|  | 'sets': [ | 
|  | if (coreRules.contains(rule.name)) 'core', | 
|  | if (recommendedRules.contains(rule.name)) 'recommended', | 
|  | if (flutterRules.contains(rule.name)) 'flutter', | 
|  | ], | 
|  | 'fixStatus': fixStatusMap[rule.name] ?? 'unregistered', | 
|  | 'details': rule.details, | 
|  | if (sinceInfo != null) | 
|  | 'sinceDartSdk': sinceInfo[rule.name]?.sinceDartSdk ?? 'Unreleased', | 
|  | } | 
|  | ]); | 
|  | return json; | 
|  | } | 
|  |  | 
|  | File machineJsonFile() { | 
|  | var outPath = pathRelativeToPackageRoot(['tool', 'machine', 'rules.json']); | 
|  | return File(outPath); | 
|  | } | 
|  |  | 
|  | Map<String, String> readFixStatusMap() { | 
|  | var statusFilePath = pathRelativeToPkgDir([ | 
|  | 'analysis_server', | 
|  | 'lib', | 
|  | 'src', | 
|  | 'services', | 
|  | 'correction', | 
|  | 'error_fix_status.yaml' | 
|  | ]); | 
|  | var contents = File(statusFilePath).readAsStringSync(); | 
|  |  | 
|  | var yaml = loadYamlNode(contents) as YamlMap; | 
|  | var fixStatusMap = <String, String>{}; | 
|  | for (var entry in yaml.entries) { | 
|  | var code = entry.key as String; | 
|  | if (code.startsWith('LintCode.')) { | 
|  | fixStatusMap[code.substring(9)] = | 
|  | (entry.value as YamlMap)['status'] as String; | 
|  | } | 
|  | } | 
|  | return fixStatusMap; | 
|  | } | 
|  |  | 
|  | Future< | 
|  | ({ | 
|  | Set<String> coreRules, | 
|  | Set<String> recommendedRules, | 
|  | Set<String> flutterRules, | 
|  | })> _fetchSetRules({bool fetch = true}) async { | 
|  | if (!fetch) { | 
|  | return const ( | 
|  | coreRules: <String>{}, | 
|  | recommendedRules: <String>{}, | 
|  | flutterRules: <String>{}, | 
|  | ); | 
|  | } | 
|  |  | 
|  | var coreRules = {...await score_utils.coreRules}; | 
|  | var recommendedRules = {...coreRules, ...await score_utils.recommendedRules}; | 
|  | var flutterRules = {...recommendedRules, ...await score_utils.flutterRules}; | 
|  |  | 
|  | return ( | 
|  | coreRules: coreRules, | 
|  | recommendedRules: recommendedRules, | 
|  | flutterRules: flutterRules, | 
|  | ); | 
|  | } |