UNPKG

@jspm/generator

Version:

Package Import Map Generation Tool

193 lines (191 loc) 8.85 kB
import { JspmError } from "../common/err.js"; import { baseUrl, isRelative } from "../common/url.js"; // @ts-ignore import sver from "sver"; const { SemverRange } = sver; // @ts-ignore import convertRange from "sver/convert-range.js"; import { builtinSchemes } from "../providers/index.js"; const supportedProtocols = [ "https", "http", "data", "file" ]; export async function parseUrlOrBuiltinTarget(resolver, targetStr, parentUrl) { const registryIndex = targetStr.indexOf(":"); if (isRelative(targetStr) || registryIndex !== -1 && supportedProtocols.includes(targetStr.slice(0, registryIndex)) || builtinSchemes.has(targetStr.slice(0, registryIndex))) { let target; let alias; let subpath = "."; const maybeBuiltin = builtinSchemes.has(targetStr.slice(0, registryIndex)) && resolver.resolveBuiltin(targetStr); if (maybeBuiltin) { if (typeof maybeBuiltin === "string") { throw new Error(`Builtin "${targetStr}" was resolved to package specifier ${maybeBuiltin}, but JSPM does not currently support installing specifiers for builtins.`); } else { ({ alias, subpath = ".", target } = maybeBuiltin); } } else { var _this; const subpathIndex = targetStr.indexOf("|"); if (subpathIndex !== -1) { subpath = `./${targetStr.slice(subpathIndex + 1)}`; targetStr = targetStr.slice(0, subpathIndex); } target = { pkgTarget: new URL(targetStr + (targetStr.endsWith("/") ? "" : "/"), parentUrl || baseUrl), installSubpath: null }; const pkgUrl = await resolver.getPackageBase(target.pkgTarget.href); alias = ((_this = pkgUrl ? await resolver.getPackageConfig(pkgUrl) : null) === null || _this === void 0 ? void 0 : _this.name) || target.pkgTarget.pathname.split("/").slice(0, -1).pop(); } if (!alias) throw new JspmError(`Unable to determine an alias for target package ${targetStr}`); return { alias, target, subpath }; } } // ad-hoc determination of local path v remote package for eg "jspm deno react" v "jspm deno react@2" v "jspm deno ./react.ts" v "jspm deno react.ts" const supportedRegistries = [ "npm", "github", "deno", "nest", "denoland" ]; export function isPackageTarget(targetStr) { if (isRelative(targetStr)) return false; const registryIndex = targetStr.indexOf(":"); if (registryIndex !== -1 && supportedRegistries.includes(targetStr.slice(0, registryIndex))) return true; const pkg = parsePkg(targetStr); if (!pkg) return false; if (pkg.pkgName.indexOf("@") !== -1) return true; if (targetStr.endsWith(".ts") || targetStr.endsWith(".js") || targetStr.endsWith(".mjs")) return false; return true; } export async function parseTarget(resolver, targetStr, parentPkgUrl, defaultRegistry) { const urlTarget = await parseUrlOrBuiltinTarget(resolver, targetStr, parentPkgUrl); if (urlTarget) return urlTarget; // TODO: package aliases support as per https://github.com/npm/rfcs/blob/latest/implemented/0001-package-aliases.md const registryIndex = targetStr.indexOf(":"); const versionOrScopeIndex = targetStr.indexOf("@"); if (targetStr.indexOf(":") !== -1 && versionOrScopeIndex !== -1 && versionOrScopeIndex < registryIndex) throw new Error(`Package aliases not yet supported. PRs welcome.`); const pkg = parsePkg(registryIndex === -1 ? targetStr : targetStr.slice(registryIndex + 1)); if (!pkg) throw new JspmError(`Invalid package name ${targetStr}`); let registry = null; if (registryIndex !== -1) registry = targetStr.slice(0, registryIndex); let alias = pkg.pkgName; const versionIndex = pkg.pkgName.indexOf("@", 1); if (versionIndex !== -1) alias = pkg.pkgName.slice(0, versionIndex); else alias = pkg.pkgName; // If no version is specified, we fallback to the constraints in the parent // package config if they exist: const pcfg = await resolver.getPackageConfig(parentPkgUrl.href); if (versionIndex === -1 && pcfg) { var _pcfg_dependencies, _pcfg_peerDependencies, _pcfg_optionalDependencies, _pcfg_devDependencies; const dep = ((_pcfg_dependencies = pcfg.dependencies) === null || _pcfg_dependencies === void 0 ? void 0 : _pcfg_dependencies[alias]) || ((_pcfg_peerDependencies = pcfg.peerDependencies) === null || _pcfg_peerDependencies === void 0 ? void 0 : _pcfg_peerDependencies[alias]) || ((_pcfg_optionalDependencies = pcfg.optionalDependencies) === null || _pcfg_optionalDependencies === void 0 ? void 0 : _pcfg_optionalDependencies[alias]) || ((_pcfg_devDependencies = pcfg.devDependencies) === null || _pcfg_devDependencies === void 0 ? void 0 : _pcfg_devDependencies[alias]); if (dep) { return { target: newPackageTarget(dep, parentPkgUrl, registry || defaultRegistry, pkg.pkgName), alias, subpath: pkg.subpath }; } } // Otherwise we construct a package target from what we were given: return { target: newPackageTarget(pkg.pkgName, parentPkgUrl, registry || defaultRegistry), alias, subpath: pkg.subpath }; } export function newPackageTarget(target, parentPkgUrl, defaultRegistry, pkgName) { if (target === ".") { // useful shorthand target = "./"; } let registry, name, ranges; const registryIndex = target.indexOf(":"); if (target.startsWith("./") || target.startsWith("../") || target.startsWith("/") || registryIndex === 1) return { pkgTarget: new URL(target, parentPkgUrl), installSubpath: null }; registry = registryIndex < 1 ? defaultRegistry : target.slice(0, registryIndex); if (registry === "file") return { pkgTarget: new URL(target.slice(registry.length + 1), parentPkgUrl), installSubpath: null }; if (registry === "https" || registry === "http") return { pkgTarget: new URL(target), installSubpath: null }; const versionIndex = target.lastIndexOf("@"); let unstable = false; if (versionIndex > registryIndex + 1) { name = target.slice(registryIndex + 1, versionIndex); const version = target.slice(versionIndex + 1); ranges = pkgName || SemverRange.isValid(version) ? [ new SemverRange(version) ] : version.split("||").map((v)=>convertRange(v)); if (version === "") unstable = true; } else if (registryIndex === -1 && pkgName) { name = pkgName; ranges = SemverRange.isValid(target) ? [ new SemverRange(target) ] : target.split("||").map((v)=>convertRange(v)); } else { name = target.slice(registryIndex + 1); ranges = [ new SemverRange("*") ]; } if (registryIndex === -1 && name.indexOf("/") !== -1 && name[0] !== "@") registry = "github"; const targetNameLen = name.split("/").length; if (targetNameLen > 2 || targetNameLen === 1 && name[0] === "@") throw new JspmError(`Invalid package target ${target}`); return { pkgTarget: { registry, name, ranges, unstable }, installSubpath: null }; } export function pkgToStr(pkg) { return `${pkg.registry ? pkg.registry + ":" : ""}${pkg.name}${pkg.version ? "@" + pkg.version : ""}`; } /** * Throws unless the given specifier is a valid npm-style package specifier. * * @param {string} specifier Specifier to validate. */ export function validatePkgName(specifier) { const parsed = parsePkg(specifier); if (!parsed || parsed.subpath !== ".") throw new Error(`"${specifier}" is not a valid npm-style package name. Subpaths must be provided separately to the installation package name.`); } /** * Parses an npm-style module specifier, such as '@jspm/generator/index.js', * and splits it into the package name ('@jspm/generator') and module subpath * ('./index.js'). Returns undefined if the given specifier is invalid. * * @param {string} specifier Specifier to parse. * @returns {{ pkgName: string, subpath: '.' | `./${string}` } | undefined} */ export function parsePkg(specifier) { let sepIndex = specifier.indexOf("/"); if (specifier[0] === "@") { if (sepIndex === -1) return; sepIndex = specifier.indexOf("/", sepIndex + 1); } // TODO: Node.js validations like percent encodng checks if (sepIndex === -1) return { pkgName: specifier, subpath: "." }; return { pkgName: specifier.slice(0, sepIndex), subpath: `.${specifier.slice(sepIndex)}` }; } //# sourceMappingURL=package.js.map