From 8c55f3eb0bc3a31dd28617351f7a583b40f97d69 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Mon, 30 Oct 2023 11:22:27 +0000 Subject: [PATCH] Revert "[analyzer] simplify the libraries.dart file" This reverts commit 29979649bd2654ed654fbd6ea87899d52ba76066. Reason for revert: makes `promiseToFuture` not exported from `dart:html`, see b/295129286 Original change's description: > [analyzer] simplify the libraries.dart file > > Cleanup and re-landing of https://dart-review.googlesource.com/c/sdk/+/317803. > > Change-Id: I9fd679fdb111895ce662ecbe6d0fc5844909c3bc > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/332441 > Reviewed-by: Konstantin Shcheglov > Commit-Queue: Devon Carew Change-Id: Id93b4a1d4bdea706ae10cfb089319514a0238a7d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/332683 Reviewed-by: Alexander Thomas Bot-Commit: Rubber Stamper Commit-Queue: Ilya Yanok --- .../completion/dart/uri_contributor.dart | 2 +- pkg/analyzer/lib/src/generated/sdk.dart | 107 +++++-- .../lib/src/test_utilities/mock_sdk.dart | 18 +- pkg/analyzer/test/src/dart/sdk/sdk_test.dart | 47 ++-- .../sdk_library_metadata/lib/libraries.dart | 262 +++++++++++++++++- 5 files changed, 365 insertions(+), 71 deletions(-) diff --git a/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart index ea9e4c1fcf0..e8a31a2a26b 100644 --- a/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart +++ b/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart @@ -117,7 +117,7 @@ class _UriSuggestionBuilder extends SimpleAstVisitor { builder.suggestUri('dart:'); var factory = request.sourceFactory; for (var lib in factory.dartSdk!.sdkLibraries) { - if (!lib.isInternal && !lib.isImplementation && lib.isDocumented) { + if (!lib.isInternal && !lib.isImplementation) { if (!lib.shortName.startsWith('dart:_')) { builder.suggestUri(lib.shortName); } diff --git a/pkg/analyzer/lib/src/generated/sdk.dart b/pkg/analyzer/lib/src/generated/sdk.dart index f6d439c8a5b..265ce7963fc 100644 --- a/pkg/analyzer/lib/src/generated/sdk.dart +++ b/pkg/analyzer/lib/src/generated/sdk.dart @@ -175,10 +175,26 @@ class SdkLibrariesReader_LibraryBuilder extends RecursiveAstVisitor { /// an implementation library. static const String _IMPLEMENTATION = "implementation"; + /// The name of the optional parameter used to specify the path used when + /// compiling for dart2js. + static const String _DART2JS_PATH = "dart2jsPath"; + /// The name of the optional parameter used to indicate whether the library is /// documented. static const String _DOCUMENTED = "documented"; + /// The name of the optional parameter used to specify the category of the + /// library. + static const String _CATEGORIES = "categories"; + + /// The name of the optional parameter used to specify the platforms on which + /// the library can be used. + static const String _PLATFORMS = "platforms"; + + /// The value of the [PLATFORMS] parameter used to specify that the library + /// can be used on the VM. + static const String _VM_PLATFORM = "VM_PLATFORM"; + /// The library map that is populated by visiting the AST structure parsed /// from the contents of the libraries file. final LibraryMap _librariesMap = LibraryMap(); @@ -187,6 +203,24 @@ class SdkLibrariesReader_LibraryBuilder extends RecursiveAstVisitor { /// parsed from the contents of the libraries file. LibraryMap get librariesMap => _librariesMap; + // To be backwards-compatible the new categories field is translated to + // an old approximation. + String convertCategories(String categories) { + switch (categories) { + case "": + return "Internal"; + case "Client": + return "Client"; + case "Server": + return "Server"; + case "Client,Server": + return "Shared"; + case "Client,Server,Embedded": + return "Shared"; + } + return "Shared"; + } + @override void visitMapLiteralEntry(MapLiteralEntry node) { var key = node.key as SimpleStringLiteral; @@ -202,10 +236,26 @@ class SdkLibrariesReader_LibraryBuilder extends RecursiveAstVisitor { } else if (argument is NamedExpression) { String name = argument.name.label.name; Expression expression = argument.expression; - if (name == _IMPLEMENTATION) { - library.implementation = (expression as BooleanLiteral).value; + if (name == _CATEGORIES) { + var value = (expression as StringLiteral).stringValue!; + library.category = convertCategories(value); + } else if (name == _IMPLEMENTATION) { + library._implementation = (expression as BooleanLiteral).value; } else if (name == _DOCUMENTED) { library.documented = (expression as BooleanLiteral).value; + } else if (name == _PLATFORMS) { + if (expression is SimpleIdentifier) { + String identifier = expression.name; + if (identifier == _VM_PLATFORM) { + library.setVmLibrary(); + } else { + library.setDart2JsLibrary(); + } + } + } else if (name == _DART2JS_PATH) { + if (expression is SimpleStringLiteral) { + library.path = expression.value; + } } } } @@ -217,11 +267,9 @@ class SdkLibrariesReader_LibraryBuilder extends RecursiveAstVisitor { /// Represents a single library in the SDK abstract class SdkLibrary { /// Return the name of the category containing the library. - @deprecated String get category; /// Return `true` if this library can be compiled to JavaScript by dart2js. - @deprecated bool get isDart2JsLibrary; /// Return `true` if the library is documented. @@ -235,11 +283,9 @@ abstract class SdkLibrary { bool get isInternal; /// Return `true` if this library can be used for both client and server. - @deprecated bool get isShared; /// Return `true` if this library can be run on the VM. - @deprecated bool get isVmLibrary; /// Return the path to the file defining the library. The path is relative to @@ -253,6 +299,14 @@ abstract class SdkLibrary { /// The information known about a single library within the SDK. class SdkLibraryImpl implements SdkLibrary { + /// The bit mask used to access the bit representing the flag indicating + /// whether a library is intended to work on the dart2js platform. + static int DART2JS_PLATFORM = 1; + + /// The bit mask used to access the bit representing the flag indicating + /// whether a library is intended to work on the VM platform. + static int VM_PLATFORM = 2; + @override final String shortName; @@ -261,9 +315,11 @@ class SdkLibraryImpl implements SdkLibrary { @override late String path; + /// The name of the category containing the library. Unless otherwise + /// specified in the libraries file all libraries are assumed to be shared + /// between server and client. @override - @deprecated - String category = ""; + String category = "Shared"; /// A flag indicating whether the library is documented. bool _documented = true; @@ -271,23 +327,20 @@ class SdkLibraryImpl implements SdkLibrary { /// A flag indicating whether the library is an implementation library. bool _implementation = false; + /// An encoding of which platforms this library is intended to work on. + int _platforms = 0; + /// Initialize a newly created library to represent the library with the given - /// [shortName]. + /// [name]. SdkLibraryImpl(this.shortName); /// Set whether the library is documented. - set documented(bool value) { - _documented = value; - } - - /// Set whether the library is an implementation library. - set implementation(bool value) { - _implementation = value; + set documented(bool documented) { + _documented = documented; } @override - @deprecated - bool get isDart2JsLibrary => false; + bool get isDart2JsLibrary => (_platforms & DART2JS_PLATFORM) != 0; @override bool get isDocumented => _documented; @@ -296,13 +349,21 @@ class SdkLibraryImpl implements SdkLibrary { bool get isImplementation => _implementation; @override - bool get isInternal => shortName.startsWith('dart:_'); + bool get isInternal => category == "Internal"; @override - @deprecated - bool get isShared => false; + bool get isShared => category == "Shared"; @override - @deprecated - bool get isVmLibrary => false; + bool get isVmLibrary => (_platforms & VM_PLATFORM) != 0; + + /// Record that this library can be compiled to JavaScript by dart2js. + void setDart2JsLibrary() { + _platforms |= DART2JS_PLATFORM; + } + + /// Record that this library can be run on the VM. + void setVmLibrary() { + _platforms |= VM_PLATFORM; + } } diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart index 11c9a344da0..2da81d05364 100644 --- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart +++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart @@ -1199,6 +1199,7 @@ class Symbol implements core.Symbol { ''', ) ], + categories: '', ); final MockSdkLibrary _LIB_IO = MockSdkLibrary( @@ -1401,12 +1402,10 @@ void createMockSdk({ var file = lib.getChildAssumingFile(unit.path); file.writeAsStringSync(unit.content); } - librariesBuffer.writeln(''' - '${library.name}': const LibraryInfo( - '${library.path}', - documented: ${!library.isInternal}, - ), -'''); + librariesBuffer.writeln( + ' "${library.name}": const LibraryInfo("${library.path}", ' + 'categories: "${library.categories}"),', + ); } librariesBuffer.writeln('};'); @@ -1435,16 +1434,15 @@ void createMockSdk({ class MockSdkLibrary implements SdkLibrary { final String name; + final String categories; final List units; - MockSdkLibrary(this.name, this.units); + MockSdkLibrary(this.name, this.units, {this.categories = 'Shared'}); @override - @deprecated String get category => throw UnimplementedError(); @override - @deprecated bool get isDart2JsLibrary => throw UnimplementedError(); @override @@ -1457,11 +1455,9 @@ class MockSdkLibrary implements SdkLibrary { bool get isInternal => shortName.startsWith('dart:_'); @override - @deprecated bool get isShared => throw UnimplementedError(); @override - @deprecated bool get isVmLibrary => throw UnimplementedError(); @override diff --git a/pkg/analyzer/test/src/dart/sdk/sdk_test.dart b/pkg/analyzer/test/src/dart/sdk/sdk_test.dart index 14ffb69b90b..9e5cf6676fd 100644 --- a/pkg/analyzer/test/src/dart/sdk/sdk_test.dart +++ b/pkg/analyzer/test/src/dart/sdk/sdk_test.dart @@ -157,7 +157,7 @@ class FolderBasedDartSdkTest with ResourceProviderMixin { File file = dirCommon.getChildAssumingFile("html_common_dart2js.dart"); var source = sdk.fromFileUri(file.toUri())!; expect(source, isNotNull); - expect(source.uri.toString(), "dart:html_common/html_common_dart2js.dart"); + expect(source.uri.toString(), "dart:html_common"); } void test_fromFile_part() { @@ -239,21 +239,28 @@ class FolderBasedDartSdkTest with ResourceProviderMixin { final Map LIBRARIES = const { "async": const LibraryInfo( "async/async.dart", - ), + categories: "Client,Server", + maturity: Maturity.STABLE, + dart2jsPatchPath: "_internal/js_runtime/lib/async_patch.dart"), "core": const LibraryInfo( "core/core.dart", - ), + categories: "Client,Server,Embedded", + maturity: Maturity.STABLE, + dart2jsPatchPath: "_internal/js_runtime/lib/core_patch.dart"), "html": const LibraryInfo( "html/dart2js/html_dart2js.dart", - ), + categories: "Client", + maturity: Maturity.WEB_STABLE), "html_common": const LibraryInfo( "html/html_common/html_common.dart", + categories: "Client", + maturity: Maturity.WEB_STABLE, + dart2jsPath: "html/html_common/html_common_dart2js.dart", documented: false, - implementation: true, - ), + implementation: true), }; '''; } @@ -273,42 +280,36 @@ class SdkLibrariesReaderTest with ResourceProviderMixin { final Map LIBRARIES = const { 'first' : const LibraryInfo( 'first/first.dart', + categories: 'Client', documented: true, - ), + platforms: VM_PLATFORM), 'second' : const LibraryInfo( 'second/second.dart', + categories: 'Server', documented: false, implementation: true, - ), - '_internal': const LibraryInfo( - 'internal/internal.dart', - documented: false, - implementation: true, - ), + platforms: 0), };'''); expect(libraryMap, isNotNull); - expect(libraryMap.size(), 3); + expect(libraryMap.size(), 2); var first = libraryMap.getLibrary("dart:first")!; expect(first, isNotNull); + expect(first.category, "Client"); expect(first.path, "first/first.dart"); expect(first.shortName, "dart:first"); + expect(first.isDart2JsLibrary, false); expect(first.isDocumented, true); expect(first.isImplementation, false); - expect(first.isInternal, false); + expect(first.isVmLibrary, true); var second = libraryMap.getLibrary("dart:second")!; expect(second, isNotNull); + expect(second.category, "Server"); expect(second.path, "second/second.dart"); expect(second.shortName, "dart:second"); + expect(second.isDart2JsLibrary, false); expect(second.isDocumented, false); expect(second.isImplementation, true); - expect(second.isInternal, false); - var internal = libraryMap.getLibrary("dart:_internal")!; - expect(internal, isNotNull); - expect(internal.path, "internal/internal.dart"); - expect(internal.shortName, "dart:_internal"); - expect(internal.isDocumented, false); - expect(internal.isImplementation, true); - expect(internal.isInternal, true); + expect(second.isVmLibrary, false); } } diff --git a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart index 3c787d406cf..be125aeee59 100644 --- a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart +++ b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart @@ -4,170 +4,306 @@ // The package:analyzer parse of the `libraries` field depends on the current // use of const. - // ignore_for_file: unnecessary_const +/// A bit flag used by [LibraryInfo] indicating that a library is used by +/// dart2js. +const int DART2JS_PLATFORM = 1; + +/// A bit flag used by [LibraryInfo] indicating that a library is used by the +/// VM. +const int VM_PLATFORM = 2; + +/// The contexts that a library can be used from. +enum Category { + /// Indicates that a library can be used in a browser context. + client, + + /// Indicates that a library can be used in a command line context. + server, + + /// Indicates that a library can be used from embedded devices. + embedded, +} + +Category? parseCategory(String name) { + switch (name) { + case 'Client': + return Category.client; + case 'Server': + return Category.server; + case 'Embedded': + return Category.embedded; + default: + return null; + } +} + /// Mapping of "dart:" library name (e.g. "core") to information about that /// library. const Map libraries = const { 'async': const LibraryInfo( 'async/async.dart', + categories: 'Client,Server', + maturity: Maturity.STABLE, + dart2jsPatchPath: '_internal/js_runtime/lib/async_patch.dart', ), 'collection': const LibraryInfo( 'collection/collection.dart', + categories: 'Client,Server,Embedded', + maturity: Maturity.STABLE, + dart2jsPatchPath: '_internal/js_runtime/lib/collection_patch.dart', ), 'convert': const LibraryInfo( 'convert/convert.dart', + categories: 'Client,Server', + maturity: Maturity.STABLE, + dart2jsPatchPath: '_internal/js_runtime/lib/convert_patch.dart', ), 'core': const LibraryInfo( 'core/core.dart', + categories: 'Client,Server,Embedded', + maturity: Maturity.STABLE, + dart2jsPatchPath: '_internal/js_runtime/lib/core_patch.dart', ), 'developer': const LibraryInfo( 'developer/developer.dart', + categories: 'Client,Server,Embedded', + maturity: Maturity.UNSTABLE, + dart2jsPatchPath: '_internal/js_runtime/lib/developer_patch.dart', ), 'ffi': const LibraryInfo( 'ffi/ffi.dart', + categories: 'Server', + maturity: Maturity.STABLE, ), 'html': const LibraryInfo( 'html/dart2js/html_dart2js.dart', + categories: 'Client', + maturity: Maturity.WEB_STABLE, + platforms: DART2JS_PLATFORM, ), 'html_common': const LibraryInfo( - 'html/html_common/html_common_dart2js.dart', + 'html/html_common/html_common.dart', + categories: 'Client', + maturity: Maturity.WEB_STABLE, + dart2jsPath: 'html/html_common/html_common_dart2js.dart', documented: false, implementation: true, ), 'indexed_db': const LibraryInfo( 'indexed_db/dart2js/indexed_db_dart2js.dart', + categories: 'Client', + maturity: Maturity.WEB_STABLE, + platforms: DART2JS_PLATFORM, ), '_http': const LibraryInfo( '_http/http.dart', + categories: '', documented: false, ), 'io': const LibraryInfo( 'io/io.dart', + categories: 'Server', + dart2jsPatchPath: '_internal/js_runtime/lib/io_patch.dart', ), 'isolate': const LibraryInfo( 'isolate/isolate.dart', + categories: 'Client,Server', + maturity: Maturity.STABLE, + dart2jsPatchPath: '_internal/js_runtime/lib/isolate_patch.dart', ), 'js': const LibraryInfo( 'js/js.dart', + categories: 'Client', + maturity: Maturity.STABLE, + platforms: DART2JS_PLATFORM, + dart2jsPatchPath: '_internal/js_runtime/lib/js_patch.dart', ), '_js': const LibraryInfo( 'js/_js.dart', + categories: 'Client', + dart2jsPatchPath: 'js/_js_client.dart', documented: false, + platforms: DART2JS_PLATFORM, ), 'js_interop': const LibraryInfo( 'js_interop/js_interop.dart', + categories: 'Client', + maturity: Maturity.EXPERIMENTAL, + platforms: DART2JS_PLATFORM, ), 'js_interop_unsafe': const LibraryInfo( 'js_interop_unsafe/js_interop_unsafe.dart', + categories: 'Client', + maturity: Maturity.EXPERIMENTAL, + platforms: DART2JS_PLATFORM, ), 'js_util': const LibraryInfo( 'js_util/js_util.dart', + categories: 'Client', + maturity: Maturity.STABLE, + platforms: DART2JS_PLATFORM, ), 'math': const LibraryInfo( 'math/math.dart', + categories: 'Client,Server,Embedded', + maturity: Maturity.STABLE, + dart2jsPatchPath: '_internal/js_runtime/lib/math_patch.dart', ), 'mirrors': const LibraryInfo( 'mirrors/mirrors.dart', + categories: 'Client,Server', + maturity: Maturity.UNSTABLE, + dart2jsPatchPath: '_internal/js_runtime/lib/mirrors_patch_cfe.dart', ), 'nativewrappers': const LibraryInfo( 'html/dartium/nativewrappers.dart', - documented: false, + categories: 'Client', implementation: true, + documented: false, + platforms: VM_PLATFORM, ), 'typed_data': const LibraryInfo( 'typed_data/typed_data.dart', + categories: 'Client,Server,Embedded', + maturity: Maturity.STABLE, + dart2jsPatchPath: '_internal/js_runtime/lib/typed_data_patch.dart', ), '_native_typed_data': const LibraryInfo( '_internal/js_runtime/lib/native_typed_data.dart', - documented: false, + categories: '', implementation: true, + documented: false, + platforms: DART2JS_PLATFORM, ), 'cli': const LibraryInfo( 'cli/cli.dart', + categories: 'Server', + platforms: VM_PLATFORM, ), 'svg': const LibraryInfo( 'svg/dart2js/svg_dart2js.dart', + categories: 'Client', + maturity: Maturity.WEB_STABLE, + platforms: DART2JS_PLATFORM, ), 'web_audio': const LibraryInfo( 'web_audio/dart2js/web_audio_dart2js.dart', + categories: 'Client', + maturity: Maturity.WEB_STABLE, + platforms: DART2JS_PLATFORM, ), 'web_gl': const LibraryInfo( 'web_gl/dart2js/web_gl_dart2js.dart', + categories: 'Client', + maturity: Maturity.WEB_STABLE, + platforms: DART2JS_PLATFORM, ), '_internal': const LibraryInfo( 'internal/internal.dart', + categories: '', documented: false, + dart2jsPatchPath: '_internal/js_runtime/lib/internal_patch.dart', ), '_js_helper': const LibraryInfo( '_internal/js_runtime/lib/js_helper.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_late_helper': const LibraryInfo( '_internal/js_runtime/lib/late_helper.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_rti': const LibraryInfo( '_internal/js_shared/lib/rti.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_dart2js_runtime_metrics': const LibraryInfo( '_internal/js_runtime/lib/dart2js_runtime_metrics.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_interceptors': const LibraryInfo( '_internal/js_runtime/lib/interceptors.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_foreign_helper': const LibraryInfo( '_internal/js_runtime/lib/foreign_helper.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_js_names': const LibraryInfo( '_internal/js_runtime/lib/js_names.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_js_primitives': const LibraryInfo( '_internal/js_runtime/lib/js_primitives.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_js_embedded_names': const LibraryInfo( '_internal/js_runtime/lib/synced/embedded_names.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_js_shared_embedded_names': const LibraryInfo( '_internal/js_shared/lib/synced/embedded_names.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_js_types': const LibraryInfo( '_internal/js_shared/lib/js_types.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_async_status_codes': const LibraryInfo( '_internal/js_runtime/lib/synced/async_status_codes.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_recipe_syntax': const LibraryInfo( '_internal/js_shared/lib/synced/recipe_syntax.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_load_library_priority': const LibraryInfo( '_internal/js_runtime/lib/synced/load_library_priority.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_metadata': const LibraryInfo( 'html/html_common/metadata.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), '_js_annotations': const LibraryInfo( 'js/_js_annotations.dart', + categories: '', documented: false, + platforms: DART2JS_PLATFORM, ), - '_wasm': const LibraryInfo( - '_wasm/wasm_types.dart', - documented: false, - ), + "_wasm": const LibraryInfo('_wasm/wasm_types.dart', + categories: '', documented: false), }; /// Information about a "dart:" library. @@ -175,18 +311,118 @@ class LibraryInfo { /// Path to the library's *.dart file relative to this file. final String path; + /// The categories in which the library can be used encoded as a + /// comma-separated String. + final String _categories; + + /// States the current maturity of this library. + final Maturity maturity; + + /// Path to the dart2js library's *.dart file relative to this file + /// or null if dart2js uses the common library path defined above. + /// Access using the [#getDart2JsPath()] method. + final String? dart2jsPath; + + /// Path to the dart2js library's patch file relative to this file + /// or null if no dart2js patch file associated with this library. + /// Access using the [#getDart2JsPatchPath()] method. + final String? dart2jsPatchPath; + /// True if this library is documented and should be shown to the user. final bool documented; + /// Bit flags indicating which platforms consume this library. + /// See [DART2JS_LIBRARY] and [VM_LIBRARY]. + final int platforms; + /// True if the library contains implementation details for another library. - /// - /// The implication is that tools should generally not show these libraries to - /// users. + /// The implication is that these libraries are less commonly used + /// and that tools like Dart Editor should not show these libraries + /// in a list of all libraries unless the user specifically asks the tool to + /// do so. final bool implementation; const LibraryInfo( this.path, { + String categories = '', + this.dart2jsPath, + this.dart2jsPatchPath, + this.implementation = false, this.documented = true, - bool? implementation, - }) : this.implementation = implementation ?? !documented; + this.maturity = Maturity.UNSPECIFIED, + this.platforms = DART2JS_PLATFORM | VM_PLATFORM, + }) : _categories = categories; + + bool get isDart2jsLibrary => (platforms & DART2JS_PLATFORM) != 0; + bool get isVmLibrary => (platforms & VM_PLATFORM) != 0; + + /// The categories in which the library can be used. + /// + /// If no categories are specified, the library is internal and can not be + /// loaded by user code. + List get categories { + // `"".split(,)` returns [""] not [], so we handle that case separately. + if (_categories.isEmpty) { + return const []; + } else { + return _categories + .split(',') + .map(parseCategory) + .whereType() + .toList(); + } + } + + bool get isInternal => categories.isEmpty; + + /// The original "categories" String that was passed to the constructor. + /// + /// Can be used to construct a slightly modified copy of this LibraryInfo. + String get categoriesString => _categories; +} + +/// Abstraction to capture the maturity of a library. +class Maturity { + final int level; + final String name; + final String description; + + const Maturity(this.level, this.name, this.description); + + @override + String toString() => '$name: $level\n$description\n'; + + static const Maturity DEPRECATED = Maturity(0, 'Deprecated', + 'This library will be remove before next major release.'); + + static const Maturity EXPERIMENTAL = Maturity( + 1, + 'Experimental', + 'This library is experimental and will likely change or be removed\n' + 'in future versions.'); + + static const Maturity UNSTABLE = Maturity( + 2, + 'Unstable', + 'This library is in still changing and have not yet endured\n' + 'sufficient real-world testing.\n' + 'Backwards-compatibility is NOT guaranteed.'); + + static const Maturity WEB_STABLE = Maturity( + 3, + 'Web Stable', + 'This library is tracking the DOM evolution as defined by WC3.\n' + 'Backwards-compatibility is NOT guaranteed.'); + + static const Maturity STABLE = Maturity( + 4, + 'Stable', + 'The library is stable. API backwards-compatibility is guaranteed.\n' + 'However implementation details might change.'); + + static const Maturity LOCKED = Maturity(5, 'Locked', + 'This library will not change except when serious bugs are encountered.'); + + static const Maturity UNSPECIFIED = Maturity(-1, 'Unspecified', + 'The maturity for this library has not been specified.'); }