diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 0499a6cf..1e3ad6f6 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -4,6 +4,16 @@ on: pull_request: jobs: + analyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dart-lang/setup-dart@v1 + with: + sdk: 2.18.7 + - run: dart pub get + - run: dart run dart_dev analyze + format: runs-on: ubuntu-latest steps: @@ -12,7 +22,7 @@ jobs: with: sdk: 2.18.7 - run: dart pub get - - run: dart run dart_dev format + - run: dart run dart_dev format --check dependency-validator: runs-on: ubuntu-latest diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 97b5ee0b..b8241116 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -49,7 +49,12 @@ jobs: strategy: matrix: - repo: ["Workiva/over_react", "rrousselGit/provider", "dart-lang/args"] + repo: [ + "Workiva/over_react", + "Workiva/w_module", + "rrousselGit/provider", + "dart-lang/args", + ] steps: # Setup scip-dart diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 00000000..74177def --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,7 @@ +include: package:workiva_analysis_options/v2.yaml + +analyzer: + strong-mode: + implicit-casts: false + exclude: + - snapshots/** \ No newline at end of file diff --git a/bin/scip_dart.dart b/bin/scip_dart.dart index e394dcb6..fa354392 100644 --- a/bin/scip_dart.dart +++ b/bin/scip_dart.dart @@ -28,7 +28,6 @@ Future main(List args) async { )) .parse(args); - Flags.instance.init(result); if ((result['path'] as List?)?.isNotEmpty == true) { @@ -40,7 +39,7 @@ Future main(List args) async { } final packageRoot = - result.rest.length > 0 ? result.rest.first : Directory.current.path; + result.rest.isNotEmpty ? result.rest.first : Directory.current.path; final packageConfig = await findPackageConfig(Directory(packageRoot)); if (packageConfig == null) { diff --git a/lib/src/flags.dart b/lib/src/flags.dart index 15988584..cc1a7d66 100644 --- a/lib/src/flags.dart +++ b/lib/src/flags.dart @@ -8,8 +8,8 @@ class Flags { bool _performance = false; void init(ArgResults results) { - _verbose = results['verbose'] ?? false; - _performance = results['performance'] ?? false; + _verbose = results['verbose'] as bool? ?? false; + _performance = results['performance'] as bool? ?? false; } static Flags get instance => _instance; diff --git a/lib/src/indexer.dart b/lib/src/indexer.dart index 1030ab83..ddf6cac6 100644 --- a/lib/src/indexer.dart +++ b/lib/src/indexer.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; import 'package:analyzer/dart/analysis/results.dart'; import 'package:path/path.dart' as p; @@ -7,6 +9,7 @@ import 'package:scip_dart/src/flags.dart'; import 'package:scip_dart/src/gen/scip.pb.dart'; import 'package:scip_dart/src/scip_visitor.dart'; +import 'package:scip_dart/src/utils.dart'; Future indexPackage( String root, @@ -15,35 +18,55 @@ Future indexPackage( ) async { final dirPath = p.normalize(p.absolute(root)); + final rootHasPubspecFile = await File( + p.join(dirPath, 'pubspec.yaml'), + ).exists(); + if (!rootHasPubspecFile) { + stderr.writeln( + 'Provided path does not contain a pubspec.yaml file. ' + 'Unable to index', + ); + exit(1); + } + final metadata = Metadata( - projectRoot: 'file:/' + dirPath, - textDocumentEncoding: TextEncoding.UTF8, - toolInfo: ToolInfo( - name: 'scip-dart', - version: '0.0.1', - arguments: [], - )); + projectRoot: 'file:/' + dirPath, + textDocumentEncoding: TextEncoding.UTF8, + toolInfo: ToolInfo( + name: 'scip-dart', + version: '0.0.1', + arguments: [], + ), + ); final allPackageRoots = packageConfig.packages .map((package) => p.normalize(package.packageUriRoot.toFilePath())) .toList(); + final nestedPackages = (await pubspecPathsFor(root)) + .map((path) => p.dirname(path)) + .where((path) => path != root) + .toList(); + + if (Flags.instance.verbose) print('Ignoring subdirectories: $nestedPackages'); final collection = AnalysisContextCollection( - includedPaths: [ - ...allPackageRoots, - dirPath, - ], - ); + includedPaths: [ + ...allPackageRoots, + dirPath, + ], + // only index dart files of the current dart package, to index nested + // packages, scip indexing can simply be re-run for that nested package + excludedPaths: nestedPackages); if (Flags.instance.performance) print('Analyzing Source'); final st = Stopwatch()..start(); final context = collection.contextFor(dirPath); final resolvedUnitFutures = context.contextRoot - .analyzedFiles() - .where((file) => p.extension(file) == '.dart') - .map(context.currentSession.getResolvedUnit); + .analyzedFiles() + .where((file) => p.extension(file) == '.dart') + .map(context.currentSession.getResolvedUnit); final resolvedUnits = await Future.wait(resolvedUnitFutures); diff --git a/lib/src/scip_visitor.dart b/lib/src/scip_visitor.dart index 003ecf44..fede0e0f 100644 --- a/lib/src/scip_visitor.dart +++ b/lib/src/scip_visitor.dart @@ -29,7 +29,6 @@ class ScipVisitor extends GeneralizingAstVisitor { Pubspec pubspec, ) : _symbolGenerator = SymbolGenerator( packageConfig, - _projectRoot, pubspec, ) { final fileSymbol = _symbolGenerator.fileSymbolFor(_relativePath); diff --git a/lib/src/symbol.dart b/lib/src/symbol.dart index 8d683cf5..31dfaefd 100644 --- a/lib/src/symbol.dart +++ b/lib/src/symbol.dart @@ -9,7 +9,6 @@ import 'package:scip_dart/src/utils.dart'; /// Each sourcefile should use its own instance of `SymbolGenerator` class SymbolGenerator { final PackageConfig _packageConfig; - final String _projectRoot; final Pubspec _pubspec; int _localElementIndex = 0; @@ -23,7 +22,6 @@ class SymbolGenerator { SymbolGenerator( this._packageConfig, - this._projectRoot, this._pubspec, ); diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 159f7efe..e4d19710 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -1,8 +1,20 @@ import 'dart:io'; import 'package:analyzer/source/line_info.dart'; +import 'package:path/path.dart' as p; + import 'package:scip_dart/src/flags.dart'; +/// Returns a list of all the pubspec.yaml paths under a directory. +/// Will recurse into child folders, will not follow links. +Future> pubspecPathsFor(String rootDirectory) async { + return Directory(rootDirectory) + .list(recursive: true, followLinks: false) + .where((file) => p.basename(file.path) == 'pubspec.yaml') + .map((file) => file.path) + .toList(); +} + enum DisplayLevel { info, warn, diff --git a/pubspec.lock b/pubspec.lock index 817730c5..ecdf8539 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,371 +5,392 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "52.0.0" + version: "54.0.0" analyzer: dependency: "direct main" description: name: analyzer - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "5.4.0" + version: "5.6.0" args: dependency: "direct main" description: name: args - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.4.2" + version: "2.4.1" async: dependency: transitive description: name: async - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.10.0" + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" build: dependency: transitive description: name: build - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "2.3.1" build_config: dependency: transitive description: name: build_config - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.1.1" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "3.1.1" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "2.2.0" build_runner: dependency: transitive description: name: build_runner - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "2.3.3" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "7.2.7" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "8.4.3" + version: "8.6.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "2.0.2" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "4.4.0" collection: dependency: transitive description: name: collection - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.17.1" + version: "1.17.2" convert: dependency: transitive description: name: convert - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "3.1.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "3.0.2" dart_dev: dependency: "direct dev" description: name: dart_dev - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "4.0.1" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.2.4" + version: "2.2.5" dependency_validator: dependency: "direct dev" description: name: dependency_validator - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "3.2.2" file: dependency: transitive description: name: file - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "6.1.4" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "3.2.0" glob: dependency: "direct dev" description: name: glob - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.1" graphs: dependency: transitive description: name: graphs - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.1" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "4.0.2" io: dependency: transitive description: name: io - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.4" js: dependency: transitive description: name: js - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "0.6.5" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "4.8.0" logging: dependency: transitive description: name: logging - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.1.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.12.14" + version: "0.12.16" meta: dependency: transitive description: name: meta - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.9.0" + version: "1.9.1" mime: dependency: transitive description: name: mime - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.4" package_config: dependency: "direct main" description: name: package_config - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" path: dependency: "direct main" description: name: path - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.8.3" pool: dependency: transitive description: name: pool - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.5.1" protobuf: dependency: "direct main" description: name: protobuf - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "2.1.4" pubspec_parse: dependency: "direct main" description: name: pubspec_parse - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.2.3" shelf: dependency: transitive description: name: shelf - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.4.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.4" source_span: dependency: transitive description: name: source_span - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "2.1.1" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.0" timing: dependency: transitive description: name: timing - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.3.1" + version: "1.3.2" watcher: dependency: transitive description: name: watcher - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.2" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dev" + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.0" + workiva_analysis_options: + dependency: "direct dev" + description: + name: workiva_analysis_options + url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "1.3.0" yaml: dependency: transitive description: name: yaml - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "3.1.1" sdks: diff --git a/pubspec.yaml b/pubspec.yaml index e1ac2c6c..fbba7dc0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: pubspec_parse: ^1.2.1 dev_dependencies: - dependency_validator: ^3.2.2 dart_dev: ">=3.9.2 <5.0.0" - glob: ^2.1.1 \ No newline at end of file + dependency_validator: ^3.2.2 + glob: ^2.1.1 + workiva_analysis_options: ^1.0.0 \ No newline at end of file diff --git a/tool/dart_dev/config.dart b/tool/dart_dev/config.dart index 9ee096e4..ffe7397c 100644 --- a/tool/dart_dev/config.dart +++ b/tool/dart_dev/config.dart @@ -4,5 +4,8 @@ import 'package:glob/glob.dart'; final config = { ...coreConfig, 'format': FormatTool() - ..exclude = [Glob('snapshots/**'), Glob('lib/src/gen/*.dart')] + ..exclude = [ + Glob('snapshots/**'), + Glob('lib/src/gen/*.dart'), + ], };