_ParseResult _parsePackage()

in lib/src/command/add.dart [297:435]


  _ParseResult _parsePackage(String package, LanguageVersion languageVersion) {
    final _conflictingFlagSets = [
      ['git-url', 'git-ref', 'git-path'],
      ['hosted-url'],
      ['path'],
      ['sdk'],
    ];

    for (final flag
        in _conflictingFlagSets.expand((s) => s).where(argResults.wasParsed)) {
      final conflictingFlag = _conflictingFlagSets
          .where((s) => !s.contains(flag))
          .expand((s) => s)
          .firstWhereOrNull(argResults.wasParsed);
      if (conflictingFlag != null) {
        usageException(
            'Packages can only have one source, "pub add" flags "--$flag" and '
            '"--$conflictingFlag" are conflicting.');
      }
    }

    /// The package to be added, along with the user-defined package constraints
    /// if present.
    PackageRange packageRange;

    /// The entry to be added to the pubspec. Assigned dynamic because it can
    /// take on either a string for simple version constraints or a map for
    /// more complicated hosted/git options.
    dynamic pubspecInformation;

    final splitPackage = package.split(':');
    final packageName = splitPackage[0];

    /// There shouldn't be more than one `:` in the package information
    if (splitPackage.length > 2) {
      usageException('Invalid package and version constraint: $package');
    }

    /// We want to allow for [constraint] to take on a `null` value here to
    /// preserve the fact that the user did not specify a constraint.
    VersionConstraint? constraint;

    try {
      constraint = splitPackage.length == 2
          ? VersionConstraint.parse(splitPackage[1])
          : null;
    } on FormatException catch (e) {
      usageException('Invalid version constraint: ${e.message}');
    }

    /// Determine the relevant [packageRange] and [pubspecInformation] depending
    /// on the type of package.
    var path = this.path;
    if (hasGitOptions) {
      dynamic git;

      if (gitUrl == null) {
        usageException('The `--git-url` is required for git dependencies.');
      }
      Uri parsed;
      try {
        parsed = Uri.parse(gitUrl!);
      } on FormatException catch (e) {
        usageException('The --git-url must be a valid url: ${e.message}.');
      }
      final urlRelativeToEntrypoint = parsed.isAbsolute
          ? parsed.toString()
          :
          // Turn the relative url from current working directory into a relative
          // url from the entrypoint.
          p.url.relative(
              p.url.join(Uri.file(p.absolute(p.current)).toString(),
                  parsed.toString()),
              from: p.toUri(p.absolute(entrypoint.root.dir)).toString());

      /// Process the git options to return the simplest representation to be
      /// added to the pubspec.
      if (gitRef == null && gitPath == null) {
        git = urlRelativeToEntrypoint;
      } else {
        git = {'url': urlRelativeToEntrypoint, 'ref': gitRef, 'path': gitPath};
        git.removeWhere((key, value) => value == null);
      }

      packageRange = cache.sources.git
          .parseRef(packageName, git, containingPath: entrypoint.pubspecPath)
          .withConstraint(constraint ?? VersionConstraint.any);
      pubspecInformation = {'git': git};
    } else if (path != null) {
      final relativeToEntryPoint = p.isRelative(path)
          ? PathSource.relativePathWithPosixSeparators(
              p.relative(path, from: entrypoint.root.dir))
          : path;
      packageRange = cache.sources.path
          .parseRef(packageName, relativeToEntryPoint,
              containingPath: entrypoint.pubspecPath)
          .withConstraint(constraint ?? VersionConstraint.any);
      pubspecInformation = {'path': relativeToEntryPoint};
    } else if (sdk != null) {
      packageRange = cache.sources.sdk
          .parseRef(packageName, sdk)
          .withConstraint(constraint ?? VersionConstraint.any);
      pubspecInformation = {'sdk': sdk};
    } else {
      // Hosted
      final Object? hostInfo;
      if (hasHostOptions) {
        hostInfo = languageVersion.supportsShorterHostedSyntax
            ? hostUrl
            : {'url': hostUrl, 'name': packageName};
        pubspecInformation = {
          'hosted': hostInfo,
        };
      } else {
        hostInfo = null;
        pubspecInformation = constraint?.toString();
      }

      packageRange = cache.hosted.source
          .parseRef(
            packageName,
            hostInfo,
            languageVersion: entrypoint.root.pubspec.languageVersion,
          )
          .withConstraint(constraint ?? VersionConstraint.any);
    }

    if (pubspecInformation is Map && constraint != null) {
      /// We cannot simply assign the value of version since it is likely that
      /// [pubspecInformation] takes on the type
      /// [Map<String, Map<String, String>>]
      pubspecInformation = {
        ...pubspecInformation,
        'version': constraint.toString()
      };
    }

    return _ParseResult(packageRange, pubspecInformation);
  }