| // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'dart:collection'; |
| |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/ast/visitor.dart'; |
| import 'package:analyzer/src/generated/source.dart' show Source; |
| import 'package:pub_semver/pub_semver.dart'; |
| |
| /// A Dart SDK installed in a specified location. |
| abstract class DartSdk { |
| /// The short name of the dart SDK 'async' library. |
| static const String DART_ASYNC = "dart:async"; |
| |
| /// The short name of the dart SDK 'core' library. |
| static const String DART_CORE = "dart:core"; |
| |
| /// The short name of the dart SDK 'html' library. |
| static const String DART_HTML = "dart:html"; |
| |
| /// The prefix shared by all dart library URIs. |
| static const String DART_LIBRARY_PREFIX = "dart:"; |
| |
| /// The version number that is returned when the real version number could not |
| /// be determined. |
| static const String DEFAULT_VERSION = "0"; |
| |
| /// Return the content of the `allowed_experiments.json` file, or `null` |
| /// if the file cannot be read, e.g. does not exist. |
| String? get allowedExperimentsJson; |
| |
| /// Return the language version of this SDK, or throws an exception. |
| /// |
| /// The language version has only major/minor components, the patch number |
| /// is always zero, because the patch number does not change the language. |
| Version get languageVersion; |
| |
| /// Return a list containing all of the libraries defined in this SDK. |
| List<SdkLibrary> get sdkLibraries; |
| |
| /// Return the revision number of this SDK, or `"0"` if the revision number |
| /// cannot be discovered. |
| String get sdkVersion; |
| |
| /// Return a list containing the library URI's for the libraries defined in |
| /// this SDK. |
| List<String> get uris; |
| |
| /// Return a source representing the given 'file:' [uri] if the file is in |
| /// this SDK, or `null` if the file is not in this SDK. |
| Source? fromFileUri(Uri uri); |
| |
| /// Return the library representing the library with the given 'dart:' [uri], |
| /// or `null` if the given URI does not denote a library in this SDK. |
| SdkLibrary? getSdkLibrary(String uri); |
| |
| /// Return the source representing the library with the given 'dart:' [uri], |
| /// or `null` if the given URI does not denote a library in this SDK. |
| Source? mapDartUri(String uri); |
| } |
| |
| /// Manages the DartSdk's that have been created. Clients need to create |
| /// multiple SDKs when the analysis options associated with those SDK's contexts |
| /// will produce different analysis results. |
| class DartSdkManager { |
| /// The absolute path to the directory containing the default SDK. |
| final String defaultSdkDirectory; |
| |
| /// A table mapping (an encoding of) analysis options and SDK locations to the |
| /// DartSdk from that location that has been configured with those options. |
| Map<SdkDescription, DartSdk> sdkMap = HashMap<SdkDescription, DartSdk>(); |
| |
| /// Initialize a newly created manager. |
| DartSdkManager(this.defaultSdkDirectory, [@deprecated bool? canUseSummaries]); |
| |
| /// Return any SDK that has been created, or `null` if no SDKs have been |
| /// created. |
| DartSdk? get anySdk { |
| if (sdkMap.isEmpty) { |
| return null; |
| } |
| return sdkMap.values.first; |
| } |
| |
| /// Return a list of the descriptors of the SDKs that are currently being |
| /// managed. |
| List<SdkDescription> get sdkDescriptors => sdkMap.keys.toList(); |
| |
| /// Return the Dart SDK that is appropriate for the given SDK [description]. |
| /// If such an SDK has not yet been created, then the [ifAbsent] function will |
| /// be invoked to create it. |
| DartSdk getSdk(SdkDescription description, DartSdk Function() ifAbsent) { |
| return sdkMap.putIfAbsent(description, ifAbsent); |
| } |
| } |
| |
| /// A map from Dart library URI's to the [SdkLibraryImpl] representing that |
| /// library. |
| class LibraryMap { |
| /// A table mapping Dart library URI's to the library. |
| final Map<String, SdkLibraryImpl> _libraryMap = <String, SdkLibraryImpl>{}; |
| |
| /// Return a list containing all of the sdk libraries in this mapping. |
| List<SdkLibraryImpl> get sdkLibraries => List.from(_libraryMap.values); |
| |
| /// Return a list containing the library URI's for which a mapping is |
| /// available. |
| List<String> get uris => _libraryMap.keys.toList(); |
| |
| /// Return info for debugging https://github.com/dart-lang/sdk/issues/35226. |
| Map<String, Object> debugInfo() { |
| var map = <String, Object>{}; |
| for (var entry in _libraryMap.entries) { |
| var uri = entry.key; |
| var lib = entry.value; |
| map[uri] = <String, Object>{ |
| 'path': lib.path, |
| 'shortName': lib.shortName, |
| }; |
| } |
| return map; |
| } |
| |
| /// Return the library with the given 'dart:' [uri], or `null` if the URI does |
| /// not map to a library. |
| SdkLibrary? getLibrary(String uri) => _libraryMap[uri]; |
| |
| /// Set the library with the given 'dart:' [uri] to the given [library]. |
| void setLibrary(String dartUri, SdkLibraryImpl library) { |
| _libraryMap[dartUri] = library; |
| } |
| |
| /// Return the number of library URI's for which a mapping is available. |
| int size() => _libraryMap.length; |
| } |
| |
| /// A description of a [DartSdk]. |
| class SdkDescription { |
| /// The path of the SDK. |
| final String path; |
| |
| SdkDescription(this.path); |
| |
| @override |
| int get hashCode { |
| return path.hashCode; |
| } |
| |
| @override |
| bool operator ==(Object other) { |
| if (other is SdkDescription) { |
| return other.path == path; |
| } |
| return false; |
| } |
| |
| @override |
| String toString() { |
| return path; |
| } |
| } |
| |
| class SdkLibrariesReader_LibraryBuilder extends RecursiveAstVisitor<void> { |
| /// The prefix added to the name of a library to form the URI used in code to |
| /// reference the library. |
| static const String _LIBRARY_PREFIX = "dart:"; |
| |
| /// The name of the optional parameter used to indicate whether the library is |
| /// 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(); |
| |
| /// Return the library map that was populated by visiting the AST structure |
| /// 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; |
| var libraryName = "$_LIBRARY_PREFIX${key.value}"; |
| |
| Expression value = node.value; |
| if (value is InstanceCreationExpression) { |
| SdkLibraryImpl library = SdkLibraryImpl(libraryName); |
| List<Expression> arguments = value.argumentList.arguments; |
| for (Expression argument in arguments) { |
| if (argument is SimpleStringLiteral) { |
| library.path = argument.value; |
| } else if (argument is NamedExpression) { |
| String name = argument.name.label.name; |
| Expression expression = argument.expression; |
| 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; |
| } |
| } |
| } |
| } |
| _librariesMap.setLibrary(libraryName, library); |
| } |
| } |
| } |
| |
| /// Represents a single library in the SDK |
| abstract class SdkLibrary { |
| /// Return the name of the category containing the library. |
| String get category; |
| |
| /// Return `true` if this library can be compiled to JavaScript by dart2js. |
| bool get isDart2JsLibrary; |
| |
| /// Return `true` if the library is documented. |
| bool get isDocumented; |
| |
| /// Return `true` if the library is an implementation library. |
| bool get isImplementation; |
| |
| /// Return `true` if library is internal can be used only by other SDK |
| /// libraries. |
| bool get isInternal; |
| |
| /// Return `true` if this library can be used for both client and server. |
| bool get isShared; |
| |
| /// Return `true` if this library can be run on the VM. |
| bool get isVmLibrary; |
| |
| /// Return the path to the file defining the library. The path is relative to |
| /// the `lib` directory within the SDK. |
| String get path; |
| |
| /// Return the short name of the library. This is the URI of the library, |
| /// including `dart:`. |
| String get shortName; |
| } |
| |
| /// 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; |
| |
| /// The path to the file defining the library. The path is relative to the |
| /// 'lib' directory within the SDK. |
| @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 |
| String category = "Shared"; |
| |
| /// A flag indicating whether the library is documented. |
| bool _documented = true; |
| |
| /// 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 |
| /// [name]. |
| SdkLibraryImpl(this.shortName); |
| |
| /// Set whether the library is documented. |
| set documented(bool documented) { |
| _documented = documented; |
| } |
| |
| @override |
| bool get isDart2JsLibrary => (_platforms & DART2JS_PLATFORM) != 0; |
| |
| @override |
| bool get isDocumented => _documented; |
| |
| @override |
| bool get isImplementation => _implementation; |
| |
| @override |
| bool get isInternal => category == "Internal"; |
| |
| @override |
| bool get isShared => category == "Shared"; |
| |
| @override |
| 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; |
| } |
| } |