Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 11 additions & 19 deletions pkgs/package_config/bin/package_config_of.dart
Original file line number Diff line number Diff line change
Expand Up @@ -147,30 +147,23 @@ Future<ConfigInfo> _resolvePackageConfig(
}

/// Gathered package configuration information for [path].
final class ConfigInfo {
final class ConfigInfo(
/// Original path being resolved.
final String path;
final String path,

/// Path to package configuration file, if any.
final String? configPath;
final String? configPath,

/// Package that path belongs to, if any.
final Package? package;
final Package? package,

/// Package URI for [path], if it has one.
/// Always `null` if [package] is `null`.
final Uri? packageUri;
final Uri? packageUri,

/// Language version override in file, if any.
final LanguageVersion? languageVersionOverride;

ConfigInfo(
this.path,
this.configPath,
this.package,
this.packageUri,
this.languageVersionOverride,
);
final LanguageVersion? languageVersionOverride,
) {

Map<String, Object?> toJson() {
return {
Expand Down Expand Up @@ -338,12 +331,13 @@ final leadRegExp = RegExp(
// --------------------------------------------------------------------
// Find and load (and cache) package configurations

class PackageConfigLoader {
class PackageConfigLoader({
/// Stop searching at the current working directory.
final bool noParent;
final bool noParent = false,

/// Stop searching if finding a `pubspec.yaml` with no package configuration.
final bool stopAtPubspec;
final bool stopAtPubspec = false,
}) {

/// Cache lookup results in case someone does more lookups on the same path.
final Map<
Expand All @@ -352,8 +346,6 @@ class PackageConfigLoader {
>
_packageConfigCache = {};

PackageConfigLoader({this.stopAtPubspec = false, this.noParent = false});

/// Finds a package configuration relative to [path].
///
/// Caches result for each directory looked at.
Expand Down
26 changes: 12 additions & 14 deletions pkgs/package_config/lib/src/errors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,30 @@
///
/// Only covers errors thrown while parsing package configuration files.
/// Programming errors and I/O exceptions are not covered.
abstract class PackageConfigError {
PackageConfigError._();
}
abstract interface class PackageConfigError {}

class PackageConfigArgumentError extends ArgumentError
implements PackageConfigError {
PackageConfigArgumentError(
implements PackageConfigError {

new( // Cannot be primary, `.from` cannot redirect to these types.
Object? super.value,
String super.name,
String super.message,
) : super.value();

PackageConfigArgumentError.from(ArgumentError error)
) : super.value();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially made this a primary constructor (using super-class arguments), but since all construction needs to go through the primary constructor, and this constructor restricts the types to non-nullable to require a name and message, the from() constructor could not redirect to it.

(That could be an argument for preferring an in-body declaring constructor, if you want other initializing constructors on the same class, which cannot be made to forward to the primary constructor.)

new from(ArgumentError error)
: super.value(error.invalidValue, error.name, error.message);
}

class PackageConfigFormatException extends FormatException
implements PackageConfigError {
PackageConfigFormatException(
class PackageConfigFormatException(
super.message,
Object? super.source, [
super.offset,
]);
]) extends FormatException
implements PackageConfigError {

PackageConfigFormatException.from(FormatException exception)
: super(exception.message, exception.source, exception.offset);
new from(FormatException exception)
: super.value(exception.message, exception.source, exception.offset);
}

/// The default `onError` handler.
Expand Down
96 changes: 41 additions & 55 deletions pkgs/package_config/lib/src/package_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import 'util.dart';
/// so classes outside of this package must not implement [PackageConfig]
/// or any subclass of it.
@sealed
abstract class PackageConfig {
abstract interface class PackageConfig {
/// The lowest configuration version currently supported.
static const int minVersion = 2;

Expand Down Expand Up @@ -56,7 +56,7 @@ abstract class PackageConfig {
/// [PackageConfig.extraData] of the created configuration.
///
/// The version of the resulting configuration is always [maxVersion].
factory PackageConfig(Iterable<Package> packages, {Object? extraData}) =>
factory(Iterable<Package> packages, {Object? extraData}) =>
SimplePackageConfig(maxVersion, packages, extraData);

/// Parses a package configuration file.
Expand Down Expand Up @@ -230,7 +230,7 @@ abstract class PackageConfig {

/// Configuration data for a single package.
@sealed
abstract class Package {
abstract interface class Package {
/// Creates a package with the provided properties.
///
/// The [name] must be a valid package name.
Expand All @@ -251,7 +251,7 @@ abstract class Package {
///
/// If [extraData] is supplied, it will be available as the
/// [Package.extraData] of the created package.
factory Package(
factory(
String name,
Uri root, {
Uri? packageUriRoot,
Expand Down Expand Up @@ -329,7 +329,8 @@ abstract class Package {
/// then an *invalid* language version may be represented by an
/// [InvalidLanguageVersion] object.
@sealed
abstract class LanguageVersion implements Comparable<LanguageVersion> {
abstract interface class LanguageVersion
implements Comparable<LanguageVersion> {
/// The maximal value allowed by [major] and [minor] values;
static const int maxValue = 0x7FFFFFFF;

Expand All @@ -338,7 +339,7 @@ abstract class LanguageVersion implements Comparable<LanguageVersion> {
///
/// Both [major] and [minor] must be greater than or equal to 0
/// and less than or equal to [maxValue].
factory LanguageVersion(int major, int minor) => SimpleLanguageVersion(
factory(int major, int minor) => SimpleLanguageVersion(
RangeError.checkValueInInterval(major, 0, maxValue, 'major'),
RangeError.checkValueInInterval(minor, 0, maxValue, 'minor'),
null,
Expand Down Expand Up @@ -424,7 +425,7 @@ abstract class LanguageVersion implements Comparable<LanguageVersion> {
/// The caller which provided the non-throwing `onError` handler
/// should be prepared to encounter invalid values.
@sealed
abstract class InvalidLanguageVersion implements LanguageVersion {
abstract interface class InvalidLanguageVersion implements LanguageVersion {
/// The value -1 for an invalid language version.
@override
int get major;
Expand Down Expand Up @@ -526,15 +527,21 @@ const bool _disallowPackagesInsidePackageUriRoot = false;
// Implementations of the main data types exposed by the API of this package.

@sealed
class SimplePackageConfig implements PackageConfig {
class SimplePackageConfig._(
this.version,
this._packageTree,
this._packages,
this.extraData,
) implements PackageConfig {

@override
final int version;
final Map<String, Package> _packages;
final PackageTree _packageTree;
@override
final Object? extraData;

factory SimplePackageConfig(
factory(
int version,
Iterable<Package> packages, [
Object? extraData,
Expand All @@ -549,13 +556,6 @@ class SimplePackageConfig implements PackageConfig {
}, extraData);
}

SimplePackageConfig._(
this.version,
this._packageTree,
this._packages,
this.extraData,
);

/// Creates empty configuration.
///
/// The empty configuration can be used in cases where no configuration is
Expand Down Expand Up @@ -738,28 +738,20 @@ class SimplePackageConfig implements PackageConfig {

/// Configuration data for a single package.
@sealed
class SimplePackage implements Package {
class SimplePackage._(
@override
final String name;
final String name,
@override
final Uri root;
final Uri root,
@override
final Uri packageUriRoot;
final Uri packageUriRoot,
@override
final LanguageVersion? languageVersion;
final LanguageVersion? languageVersion,
@override
final Object? extraData;
final Object? extraData,
@override
final bool relativeRoot;

SimplePackage._(
this.name,
this.root,
this.packageUriRoot,
this.languageVersion,
this.extraData,
this.relativeRoot,
);
final bool relativeRoot,
) implements Package {

/// Creates a [SimplePackage] with the provided content.
///
Expand Down Expand Up @@ -941,19 +933,17 @@ LanguageVersion parseLanguageVersion(
}

@sealed
class SimpleLanguageVersion implements LanguageVersion {
class SimpleLanguageVersion(
@override
final int major;
final int major,
@override
final int minor;

final int minor,
/// A cache for `toString`, pre-filled with source if created by parsing.
///
/// Also used by [SimpleInvalidLanguageVersion] for its invalid source
/// or a suitably invalid `toString` value.
String? _source;

SimpleLanguageVersion(this.major, this.minor, this._source);
String? _source,
) implements LanguageVersion {

@override
bool operator ==(Object other) =>
Expand All @@ -974,22 +964,22 @@ class SimpleLanguageVersion implements LanguageVersion {
}

@sealed
class SimpleInvalidLanguageVersion extends SimpleLanguageVersion
class SimpleInvalidLanguageVersion(String source)
extends SimpleLanguageVersion(-1, -1, source)
Copy link
Member Author

@lrhn lrhn Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without super-class arguments, this will be an in-body

  new(String source): super(-1, -1, source);

Just wanted to show what it would look like with super-class arguments. (Because I probably wouldn't use a primary constructor without it.)

implements InvalidLanguageVersion {
SimpleInvalidLanguageVersion(String source) : super(-1, -1, source);

@override
int get hashCode => identityHashCode(this);
@override
bool operator ==(Object other) => identical(this, other);
}

abstract class PackageTree {
abstract interface class PackageTree {
Iterable<Package> get allPackages;
SimplePackage? packageOf(Uri file);
}

class _PackageTrieNode {
class _PackageTrieNode() {
SimplePackage? package;

/// Indexed by path segment.
Expand All @@ -1008,7 +998,7 @@ class _PackageTrieNode {
/// The package root path of a package must not be inside another package's
/// root path.
/// Entire other packages are allowed inside a package's root.
class TriePackageTree implements PackageTree {
class TriePackageTree() implements PackageTree {
/// Indexed by URI scheme.
final Map<String, _PackageTrieNode> _map = {};

Expand Down Expand Up @@ -1155,9 +1145,7 @@ class TriePackageTree implements PackageTree {
}
}

class EmptyPackageTree implements PackageTree {
const EmptyPackageTree();

class const EmptyPackageTree() implements PackageTree {
@override
Iterable<Package> get allPackages => const Iterable<Package>.empty();

Expand All @@ -1184,18 +1172,16 @@ enum ConflictType { sameRoots, interleaving, insidePackageRoot }
/// The [package] conflicts with [existingPackage] if it has
/// the same root path or the package URI root path
/// of [existingPackage] is inside the root path of [package].
class ConflictException {
class ConflictException(
/// The existing package that [package] conflicts with.
final SimplePackage existingPackage;

final SimplePackage existingPackage,
/// The package that could not be added without a conflict.
final SimplePackage package;

final SimplePackage package,
/// Whether the conflict is with the package URI root of [existingPackage].
final ConflictType conflictType;

final ConflictType conflictType,
) {
/// Creates a root conflict between [package] and [existingPackage].
ConflictException(this.package, this.existingPackage, this.conflictType);
this;
}

/// Used for sorting packages by root path.
Expand Down
Loading