diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml deleted file mode 100644 index 04711c2a3..000000000 --- a/.github/workflows/gh-pages.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Deploy to GitHub Pages - -on: - push: - branches: - - main - -# Declare default permissions as read only. -permissions: read-all - -jobs: - build-and-deploy-docs: - permissions: - contents: write - runs-on: ubuntu-latest - if: github.repository == 'dart-lang/linter' - - steps: - - name: Checkout repository - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 - - name: Setup Dart - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f - with: - sdk: dev - - name: Get dependencies - run: dart pub get - - name: Generate docs - run: dart run tool/doc.dart --create-dirs --out lints - - name: Deploy docs - uses: peaceiris/actions-gh-pages@373f7f263a76c20808c831209c920827a82a2847 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_branch: gh-pages - publish_dir: lints - destination_dir: lints - keep_files: true diff --git a/README.md b/README.md index 7a1297336..7d33ca53e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ The Dart Linter package defines lint rules that identify and report on "lints" found in Dart code. Linting is performed by the Dart analysis server and the `dart analyze` command in the [Dart command-line tool][dart_cli]. -[![Lint Count](https://dart-lang.github.io/linter/lints/count-badge.svg)](https://dart-lang.github.io/linter/lints/) [![Build Status](https://github.com/dart-lang/linter/workflows/linter/badge.svg)](https://github.com/dart-lang/linter/actions) [![Coverage Status](https://coveralls.io/repos/dart-lang/linter/badge.svg)](https://coveralls.io/r/dart-lang/linter) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/dart-lang/linter/badge)](https://deps.dev/project/github/dart-lang%2Flinter) diff --git a/doc/writing-lints.md b/doc/writing-lints.md index fe9594597..8e2f28fc0 100644 --- a/doc/writing-lints.md +++ b/doc/writing-lints.md @@ -161,7 +161,6 @@ Details are under active development. Feedback is most [welcome][issues]! [lib/src/rules]: https://github.com/dart-lang/linter/tree/main/lib/src/rules [test_data/rules]: https://github.com/dart-lang/linter/tree/main/test_data/rules [rule.dart]: https://github.com/dart-lang/linter/blob/main/tool/rule.dart -[doc.dart]: https://github.com/dart-lang/linter/blob/main/tool/doc.dart [analyzer.dart utility library]: https://github.com/dart-lang/linter/blob/main/lib/src/analyzer.dart [implementation_imports]: https://dart.dev/lints/implementation_imports [Dart Language Specification]: https://dart.dev/guides/language/spec diff --git a/lib/src/util/score_utils.dart b/lib/src/util/score_utils.dart index 6690b41bd..143880c12 100644 --- a/lib/src/util/score_utils.dart +++ b/lib/src/util/score_utils.dart @@ -19,8 +19,7 @@ Future> _readRecommendedLints() async => _fetchLints( /// todo(pq): update `scorecard.dart` to reuse these fetch functions. Future> _fetchLints(String url) async { - var client = http.Client(); - var req = await client.get(Uri.parse(url)); + var req = await http.get(Uri.parse(url)); return _readLints(req.body); } diff --git a/test/doc_test.dart b/test/doc_test.dart index c6a658948..878c2f26d 100644 --- a/test/doc_test.dart +++ b/test/doc_test.dart @@ -4,7 +4,7 @@ import 'package:test/test.dart'; -import '../tool/doc.dart'; +import '../tool/machine.dart'; import 'util/test_utils.dart'; void main() { diff --git a/tool/doc.dart b/tool/doc.dart deleted file mode 100644 index 891911775..000000000 --- a/tool/doc.dart +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright (c) 2015, 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:async'; -import 'dart:io'; - -import 'package:analyzer/src/lint/config.dart'; -import 'package:analyzer/src/lint/registry.dart'; -import 'package:args/args.dart'; -import 'package:http/http.dart' as http; -import 'package:linter/src/analyzer.dart'; -import 'package:linter/src/rules.dart'; -import 'package:linter/src/utils.dart'; -import 'package:yaml/yaml.dart'; - -import 'machine.dart'; -import 'since.dart'; - -/// Generates lint rule docs for publishing to https://dart-lang.github.io/ -void main(List args) async { - var parser = ArgParser() - ..addOption('out', abbr: 'o', help: 'Specifies output directory.') - ..addFlag('create-dirs', - abbr: 'd', help: 'Enables creation of necessary directories.'); - - ArgResults options; - try { - options = parser.parse(args); - } on FormatException catch (err) { - printUsage(parser, err.message); - return; - } - - var outDir = options['out'] as String?; - - var createDirectories = options['create-dirs'] == true; - - await generateDocs(outDir, createDirectories: createDirectories); -} - -final coreRules = []; -final flutterRules = []; -final recommendedRules = []; - -final Map _fixStatusMap = {}; - -Future fetchBadgeInfo() async { - var core = await fetchConfig( - 'https://raw.githubusercontent.com/dart-lang/lints/main/lib/core.yaml'); - if (core != null) { - for (var ruleConfig in core.ruleConfigs) { - coreRules.add(ruleConfig.name); - } - } - - var recommended = await fetchConfig( - 'https://raw.githubusercontent.com/dart-lang/lints/main/lib/recommended.yaml'); - if (recommended != null) { - recommendedRules.addAll(coreRules); - for (var ruleConfig in recommended.ruleConfigs) { - recommendedRules.add(ruleConfig.name); - } - } - - var flutter = await fetchConfig( - 'https://raw.githubusercontent.com/flutter/packages/main/packages/flutter_lints/lib/flutter.yaml'); - if (flutter != null) { - flutterRules.addAll(recommendedRules); - for (var ruleConfig in flutter.ruleConfigs) { - flutterRules.add(ruleConfig.name); - } - } -} - -Future fetchConfig(String url) async { - var client = http.Client(); - printToConsole('loading $url...'); - var req = await client.get(Uri.parse(url)); - return processAnalysisOptionsFile(req.body); -} - -Future> fetchFixStatusMap() async { - if (_fixStatusMap.isNotEmpty) return _fixStatusMap; - var url = - 'https://raw.githubusercontent.com/dart-lang/sdk/main/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml'; - var client = http.Client(); - printToConsole('loading $url...'); - var req = await client.get(Uri.parse(url)); - var yaml = loadYamlNode(req.body) as YamlMap; - 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 generateDocs(String? dir, {bool createDirectories = false}) async { - var outDir = dir; - if (outDir != null) { - var d = Directory(outDir); - if (createDirectories) { - d.createSync(); - } - - if (!d.existsSync()) { - printToConsole("Directory '${d.path}' does not exist"); - return; - } - - if (!File('$outDir/options').existsSync()) { - var lintsChildDir = Directory('$outDir/lints'); - if (lintsChildDir.existsSync()) { - outDir = lintsChildDir.path; - } - } - - if (createDirectories) { - Directory('$outDir/machine').createSync(); - } - } - - registerLintRules(); - - // Generate lint count badge. - await CountBadger(Registry.ruleRegistry).generate(outDir); - - // Fetch info for lint group/style badge generation. - await fetchBadgeInfo(); - - var fixStatusMap = await fetchFixStatusMap(); - - // Generate a machine-readable summary of rules. - MachineSummaryGenerator(Registry.ruleRegistry, fixStatusMap).generate(outDir); -} - -void printUsage(ArgParser parser, [String? error]) { - var message = 'Generates lint docs.'; - if (error != null) { - message = error; - } - - stdout.write('''$message -Usage: doc -${parser.usage} -'''); -} - -class CountBadger { - Iterable rules; - - CountBadger(this.rules); - - Future generate(String? dirPath) async { - var lintCount = rules.length; - - var client = http.Client(); - var req = await client.get( - Uri.parse('https://img.shields.io/badge/lints-$lintCount-blue.svg')); - var bytes = req.bodyBytes; - await File('$dirPath/count-badge.svg').writeAsBytes(bytes); - } -} - -class MachineSummaryGenerator { - final Iterable rules; - final Map fixStatusMap; - - MachineSummaryGenerator(this.rules, this.fixStatusMap); - - void generate(String? filePath) { - var generated = getMachineListing(rules, - fixStatusMap: fixStatusMap, sinceInfo: sinceMap); - if (filePath != null) { - var outPath = '$filePath/machine/rules.json'; - printToConsole('Writing to $outPath'); - File(outPath).writeAsStringSync(generated); - } else { - printToConsole(generated); - } - } -} diff --git a/tool/machine.dart b/tool/machine.dart index 717b977ff..b8619defb 100644 --- a/tool/machine.dart +++ b/tool/machine.dart @@ -7,12 +7,14 @@ import 'dart:io'; import 'package:analyzer/src/lint/registry.dart'; import 'package:args/args.dart'; +import 'package:http/http.dart' as http; import 'package:linter/src/analyzer.dart'; import 'package:linter/src/rules.dart'; +import 'package:linter/src/util/score_utils.dart' as score_utils; import 'package:linter/src/utils.dart'; import 'package:path/path.dart' as path; +import 'package:yaml/yaml.dart'; -import 'doc.dart'; import 'since.dart'; /// Generates a list of lint rules in machine format suitable for consumption by @@ -38,24 +40,50 @@ void main(List args) async { } } -Future generateRulesJson( - {bool pretty = true, bool includeSetInfo = true}) async { - registerLintRules(); - if (includeSetInfo) { - await fetchBadgeInfo(); +Future> fetchFixStatusMap() async { + var url = + 'https://raw.githubusercontent.com/dart-lang/sdk/main/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml'; + printToConsole('loading $url...'); + var req = await http.get(Uri.parse(url)); + var yaml = loadYamlNode(req.body) as YamlMap; + var fixStatusMap = {}; + 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 generateRulesJson({ + bool pretty = true, + bool includeSetInfo = true, +}) async { + registerLintRules(); var fixStatusMap = await fetchFixStatusMap(); - return getMachineListing(Registry.ruleRegistry, + return await getMachineListing(Registry.ruleRegistry, fixStatusMap: fixStatusMap, sinceInfo: sinceMap, pretty: pretty); } -String getMachineListing(Iterable ruleRegistry, - {Map? fixStatusMap, - bool pretty = true, - Map? sinceInfo}) { +Future getMachineListing( + Iterable ruleRegistry, { + Map? fixStatusMap, + bool pretty = true, + bool includeSetInfo = true, + Map? sinceInfo, +}) async { var rules = List.of(ruleRegistry, growable: false)..sort(); 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) { @@ -77,3 +105,28 @@ String getMachineListing(Iterable ruleRegistry, ]); return json; } + +Future< + ({ + Set coreRules, + Set recommendedRules, + Set flutterRules, + })> _fetchSetRules({bool fetch = true}) async { + if (!fetch) { + return const ( + coreRules: {}, + recommendedRules: {}, + flutterRules: {}, + ); + } + + 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, + ); +}