import { isString } from 'lodash'; import * as npa from 'npm-package-arg'; import { Observable, of } from 'rxjs'; import { mergeMap } from 'rxjs/operators'; import { maxSatisfying } from 'semver'; import { resolve } from 'url'; import { OPTION_NAME } from '../constants'; import { assertParameter } from './assert'; import { rxGetJson } from './rx.download'; export function getMatchingVersion(aVersions: string[], aRange: string): string { // find all matches return maxSatisfying(aVersions, aRange); } export interface ParsedReference { name: string; spec: string; escapedName: string; } export function parseReference(aReference: string): ParsedReference { // parse const res = npa(aReference); // sanity check assertParameter(res.name, OPTION_NAME); assertParameter(res.escapedName, OPTION_NAME); // get the spec const spec = res.rawSpec ? (res.rawSpec === 'latest') ? '*' : res.rawSpec : '*'; // default return { name: res.name!, spec, escapedName: res.escapedName! }; } function _getPackageJsonFromResponse(aResp: any, aBaseUrl: string, aReference: ParsedReference): Observable { // read the versions const versions: string[] = Object.keys(aResp.versions); // select the best one const matching = getMatchingVersion(versions, aReference.spec); // now return the package const version = aResp.versions[matching]; if (isString(version)) { // make an extra request return rxGetJson(aBaseUrl + '/' + encodeURIComponent(matching)); } // default return of(version); } export function getPackageJson(aBaseUrl: string, aReference: ParsedReference): Observable { // the url const url = resolve(aBaseUrl, aReference.escapedName); // make the request return rxGetJson(url).pipe(mergeMap(resp => _getPackageJsonFromResponse(resp, url, aReference))); }