blob: 566987455909b5530264155b3737f0e541ff6753 [file] [log] [blame]
// Copyright (c) 2020, 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.
// @dart = 2.9
/// Module metadata format version
///
/// Module reader always creates the current version but is able to read
/// metadata files with later versions as long as the changes are backward
/// compatible, i.e. only minor or patch versions have changed.
///
/// See: https://goto.google.com/dart-web-debugger-metadata
class ModuleMetadataVersion {
final int majorVersion;
final int minorVersion;
final int patchVersion;
const ModuleMetadataVersion(
this.majorVersion,
this.minorVersion,
this.patchVersion,
);
/// Current metadata version
///
/// Version follows simple semantic versioning format 'major.minor.patch'
/// See https://semver.org
///
/// TODO(annagrin): create metadata package, make version the same as the
/// metadata package version, automate updating with the package update
static const ModuleMetadataVersion current = ModuleMetadataVersion(1, 0, 2);
/// Current metadata version created by the reader
String get version => '$majorVersion.$minorVersion.$patchVersion';
/// Is this metadata version compatible with the given version
///
/// The minor and patch version changes never remove any fields that current
/// version supports, so the reader can create current metadata version from
/// any file created with a later reader, as long as the major version does
/// not change.
bool isCompatibleWith(String version) {
var parts = version.split('.');
if (parts.length != 3) {
throw FormatException('Version: $version'
'does not follow simple semantic versioning format');
}
var major = int.parse(parts[0]);
var minor = int.parse(parts[1]);
var patch = int.parse(parts[2]);
return major == majorVersion &&
minor >= minorVersion &&
patch >= patchVersion;
}
}
/// Library metadata
///
/// Represents library metadata used in the debugger,
/// supports reading from and writing to json
/// See: https://goto.google.com/dart-web-debugger-metadata
class LibraryMetadata {
/// Library name as defined in pubspec.yaml
final String name;
/// Library importUri
///
/// Example package:path/path.dart
final String importUri;
/// Library fileUri
///
/// Example file:///path/to/path/path.dart
final String fileUri;
/// All file uris from the library
///
/// Can be relative paths to the directory of the fileUri
final List<String> partUris;
LibraryMetadata(this.name, this.importUri, this.fileUri, this.partUris);
LibraryMetadata.fromJson(Map<String, dynamic> json)
: name = json['name'] as String,
importUri = json['importUri'] as String,
fileUri = json['fileUri'] as String,
partUris =
List.castFrom<dynamic, String>(json['partUris'] as List<dynamic>);
Map<String, dynamic> toJson() {
return {
'name': name,
'importUri': importUri,
'fileUri': fileUri,
'partUris': [...partUris]
};
}
}
/// Module metadata
///
/// Represents module metadata used in the debugger,
/// supports reading from and writing to json
/// See: https://goto.google.com/dart-web-debugger-metadata
class ModuleMetadata {
/// Metadata format version
String version;
/// Module name
///
/// Used as a name of the js module created by the compiler and
/// as key to store and load modules in the debugger and the browser
final String name;
/// Name of the function enclosing the module
///
/// Used by debugger to determine the top dart scope
final String closureName;
/// Source map uri
final String sourceMapUri;
/// Module uri
final String moduleUri;
/// The uri where DDC wrote a full .dill file for this module.
///
/// Can be `null` if the module was compiled without the option to output the
/// .dill fle.
final String fullDillUri;
final Map<String, LibraryMetadata> libraries = {};
/// True if the module corresponding to this metadata was compiled with sound
/// null safety enabled.
final bool soundNullSafety;
ModuleMetadata(this.name, this.closureName, this.sourceMapUri, this.moduleUri,
this.fullDillUri, this.soundNullSafety,
{this.version}) {
version ??= ModuleMetadataVersion.current.version;
}
/// Add [library] to metadata
///
/// Used for filling the metadata in the compiler or for reading from
/// stored metadata files.
void addLibrary(LibraryMetadata library) {
if (!libraries.containsKey(library.importUri)) {
libraries[library.importUri] = library;
} else {
throw ('Metadata creation error: '
'Cannot add library $library with uri ${library.importUri}: '
'another library "${libraries[library.importUri]}" is found '
'with the same uri');
}
}
ModuleMetadata.fromJson(Map<String, dynamic> json)
: version = json['version'] as String,
name = json['name'] as String,
closureName = json['closureName'] as String,
sourceMapUri = json['sourceMapUri'] as String,
moduleUri = json['moduleUri'] as String,
fullDillUri = json['fullDillUri'] as String,
soundNullSafety = json['soundNullSafety'] as bool {
var fileVersion = json['version'] as String;
if (!ModuleMetadataVersion.current.isCompatibleWith(version)) {
throw Exception('Unsupported metadata version $fileVersion');
}
for (var l in json['libraries'] as List<dynamic>) {
addLibrary(LibraryMetadata.fromJson(l as Map<String, dynamic>));
}
}
Map<String, dynamic> toJson() {
return {
'version': version,
'name': name,
'closureName': closureName,
'sourceMapUri': sourceMapUri,
'moduleUri': moduleUri,
'fullDillUri': fullDillUri,
'libraries': [for (var lib in libraries.values) lib.toJson()],
'soundNullSafety': soundNullSafety
};
}
}