Future runLinter()

in lib/src/cli.dart [49:178]


Future runLinter(List<String> args, LinterOptions initialLintOptions) async {
  // Force the rule registry to be populated.
  registerLintRules();

  var parser = ArgParser();
  parser
    ..addFlag('help',
        abbr: 'h', negatable: false, help: 'Show usage information.')
    ..addFlag('stats',
        abbr: 's', negatable: false, help: 'Show lint statistics.')
    ..addFlag('benchmark', negatable: false, help: 'Show lint benchmarks.')
    ..addFlag('visit-transitive-closure',
        help: 'Visit the transitive closure of imported/exported libraries.')
    ..addFlag('quiet', abbr: 'q', help: "Don't show individual lint errors.")
    ..addFlag('machine',
        help: 'Print results in a format suitable for parsing.',
        negatable: false)
    ..addOption('config', abbr: 'c', help: 'Use configuration from this file.')
    ..addOption('dart-sdk', help: 'Custom path to a Dart SDK.')
    ..addMultiOption('rules',
        help: 'A list of lint rules to run. For example: '
            'avoid_as,annotate_overrides')
    ..addOption('packages',
        help: 'Path to the package resolution configuration file, which\n'
            'supplies a mapping of package names to paths.');

  ArgResults options;
  try {
    options = parser.parse(args);
  } on FormatException catch (err) {
    printUsage(parser, errorSink, err.message);
    exitCode = unableToProcessExitCode;
    return;
  }

  if (options['help'] as bool) {
    printUsage(parser, outSink);
    return;
  }

  if (options.rest.isEmpty) {
    printUsage(parser, errorSink,
        'Please provide at least one file or directory to lint.');
    exitCode = unableToProcessExitCode;
    return;
  }

  var lintOptions = initialLintOptions;

  var configFile = options['config'];
  if (configFile is String) {
    var config = LintConfig.parse(readFile(configFile));
    lintOptions.configure(config);
  }

  var lints = options['rules'];
  if (lints is Iterable<String> && lints.isNotEmpty) {
    var rules = <LintRule>[];
    for (var lint in lints) {
      var rule = Registry.ruleRegistry[lint];
      if (rule == null) {
        errorSink.write('Unrecognized lint rule: $lint');
        exit(unableToProcessExitCode);
      }
      rules.add(rule);
    }

    lintOptions.enabledLints = rules;
  }

  var customSdk = options['dart-sdk'];
  if (customSdk is String) {
    lintOptions.dartSdkPath = customSdk;
  }

  var packageConfigFile = options['packages'] as String?;
  packageConfigFile = packageConfigFile != null
      ? _absoluteNormalizedPath(packageConfigFile)
      : null;

  var stats = options['stats'] as bool;
  var benchmark = options['benchmark'] as bool;
  if (stats || benchmark) {
    lintOptions.enableTiming = true;
  }

  lintOptions
    ..packageConfigPath = packageConfigFile
    ..resourceProvider = PhysicalResourceProvider.INSTANCE;

  var filesToLint = <File>[];
  for (var path in options.rest) {
    filesToLint.addAll(
      collectFiles(path)
          .map((file) => _absoluteNormalizedPath(file.path))
          .map((path) => File(path)),
    );
  }

  if (benchmark) {
    await writeBenchmarks(outSink, filesToLint, lintOptions);
    return;
  }

  var linter = DartLinter(lintOptions);

  try {
    var timer = Stopwatch()..start();
    var errors = await lintFiles(linter, filesToLint);
    timer.stop();

    var commonRoot = getRoot(options.rest);
    var machine = options['machine'] ?? false;
    var quiet = options['quiet'] ?? false;
    ReportFormatter(errors, lintOptions.filter, outSink,
            elapsedMs: timer.elapsedMilliseconds,
            fileCount: linter.numSourcesAnalyzed,
            fileRoot: commonRoot,
            showStatistics: stats,
            machineOutput: machine as bool,
            quiet: quiet as bool)
        .write();
    // ignore: avoid_catches_without_on_clauses
  } catch (err, stack) {
    errorSink.writeln('''An error occurred while linting
  Please report it at: github.com/dart-lang/linter/issues
$err
$stack''');
  }
}