text: /* @flow */
  
  import type {Manifest, FetchedMetadata} from '../../types.js';
  import type PackageRequest from '../../package-request.js';
  import TarballFetcher from '../../fetchers/tarball-fetcher.js';
  import ExoticResolver from './exotic-resolver.js';
  import Git from './git-resolver.js';
  import * as versionUtil from '../../util/version.js';
  import * as crypto from '../../util/crypto.js';
  import * as fs from '../../util/fs.js';
  
  const invariant = require('invariant');
  
  export default class TarballResolver extends ExoticResolver {
    constructor(request: PackageRequest, fragment: string) {
      super(request, fragment);
  
      const {hash, url} = versionUtil.explodeHashedUrl(fragment);
      this.hash = hash;
      this.url = url;
    }
  
    url: string;
    hash: string;
  
    static isVersion(pattern: string): boolean {
      // we can sometimes match git urls which we don't want
      if (Git.isVersion(pattern)) {
        return false;
      }
  
      // full http url
      if (pattern.startsWith('http://') || pattern.startsWith('https://')) {
        return true;
      }
  
      // local file reference - ignore patterns with names
      if (pattern.indexOf('@') < 0) {
        if (pattern.endsWith('.tgz') || pattern.endsWith('tar.gz')) {
          return true;
        }
      }
  
      return false;
    }
  
    async resolve(): Promise<Manifest> {
      const shrunk = this.request.getLocked('tarball');
      if (shrunk) {
        return shrunk;
      }
  
      const {url} = this;
      let {hash, registry} = this;
      let pkgJson;
  
      // generate temp directory
      const dest = this.config.getTemp(crypto.hash(url));
  
      if (await this.config.isValidModuleDest(dest)) {
        // load from local cache
        ({package: pkgJson, hash, registry} = await this.config.readPackageMetadata(dest));
      } else {
        // delete if invalid
        await fs.unlink(dest);
  
        const fetcher = new TarballFetcher(dest, {
          type: 'tarball',
          reference: url,
          registry,
          hash,
        }, this.config, false);
  
        // fetch file and get it's hash
        const fetched: FetchedMetadata = await fetcher.fetch();
        pkgJson = fetched.package;
        hash = fetched.hash;
  
        registry = pkgJson._registry;
        invariant(registry, 'expected registry');
      }
  
      // use the commit/tarball hash as the uid as we can't rely on the version as it's not
      // in the registry
      pkgJson._uid = hash;
  
      // set remote so it can be "fetched"
      pkgJson._remote = {
        type: 'copy',
        resolved: `${url}#${hash}`,
        hash,
        registry,
        reference: dest,
      };
  
      return pkgJson;
    }
  }
  