Skip to content

Commit

Permalink
Expose wasm readiness analysis in the report (without any score) (#1396)
Browse files Browse the repository at this point in the history
  • Loading branch information
isoos authored Aug 20, 2024
1 parent 9849de1 commit 9d1bb7b
Show file tree
Hide file tree
Showing 41 changed files with 297 additions and 100 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.22.11

- Expose `wasm` readiness analysis in the report (without any score).

## 0.22.10

- Remove `workspace` and `resolution` properties from pubspec before analyzing.
Expand Down
23 changes: 23 additions & 0 deletions lib/src/internal_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import 'package:json_annotation/json_annotation.dart';

import 'model.dart';
import 'tag/_common.dart';
import 'tag/pana_tags.dart';
import 'tool/run_constrained.dart';

part 'internal_model.g.dart';

Expand Down Expand Up @@ -47,6 +50,26 @@ class VersionDescriptor {
Map<String, dynamic> toJson() => _$VersionDescriptorToJson(this);
}

class AnalyzeToolResult {
final List<CodeProblem>? items;
final List<String> tags;
final List<Explanation> explanations;
final ToolException? toolError;

AnalyzeToolResult({
required this.items,
required this.tags,
required this.explanations,
}) : toolError = null;

AnalyzeToolResult.toolError(this.toolError)
: items = null,
tags = [PanaTags.hasError],
explanations = [];

bool get hasError => toolError != null;
}

@JsonSerializable()
class CodeProblem implements Comparable<CodeProblem> {
/// The errors which don't block platform classification.
Expand Down
53 changes: 2 additions & 51 deletions lib/src/package_analyzer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,15 @@ import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;

import 'download_utils.dart';
import 'internal_model.dart';
import 'logging.dart';
import 'maintenance.dart';
import 'messages.dart';
import 'model.dart';
import 'package_context.dart';
import 'pubspec.dart';
import 'report/create_report.dart';
import 'sdk_env.dart';
import 'tag/pana_tags.dart';
import 'tag/tagger.dart';
import 'tool/git_tool.dart';
import 'tool/run_constrained.dart';
import 'utils.dart';

class InspectOptions {
Expand Down Expand Up @@ -120,17 +116,6 @@ class PackageAnalyzer {
packageDir: pkgDir,
);

final dartFiles = <String>[];
final fileList = listFiles(pkgDir, deleteBadExtracted: true);
await for (final file in fileList) {
final isInBin = path.isWithin('bin', file);
final isInLib = path.isWithin('lib', file);
final isDart = file.endsWith('.dart');
if (isDart && (isInLib || isInBin)) {
dartFiles.add(file);
}
}

Pubspec? pubspec;
try {
pubspec = context.pubspec;
Expand All @@ -157,42 +142,8 @@ class PackageAnalyzer {
'[report the issue](https://github.com/dart-lang/pana/issues).');
}

if (await context.resolveDependencies()) {
List<CodeProblem>? analyzerItems;
if (dartFiles.isNotEmpty) {
try {
analyzerItems = await context.staticAnalysis();
} on ToolException catch (e) {
context.errors
.add(runningDartAnalyzerFailed(context.usesFlutter, e.message));
}
} else {
analyzerItems = <CodeProblem>[];
}
if (analyzerItems != null && !analyzerItems.any((item) => item.isError)) {
final tagger = Tagger(pkgDir);
final tags_ = <String>[];
final explanations = <Explanation>[];
// TODO: refactor these methods to return the tags+explanations
tagger.sdkTags(tags_, explanations);
tagger.platformTags(tags_, explanations);
tagger.runtimeTags(tags_, explanations);
tagger.flutterPluginTags(tags_, explanations);
tagger.nullSafetyTags(tags_, explanations);
tagger.wasmReadyTag(tags_, explanations);
// tags are exposed, explanations are ignored
// TODO: use a single result object to derive tags + report
tags.addAll(tags_);

if (context.currentSdkVersion.major >= 3) {
tags.add(PanaTags.isDart3Compatible);
}
} else {
tags.add(PanaTags.hasError);
}
} else {
tags.add(PanaTags.hasError);
}
final tr = await context.staticAnalysis;
tags.addAll(tr.tags);

final licenses = await context.licenses;
tags.addAll((await context.licenceTags).tags);
Expand Down
67 changes: 56 additions & 11 deletions lib/src/package_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ import 'repository/check_repository.dart';
import 'screenshots.dart';
import 'sdk_env.dart';
import 'tag/license_tags.dart';
import 'tag/pana_tags.dart';
import 'tag/tagger.dart';
import 'tool/run_constrained.dart';
import 'utils.dart' show listFocusDirs;
import 'utils.dart' show listFiles, listFocusDirs;

/// Shared (intermediate) results between different packages or versions.
/// External systems that may be independent of the archive content may be
Expand Down Expand Up @@ -94,7 +96,6 @@ class PackageContext {
final _stopwatch = Stopwatch();

Pubspec? _pubspec;
List<CodeProblem>? _codeProblems;

PackageContext({
required this.sharedContext,
Expand Down Expand Up @@ -228,17 +229,61 @@ class PackageContext {
}
}();

Future<List<CodeProblem>> staticAnalysis() async {
if (_codeProblems != null) return _codeProblems!;
try {
late final Future<List<String>> _dartFiles = () async {
final results = <String>[];
final fileList = listFiles(packageDir, deleteBadExtracted: true);
await for (final file in fileList) {
final isInBin = p.isWithin('bin', file);
final isInLib = p.isWithin('lib', file);
final isDart = file.endsWith('.dart');
if (isDart && (isInLib || isInBin)) {
results.add(file);
}
}
return results;
}();

late final Future<AnalyzeToolResult> staticAnalysis = () async {
List<CodeProblem>? items;
final tags = <String>[];
final explanations = <Explanation>[];
final dartFiles = await _dartFiles;

if (!await resolveDependencies()) {
tags.add(PanaTags.hasError);
} else if (dartFiles.isEmpty) {
items = [];
} else {
log.info('Analyzing package...');
_codeProblems = await _staticAnalysis(packageDir: packageDir);
return _codeProblems!;
} on ToolException catch (e) {
errors.add(messages.runningDartAnalyzerFailed(usesFlutter, e.message));
rethrow;
try {
items = await _staticAnalysis(packageDir: packageDir);
} on ToolException catch (e) {
errors.add(messages.runningDartAnalyzerFailed(usesFlutter, e.message));
return AnalyzeToolResult.toolError(e);
}
}
}

if (items != null && !items.any((item) => item.isError)) {
final tagger = Tagger(packageDir);
// TODO: refactor these methods to return the tags+explanations
tagger.sdkTags(tags, explanations);
tagger.platformTags(tags, explanations);
tagger.runtimeTags(tags, explanations);
tagger.flutterPluginTags(tags, explanations);
tagger.nullSafetyTags(tags, explanations);
tagger.wasmReadyTag(tags, explanations);
if (currentSdkVersion.major >= 3) {
tags.add(PanaTags.isDart3Compatible);
}
} else {
tags.add(PanaTags.hasError);
}
return AnalyzeToolResult(
items: items,
tags: tags,
explanations: explanations,
);
}();

Future<List<CodeProblem>> _staticAnalysis({
required String packageDir,
Expand Down
6 changes: 2 additions & 4 deletions lib/src/report/create_report.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import '../model.dart';
import '../package_context.dart';
import '../pubspec.dart';

import 'dependencies.dart';
import 'documentation.dart';
Expand All @@ -19,9 +18,8 @@ import 'template.dart';
export '_common.dart' show renderSimpleSectionSummary;

Future<Report> createReport(PackageContext context) async {
Pubspec pubspec;
try {
pubspec = context.pubspec;
context.pubspec;
} on Exception catch (e) {
return Report(
sections: [
Expand All @@ -38,7 +36,7 @@ Future<Report> createReport(PackageContext context) async {
}

final templateReport = await followsTemplate(context);
final platformReport = await multiPlatform(context.packageDir, pubspec);
final platformReport = await multiPlatform(context);
final staticAnalysisReport = await staticAnalysis(context);
final dependenciesReport = await trustworthyDependency(context);

Expand Down
59 changes: 52 additions & 7 deletions lib/src/report/multi_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ import 'dart:io';
import 'package:path/path.dart' as p;

import '../model.dart';
import '../pubspec.dart';
import '../package_context.dart';
import '../tag/pana_tags.dart';
import '../tag/tagger.dart';
import '_common.dart';

Future<ReportSection> multiPlatform(String packageDir, Pubspec pubspec) async {
Future<ReportSection> multiPlatform(PackageContext context) async {
Subsection subsection;
final flutterPackage = pubspec.usesFlutter;
final flutterPackage = context.pubspec.usesFlutter;

if (File(p.join(packageDir, '.dart_tool', 'package_config.json'))
if (File(p.join(context.packageDir, '.dart_tool', 'package_config.json'))
.existsSync()) {
final tags = <String>[];
final explanations = <Explanation>[];
final tagger = Tagger(packageDir);
final tagger = Tagger(context.packageDir);
final sdkTags = <String>[];
final sdkExplanations = <Explanation>[];
tagger.sdkTags(sdkTags, sdkExplanations);
Expand Down Expand Up @@ -117,11 +117,56 @@ Future<ReportSection> multiPlatform(String packageDir, Pubspec pubspec) async {
);
}

final wasmSubsection = await _createWasmSubsection(context);

return makeSection(
id: ReportSectionId.platform,
title: 'Platform support',
maxPoints: 20,
basePath: packageDir,
subsections: [subsection],
basePath: context.packageDir,
subsections: [subsection, wasmSubsection],
maxIssues: 20);
}

Future<Subsection> _createWasmSubsection(PackageContext context) async {
final tr = await context.staticAnalysis;
final description = 'WASM compatibility';
final explanation =
tr.explanations.where((e) => e.tag == PanaTags.isWasmReady).firstOrNull;
if (explanation != null) {
return Subsection(
description,
[
explanationToIssue(explanation),
RawParagraph('See https://dart.dev/web/wasm for details.'),
],
0,
0,
ReportStatus.failed,
);
}

if (tr.tags.contains(PanaTags.isWasmReady)) {
return Subsection(
description,
[
RawParagraph('Package is compatible with runtime `wasm`. '
'See https://dart.dev/web/wasm for details.')
],
0,
0,
ReportStatus.passed,
);
} else {
return Subsection(
description,
[
RawParagraph('Unable to detect compatibility with runtime `wasm`.'),
RawParagraph('See https://dart.dev/web/wasm for details.'),
],
0,
0,
ReportStatus.failed,
);
}
}
8 changes: 4 additions & 4 deletions lib/src/report/static_analysis.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,18 @@ Future<_AnalysisResult> _analyzePackage(PackageContext context) async {
context.usesFlutter ? 'flutter pub get' : 'dart pub get',
);
}
final list = await context.staticAnalysis();
final rs = await context.staticAnalysis;

return _AnalysisResult(
list
rs.items!
.where((element) => element.isError)
.map(issueFromCodeProblem)
.toList(),
list
rs.items!
.where((element) => element.isWarning)
.map(issueFromCodeProblem)
.toList(),
list
rs.items!
.where((element) => element.isInfo)
.map(issueFromCodeProblem)
.toList(),
Expand Down
2 changes: 1 addition & 1 deletion lib/src/version.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: pana
description: PAckage aNAlyzer - produce a report summarizing the health and quality of a Dart package.
version: 0.22.10
version: 0.22.11
repository: https://github.com/dart-lang/pana
topics:
- tool
Expand Down
2 changes: 1 addition & 1 deletion test/goldens/end2end/_dummy_pkg-1.0.0-null-safety.1.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"grantedPoints": 0,
"maxPoints": 20,
"status": "failed",
"summary": "### [x] 0/20 points: Platform support detection failed\n\n<details>\n<summary>\nCould not determine supported platforms as package resolution failed.\n</summary>\n\nRun `dart pub get` for more information.\n</details>"
"summary": "### [x] 0/20 points: Platform support detection failed\n\n<details>\n<summary>\nCould not determine supported platforms as package resolution failed.\n</summary>\n\nRun `dart pub get` for more information.\n</details>\n\n### [x] 0/0 points: WASM compatibility\n\nUnable to detect compatibility with runtime `wasm`.\nSee https://dart.dev/web/wasm for details."
},
{
"id": "analysis",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ Could not determine supported platforms as package resolution failed.
Run `dart pub get` for more information.
</details>

### [x] 0/0 points: WASM compatibility

Unable to detect compatibility with runtime `wasm`.
See https://dart.dev/web/wasm for details.

## 0/50 Pass static analysis

### [x] 0/50 points: code has no errors, warnings, lints, or formatting issues
Expand Down
2 changes: 1 addition & 1 deletion test/goldens/end2end/async-2.11.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"grantedPoints": 20,
"maxPoints": 20,
"status": "passed",
"summary": "### [*] 20/20 points: Supports 6 of 6 possible platforms (**iOS**, **Android**, **Web**, **Windows**, **macOS**, **Linux**)\n\n* ✓ Android\n* ✓ iOS\n* ✓ Windows\n* ✓ Linux\n* ✓ macOS\n* ✓ Web"
"summary": "### [*] 20/20 points: Supports 6 of 6 possible platforms (**iOS**, **Android**, **Web**, **Windows**, **macOS**, **Linux**)\n\n* ✓ Android\n* ✓ iOS\n* ✓ Windows\n* ✓ Linux\n* ✓ macOS\n* ✓ Web\n\n### [*] 0/0 points: WASM compatibility\n\nPackage is compatible with runtime `wasm`. See https://dart.dev/web/wasm for details."
},
{
"id": "analysis",
Expand Down
Loading

0 comments on commit 9d1bb7b

Please sign in to comment.