Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

is:wasm-ready tag #1336

Merged
merged 13 commits into from
Feb 9, 2024
1 change: 1 addition & 0 deletions lib/src/package_analyzer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ class PackageAnalyzer {
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_);
Expand Down
8 changes: 4 additions & 4 deletions lib/src/report/multi_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Future<ReportSection> multiPlatform(String packageDir, Pubspec pubspec) async {

Subsection scorePlatforms(
List<String> tags, List<Explanation> explanations) {
// Scoring and the report only takes these platforms into account.
final tagNames = const {
PanaTags.platformIos: 'iOS',
PanaTags.platformAndroid: 'Android',
Expand All @@ -45,12 +46,13 @@ Future<ReportSection> multiPlatform(String packageDir, Pubspec pubspec) async {
PanaTags.platformMacos: 'macOS',
PanaTags.platformLinux: 'Linux',
};
final officialTags = tags.where(tagNames.containsKey).toList();
final sdkExplanations =
explanations.where((e) => e.tag != null && e.tag!.startsWith('sdk:'));
final platformExplanations = explanations
.where((e) => e.tag == null || !e.tag!.startsWith('sdk:'));
final officialExplanations = platformExplanations.where((e) =>
!tags.contains(e.tag) &&
!officialTags.contains(e.tag) &&
(e.tag == null || tagNames.containsKey(e.tag)));
final trustExplanations = explanations.where((e) => tags.contains(e.tag));
final paragraphs = <Paragraph>[
Expand All @@ -59,7 +61,7 @@ Future<ReportSection> multiPlatform(String packageDir, Pubspec pubspec) async {
if (sdkExplanations.isNotEmpty)
// This empty line is required for `package:markdown` to render the following list correctly.
RawParagraph(''),
for (final tag in tags.where((e) => e.startsWith('platform')))
for (final tag in officialTags.where((e) => e.startsWith('platform')))
RawParagraph('* ✓ ${tagNames[tag]}'),
if (officialExplanations.isNotEmpty)
RawParagraph('\nThese platforms are not supported:\n'),
Expand All @@ -70,8 +72,6 @@ Future<ReportSection> multiPlatform(String packageDir, Pubspec pubspec) async {
...trustExplanations.map(explanationToIssue),
];

final officialTags = tags.where(tagNames.containsKey).toList();

final status =
officialTags.where((tag) => tag.startsWith('platform:')).isEmpty
? ReportStatus.failed
Expand Down
6 changes: 6 additions & 0 deletions lib/src/tag/_specs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ class Runtime {
tag: PanaTags.runtimeWeb,
);

static final wasm = Runtime(
'wasm',
{..._onAllPlatforms, 'ui', 'ui_web', 'js_interop', 'js_interop_unsafe'},
sigurdm marked this conversation as resolved.
Show resolved Hide resolved
tag: PanaTags.isWasmReady,
);

static final flutterNative = Runtime(
'flutter-native',
{
Expand Down
1 change: 1 addition & 0 deletions lib/src/tag/pana_tags.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ abstract class PanaTags {
static const runtimeFlutterNative = 'runtime:flutter-native';
static const runtimeFlutterWeb = 'runtime:flutter-web';
static const runtimeWeb = 'runtime:web';
static const isWasmReady = 'is:wasm-ready';

// platform tags
static const platformAndroid = 'platform:android';
Expand Down
24 changes: 24 additions & 0 deletions lib/src/tag/tagger.dart
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,30 @@ class Tagger {
}
}

/// Adds the is:wasm-ready tag if there are no uses of disallowed dart: libraries.
void wasmReadyTag(List<String> tags, List<Explanation> explanations) {
final runtime = Runtime.wasm;
final finder = runtimeViolationFinder(
LibraryGraph(_session, runtime.declaredVariables),
runtime,
(List<Uri> path) => Explanation(
'Package not compatible with runtime ${runtime.name}',
'Because:\n${LibraryGraph.formatPath(path)}',
tag: runtime.tag));
var supports = true;
for (final lib in _topLibraries) {
final violationResult = finder.findViolation(lib);
if (violationResult != null) {
explanations.add(violationResult);
supports = false;
break;
}
}
if (supports) {
tags.add(runtime.tag);
}
}

/// Adds tags for the Dart runtimes that this package supports to [tags].
///
/// Adds [Explanation]s to [explanations] for runtimes not supported.
Expand Down
1 change: 1 addition & 0 deletions test/goldens/end2end/async-2.11.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"runtime:native-jit",
"runtime:web",
"is:null-safe",
"is:wasm-ready",
"is:dart3-compatible",
"license:bsd-3-clause",
"license:fsf-libre",
Expand Down
1 change: 1 addition & 0 deletions test/goldens/end2end/http-0.13.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"runtime:native-jit",
"runtime:web",
"is:null-safe",
"is:wasm-ready",
"is:dart3-compatible",
"license:bsd-3-clause",
"license:fsf-libre",
Expand Down
1 change: 1 addition & 0 deletions test/goldens/end2end/lints-1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"runtime:native-jit",
"runtime:web",
"is:null-safe",
"is:wasm-ready",
"is:dart3-compatible",
"license:bsd-3-clause",
"license:fsf-libre",
Expand Down
1 change: 1 addition & 0 deletions test/goldens/end2end/nsd_android-1.2.2.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"platform:android",
"is:plugin",
"is:null-safe",
"is:wasm-ready",
"is:dart3-compatible",
"license:mit",
"license:fsf-libre",
Expand Down
1 change: 1 addition & 0 deletions test/goldens/end2end/onepub-1.1.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
"runtime:native-aot",
"runtime:native-jit",
"is:null-safe",
"is:wasm-ready",
"is:dart3-compatible",
"license:unknown"
],
Expand Down
1 change: 1 addition & 0 deletions test/goldens/end2end/url_launcher-6.1.12.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
"platform:web",
"is:plugin",
"is:null-safe",
"is:wasm-ready",
"is:dart3-compatible",
"license:bsd-3-clause",
"license:fsf-libre",
Expand Down
80 changes: 76 additions & 4 deletions test/tag/tag_end2end_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,11 @@ int fourtyTwo() => 42;
_expectTagging(tagger.sdkTags, tags: {'sdk:flutter', 'sdk:dart'});
_expectTagging(tagger.platformTags,
tags: {'platform:windows', 'platform:android'});
_expectTagging(tagger.runtimeTags,
tags: ['runtime:native-aot', 'runtime:native-jit', 'runtime:web']);
_expectTagging(tagger.runtimeTags, tags: [
'runtime:native-aot',
'runtime:native-jit',
'runtime:web',
]);
_expectTagging(tagger.flutterPluginTags, tags: isEmpty);
});

Expand Down Expand Up @@ -406,7 +409,7 @@ Because:
finding: 'Package not compatible with runtime js', explanation: '''
Because:
* `package:my_package/my_package.dart` that imports:
* `dart:io`''')
* `dart:io`'''),
});
_expectTagging(tagger.flutterPluginTags, tags: isEmpty);
});
Expand Down Expand Up @@ -449,7 +452,11 @@ int fourtyThree() => 43;
},
explanations: isEmpty);
_expectTagging(tagger.runtimeTags,
tags: {'runtime:native-aot', 'runtime:native-jit', 'runtime:web'},
tags: {
'runtime:native-aot',
'runtime:native-jit',
'runtime:web',
},
explanations: isEmpty);
_expectTagging(tagger.flutterPluginTags, tags: isEmpty);
});
Expand Down Expand Up @@ -570,6 +577,71 @@ name: my_package
_expectTagging(tagger.flutterPluginTags, tags: {'is:plugin'});
});
});

group('wasm tag', () {
test('Excluded with dart:js', () async {
final descriptor = d.dir('cache', [
packageWithPathDeps('my_package', lib: [
d.file('my_package.dart', '''
import 'dart:js';
'''),
])
]);

await descriptor.create();
final tagger = Tagger('${descriptor.io.path}/my_package');
_expectTagging(tagger.wasmReadyTag,
tags: isNot(contains('is:wasm-ready')));
});

test('Excluded with dart:js_util', () async {
final descriptor = d.dir('cache', [
packageWithPathDeps('my_package', lib: [
d.file('my_package.dart', '''
import 'dart:js_util';
'''),
])
]);

await descriptor.create();
final tagger = Tagger('${descriptor.io.path}/my_package');
_expectTagging(tagger.wasmReadyTag,
tags: isNot(contains('is:wasm-ready')));
});
test('Excluded with dart:html', () async {
final descriptor = d.dir('cache', [
packageWithPathDeps('my_package', lib: [
d.file('my_package.dart', '''
import 'dart:html';
'''),
])
]);

await descriptor.create();
final tagger = Tagger('${descriptor.io.path}/my_package');
_expectTagging(tagger.wasmReadyTag,
tags: isNot(contains('is:wasm-ready')));
});

test(
'Included with dart:ui, dart:ui_web dart:js_interop dart:js_interop_unsafe',
() async {
final descriptor = d.dir('cache', [
packageWithPathDeps('my_package', lib: [
d.file('my_package.dart', '''
import 'dart:ui';
import 'dart:ui_web';
import 'dart:js_interop';
import 'dart:js_interop_unsafe';
'''),
])
]);

await descriptor.create();
final tagger = Tagger('${descriptor.io.path}/my_package');
_expectTagging(tagger.wasmReadyTag, tags: contains('is:wasm-ready'));
});
});
}

Matcher _explanation(
Expand Down