Skip to content

Commit

Permalink
is:wasm-ready tag (#1336)
Browse files Browse the repository at this point in the history
  • Loading branch information
sigurdm committed Feb 9, 2024
1 parent f6f298f commit 65458f0
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 8 deletions.
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'},
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

0 comments on commit 65458f0

Please sign in to comment.