@jspm/generator
Version:
Package Import Map Generation Tool
1,277 lines (1,258 loc) • 209 kB
JavaScript
import sver, { SemverRange as SemverRange$2, Semver as Semver$1 } from 'sver';
import convertRange from 'sver/convert-range.js';
import { fetch as fetch$1, clearCache as clearCache$1 } from '#fetch';
import { ImportMap, getScopeMatches, getMapMatch as getMapMatch$1 } from '@jspm/import-map';
import process$1 from 'process';
import { parse } from 'es-module-lexer/js';
import { init, parse as parse$1 } from 'es-module-lexer';
import { s as setRetryCount } from './fetch-common-3aa262c0.js';
let _nodeCrypto;
async function getIntegrityNodeLegacy(buf) {
const hash = (_nodeCrypto || (_nodeCrypto = await (0, eval)('import("node:crypto")'))).createHash("sha384");
hash.update(buf);
return `sha384-${hash.digest("base64")}`;
}
let getIntegrity = async function getIntegrity(buf) {
const data = typeof buf === "string" ? new TextEncoder().encode(buf) : buf;
const hashBuffer = await crypto.subtle.digest("SHA-384", data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashBase64 = btoa(String.fromCharCode(...hashArray));
return `sha384-${hashBase64}`;
};
if (typeof crypto === "undefined") getIntegrity = getIntegrityNodeLegacy;
// See: https://nodejs.org/docs/latest/api/modules.html#the-module-scope
const cjsGlobals = [
"__dirname",
"__filename",
"exports",
"module",
"require"
];
let babel$1;
function setBabel$1(_babel) {
babel$1 = _babel;
}
async function createCjsAnalysis(imports, source, url) {
if (!babel$1) babel$1 = await import('@babel/core');
const requires = new Set();
const lazy = new Set();
const unboundGlobals = new Set();
babel$1.transform(source, {
ast: false,
sourceMaps: false,
inputSourceMap: false,
babelrc: false,
babelrcRoots: false,
configFile: false,
highlightCode: false,
compact: false,
sourceType: "script",
parserOpts: {
allowReturnOutsideFunction: true,
// plugins: stage3Syntax,
errorRecovery: true
},
plugins: [
({ types: t })=>{
return {
visitor: {
Program (path, state) {
state.functionDepth = 0;
},
CallExpression (path, state) {
if (t.isIdentifier(path.node.callee, {
name: "require"
}) || t.isIdentifier(path.node.callee.object, {
name: "require"
}) && t.isIdentifier(path.node.callee.property, {
name: "resolve"
}) || t.isMemberExpression(path.node.callee) && t.isIdentifier(path.node.callee.object, {
name: "module"
}) && t.isIdentifier(path.node.callee.property, {
name: "require"
})) {
const req = buildDynamicString$1(path.get("arguments.0").node, url);
requires.add(req);
if (state.functionDepth > 0) lazy.add(req);
}
},
ReferencedIdentifier (path) {
let identifierName = path.node.name;
if (!path.scope.hasBinding(identifierName)) {
unboundGlobals.add(identifierName);
}
},
Scope: {
enter (path, state) {
if (t.isFunction(path.scope.block)) state.functionDepth++;
},
exit (path, state) {
if (t.isFunction(path.scope.block)) state.functionDepth--;
}
}
}
};
}
]
});
// Check if the module actually uses any CJS-specific globals, as otherwise
// other host runtimes like browser/deno can run this module anyway:
let usesCjs = false;
for (let g of cjsGlobals){
if (unboundGlobals.has(g)) {
usesCjs = true;
break;
}
}
return {
deps: [
...requires
],
dynamicDeps: imports.filter((impt)=>impt.n).map((impt)=>impt.n),
cjsLazyDeps: [
...lazy
],
size: source.length,
format: "commonjs",
usesCjs,
integrity: await getIntegrity(source)
};
}
function buildDynamicString$1(node, fileName, isEsm = false, lastIsWildcard = false) {
if (node.type === "StringLiteral") {
return node.value;
}
if (node.type === "TemplateLiteral") {
let str = "";
for(let i = 0; i < node.quasis.length; i++){
const quasiStr = node.quasis[i].value.cooked;
if (quasiStr.length) {
str += quasiStr;
lastIsWildcard = false;
}
const nextNode = node.expressions[i];
if (nextNode) {
const nextStr = buildDynamicString$1(nextNode, fileName, isEsm, lastIsWildcard);
if (nextStr.length) {
lastIsWildcard = nextStr.endsWith("*");
str += nextStr;
}
}
}
return str;
}
if (node.type === "BinaryExpression" && node.operator === "+") {
const leftResolved = buildDynamicString$1(node.left, fileName, isEsm, lastIsWildcard);
if (leftResolved.length) lastIsWildcard = leftResolved.endsWith("*");
const rightResolved = buildDynamicString$1(node.right, fileName, isEsm, lastIsWildcard);
return leftResolved + rightResolved;
}
if (node.type === "Identifier") {
if (node.name === "__dirname") return ".";
if (node.name === "__filename") return "./" + fileName;
}
// TODO: proper expression support
// new URL('...', import.meta.url).href | new URL('...', import.meta.url).toString() | new URL('...', import.meta.url).pathname
// import.meta.X
/*if (isEsm && node.type === 'MemberExpression' && node.object.type === 'MetaProperty' &&
node.object.meta.type === 'Identifier' && node.object.meta.name === 'import' &&
node.object.property.type === 'Identifier' && node.object.property.name === 'meta') {
if (node.property.type === 'Identifier' && node.property.name === 'url') {
return './' + fileName;
}
}*/ return lastIsWildcard ? "" : "*";
}
let babel, babelPresetTs, babelPluginImportAttributes;
function setBabel(_babel, _babelPresetTs, _babelPluginImportAttributes) {
babel = _babel, babelPresetTs = _babelPresetTs, babelPluginImportAttributes = _babelPluginImportAttributes;
}
const globalConsole = globalThis.console;
const dummyConsole = {
log () {},
warn () {},
memory () {},
assert () {},
clear () {},
count () {},
countReset () {},
debug () {},
dir () {},
dirxml () {},
error () {},
exception () {},
group () {},
groupCollapsed () {},
groupEnd () {},
info () {},
table () {},
time () {},
timeEnd () {},
timeLog () {},
timeStamp () {},
trace () {}
};
async function createTsAnalysis(source, url) {
if (!babel) [babel, { default: babelPresetTs }, { default: babelPluginImportAttributes }] = await Promise.all([
import('@babel/core'),
import('@babel/preset-typescript'),
import('@babel/plugin-syntax-import-attributes')
]);
const imports = new Set();
const dynamicImports = new Set();
// @ts-ignore
globalThis.console = dummyConsole;
try {
babel.transform(source, {
filename: "/" + url,
ast: false,
sourceMaps: false,
inputSourceMap: false,
babelrc: false,
babelrcRoots: false,
configFile: false,
highlightCode: false,
compact: false,
sourceType: "module",
parserOpts: {
plugins: [
"jsx"
],
errorRecovery: true
},
presets: [
[
babelPresetTs,
{
onlyRemoveTypeImports: true
}
]
],
plugins: [
babelPluginImportAttributes,
()=>{
return {
visitor: {
ExportAllDeclaration (path) {
if (path.node.exportKind !== "type") imports.add(path.node.source.value);
},
ExportNamedDeclaration (path) {
if (path.node.source) imports.add(path.node.source.value);
},
ImportDeclaration (path) {
if (path.node.exportKind !== "type") imports.add(path.node.source.value);
},
Import (path) {
dynamicImports.add(buildDynamicString(path.parentPath.get("arguments.0").node, url, true));
}
}
};
}
]
});
} finally{
globalThis.console = globalConsole;
}
return {
deps: [
...imports
],
dynamicDeps: [
...dynamicImports
],
cjsLazyDeps: null,
size: source.length,
format: "typescript",
integrity: await getIntegrity(source)
};
}
// We use the special character \x10 as a "wildcard symbol"
function buildDynamicString(node, fileName, isEsm = false, lastIsWildcard = false) {
if (node.type === "StringLiteral") {
return node.value;
}
if (node.type === "TemplateLiteral") {
let str = "";
for(let i = 0; i < node.quasis.length; i++){
const quasiStr = node.quasis[i].value.cooked;
if (quasiStr.length) {
str += quasiStr;
lastIsWildcard = false;
}
const nextNode = node.expressions[i];
if (nextNode) {
const nextStr = buildDynamicString(nextNode, fileName, isEsm, lastIsWildcard);
if (nextStr.length) {
lastIsWildcard = nextStr.endsWith("\x10");
str += nextStr;
}
}
}
return str;
}
if (node.type === "BinaryExpression" && node.operator === "+") {
const leftResolved = buildDynamicString(node.left, fileName, isEsm, lastIsWildcard);
if (leftResolved.length) lastIsWildcard = leftResolved.endsWith("\x10");
const rightResolved = buildDynamicString(node.right, fileName, isEsm, lastIsWildcard);
return leftResolved + rightResolved;
}
if (isEsm && node.type === "Identifier") {
if (node.name === "__dirname") return ".";
if (node.name === "__filename") return "./" + fileName;
}
// TODO: proper expression support
// new URL('...', import.meta.url).href | new URL('...', import.meta.url).toString() | new URL('...', import.meta.url).pathname
// import.meta.X
/*if (isEsm && node.type === 'MemberExpression' && node.object.type === 'MetaProperty' &&
node.object.meta.type === 'Identifier' && node.object.meta.name === 'import' &&
node.object.property.type === 'Identifier' && node.object.property.name === 'meta') {
if (node.property.type === 'Identifier' && node.property.name === 'url') {
return './' + fileName;
}
}*/ return lastIsWildcard ? "" : "\x10";
}
function _define_property$5(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
class JspmError extends Error {
constructor(msg, code){
super(msg), _define_property$5(this, "jspmError", true), _define_property$5(this, "code", void 0);
this.code = code;
}
}
function throwInternalError(...args) {
throw new Error("Internal Error" + (args.length ? " " + args.join(", ") : ""));
}
// @ts-ignore
let retryCount = 5, poolSize = 100;
let _fetch = wrappedFetch(fetch$1);
/**
* Allows customizing the fetch implementation used by the generator.
*/ function setFetch(fetch) {
_fetch = wrappedFetch(fetch);
}
/**
* Wraps a fetch request with pooling, and retry logic on exceptions (emfile / network errors).
*/ function wrappedFetch(fetch) {
const wrappedFetch = async function(url, ...args) {
url = url.toString();
let retries = 0;
try {
await pushFetchPool();
while(true){
try {
return await fetch(url, ...args);
} catch (e) {
if (retries++ >= retryCount) throw e;
}
}
} finally{
popFetchPool();
}
};
wrappedFetch.arrayBuffer = async function(url, ...args) {
url = url.toString();
let retries = 0;
try {
await pushFetchPool();
while(true){
try {
var res = await fetch(url, ...args);
} catch (e) {
if (retries++ >= retryCount) throw e;
continue;
}
switch(res.status){
case 200:
case 304:
break;
// not found = null
case 404:
return null;
default:
throw new Error(`Invalid status code ${res.status}`);
}
try {
return await res.arrayBuffer();
} catch (e) {
if (retries++ >= retryCount && e.code === "ERR_SOCKET_TIMEOUT" || e.code === "ETIMEOUT" || e.code === "ECONNRESET" || e.code === "FETCH_ERROR") {}
}
}
} finally{
popFetchPool();
}
};
wrappedFetch.text = async function(url, ...args) {
const arrayBuffer = await this.arrayBuffer(url, ...args);
if (!arrayBuffer) return null;
return new TextDecoder().decode(arrayBuffer);
};
return wrappedFetch;
}
// restrict in-flight fetches to a pool of 100
let p = [];
let c = 0;
function pushFetchPool() {
if (++c > poolSize) return new Promise((r)=>p.push(r));
}
function popFetchPool() {
c--;
if (p.length) p.shift()();
}
function isFetchProtocol(protocol) {
return protocol === "file:" || protocol === "https:" || protocol === "http:" || protocol === "data:";
}
let baseUrl;
// @ts-ignore
if (typeof Deno !== "undefined") {
// @ts-ignore
const denoCwd = Deno.cwd();
baseUrl = new URL("file://" + (denoCwd[0] === "/" ? "" : "/") + denoCwd + "/");
} else if (typeof process !== "undefined" && process.versions.node) {
baseUrl = new URL("file://" + process.cwd() + "/");
} else if (typeof document !== "undefined") {
baseUrl = new URL(document.baseURI);
}
if (!baseUrl && typeof location !== "undefined") {
baseUrl = new URL(location.href);
}
baseUrl.search = baseUrl.hash = "";
function resolveUrl(url, mapUrl, rootUrl) {
if (url.startsWith("/")) return rootUrl ? new URL("." + url.slice(url[1] === "/" ? 1 : 0), rootUrl).href : url;
return new URL(url, mapUrl).href;
}
function importedFrom(parentUrl) {
if (!parentUrl) return "";
return ` imported from ${parentUrl}`;
}
function matchesRoot(url, baseUrl) {
return url.protocol === baseUrl.protocol && url.host === baseUrl.host && url.port === baseUrl.port && url.username === baseUrl.username && url.password === baseUrl.password;
}
function relativeUrl(url, baseUrl, absolute = false) {
const href = url.href;
let baseUrlHref = baseUrl.href;
if (!baseUrlHref.endsWith("/")) baseUrlHref += "/";
if (href.startsWith(baseUrlHref)) return (absolute ? "/" : "./") + href.slice(baseUrlHref.length);
if (!matchesRoot(url, baseUrl)) return url.href;
if (absolute) return url.href;
const baseUrlPath = baseUrl.pathname;
const urlPath = url.pathname;
const minLen = Math.min(baseUrlPath.length, urlPath.length);
let sharedBaseIndex = -1;
for(let i = 0; i < minLen; i++){
if (baseUrlPath[i] !== urlPath[i]) break;
if (urlPath[i] === "/") sharedBaseIndex = i;
}
return "../".repeat(baseUrlPath.slice(sharedBaseIndex + 1).split("/").length - 1) + urlPath.slice(sharedBaseIndex + 1) + url.search + url.hash;
}
function isURL(specifier) {
try {
if (specifier[0] === "#") return false;
new URL(specifier);
} catch {
return false;
}
return true;
}
function isPlain(specifier) {
return !isRelative(specifier) && !isURL(specifier);
}
function isRelative(specifier) {
return specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/");
}
const cdnUrl$5 = "https://deno.land/x/";
const stdlibUrl = "https://deno.land/std";
let denoStdVersion;
function resolveBuiltin$1(specifier, env) {
// Bare npm:XXX imports are supported by Deno:
if (env.includes("deno") && specifier.startsWith("npm:")) return specifier;
if (specifier.startsWith("deno:")) {
let name = specifier.slice(5);
if (name.endsWith(".ts")) name = name.slice(0, -3);
let alias = name, subpath = ".";
const slashIndex = name.indexOf("/");
if (slashIndex !== -1) {
alias = name.slice(0, slashIndex);
subpath = `./${name.slice(slashIndex + 1)}`;
}
return {
alias,
subpath,
target: {
pkgTarget: {
registry: "deno",
name: "std",
ranges: [
new SemverRange$2("*")
],
unstable: true
},
installSubpath: `./${slashIndex === -1 ? name : name.slice(0, slashIndex)}`
}
};
}
}
async function pkgToUrl$6(pkg) {
if (pkg.registry === "deno") return `${stdlibUrl}@${pkg.version}/`;
if (pkg.registry === "denoland") return `${cdnUrl$5}${pkg.name}@${vCache[pkg.name] ? "v" : ""}${pkg.version}/`;
throw new Error(`Deno provider does not support the ${pkg.registry} registry for package "${pkg.name}" - perhaps you mean to install "denoland:${pkg.name}"?`);
}
async function getPackageConfig$3(pkgUrl) {
if (pkgUrl.startsWith("https://deno.land/std@")) {
return {
exports: {
"./archive": "./archive/mod.ts",
"./archive/*.ts": "./archive/*.ts",
"./archive/*": "./archive/*.ts",
"./async": "./async/mod.ts",
"./async/*.ts": "./async/*.ts",
"./async/*": "./async/*.ts",
"./bytes": "./bytes/mod.ts",
"./bytes/*.ts": "./bytes/*.ts",
"./bytes/*": "./bytes/*.ts",
"./collection": "./collection/mod.ts",
"./collection/*.ts": "./collection/*.ts",
"./collection/*": "./collection/*.ts",
"./crypto": "./crypto/mod.ts",
"./crypto/*.ts": "./crypto/*.ts",
"./crypto/*": "./crypto/*.ts",
"./datetime": "./datetime/mod.ts",
"./datetime/*.ts": "./datetime/*.ts",
"./datetime/*": "./datetime/*.ts",
"./dotenv": "./dotenv/mod.ts",
"./dotenv/*.ts": "./dotenv/*.ts",
"./dotenv/*": "./dotenv/*.ts",
"./encoding": "./encoding/mod.ts",
"./encoding/*.ts": "./encoding/*.ts",
"./encoding/*": "./encoding/*.ts",
"./examples": "./examples/mod.ts",
"./examples/*.ts": "./examples/*.ts",
"./examples/*": "./examples/*.ts",
"./flags": "./flags/mod.ts",
"./flags/*.ts": "./flags/*.ts",
"./flags/*": "./flags/*.ts",
"./fmt": "./fmt/mod.ts",
"./fmt/*.ts": "./fmt/*.ts",
"./fmt/*": "./fmt/*.ts",
"./fs": "./fs/mod.ts",
"./fs/*.ts": "./fs/*.ts",
"./fs/*": "./fs/*.ts",
"./hash": "./hash/mod.ts",
"./hash/*.ts": "./hash/*.ts",
"./hash/*": "./hash/*.ts",
"./http": "./http/mod.ts",
"./http/*.ts": "./http/*.ts",
"./http/*": "./http/*.ts",
"./io": "./io/mod.ts",
"./io/*.ts": "./io/*.ts",
"./io/*": "./io/*.ts",
"./log": "./log/mod.ts",
"./log/*.ts": "./log/*.ts",
"./log/*": "./log/*.ts",
"./media_types": "./media_types/mod.ts",
"./media_types/*.ts": "./media_types/*.ts",
"./media_types/*": "./media_types/*.ts",
"./node": "./node/mod.ts",
"./node/*.ts": "./node/*.ts",
"./node/*": "./node/*.ts",
"./path": "./path/mod.ts",
"./path/*.ts": "./path/*.ts",
"./path/*": "./path/*.ts",
"./permissions": "./permissions/mod.ts",
"./permissions/*.ts": "./permissions/*.ts",
"./permissions/*": "./permissions/*.ts",
"./signal": "./signal/mod.ts",
"./signal/*.ts": "./signal/*.ts",
"./signal/*": "./signal/*.ts",
"./streams": "./streams/mod.ts",
"./streams/*.ts": "./streams/*.ts",
"./streams/*": "./streams/*.ts",
"./testing": "./testing/mod.ts",
"./testing/*.ts": "./testing/*.ts",
"./testing/*": "./testing/*.ts",
"./textproto": "./textproto/mod.ts",
"./textproto/*.ts": "./textproto/*.ts",
"./textproto/*": "./textproto/*.ts",
"./uuid": "./uuid/mod.ts",
"./uuid/*.ts": "./uuid/*.ts",
"./uuid/*": "./uuid/*.ts",
"./version": "./version.ts",
"./version.ts": "./version.ts",
"./wasi": "./wasi/mod.ts",
"./wasi/*.ts": "./wasi/*.ts",
"./wasi/*": "./wasi*.ts"
}
};
}
// If there's a package.json, return that:
const pkgJsonUrl = new URL("package.json", pkgUrl);
const pkgRes = await _fetch(pkgJsonUrl.href, this.fetchOpts);
switch(pkgRes.status){
case 200:
case 304:
return await pkgRes.json();
}
return null;
}
const vCache = {};
function parseUrlPkg$7(url) {
let subpath = null;
if (url.startsWith(stdlibUrl) && url[stdlibUrl.length] === "@") {
const version = url.slice(stdlibUrl.length + 1, url.indexOf("/", stdlibUrl.length + 1));
subpath = url.slice(stdlibUrl.length + version.length + 2);
if (subpath.endsWith("/mod.ts")) subpath = subpath.slice(0, -7);
else if (subpath.endsWith(".ts")) subpath = subpath.slice(0, -3);
const name = subpath.indexOf("/") === -1 ? subpath : subpath.slice(0, subpath.indexOf("/"));
return {
pkg: {
registry: "deno",
name: "std",
version
},
layer: "default",
subpath: `./${name}${subpath ? `./${subpath}/mod.ts` : ""}`
};
} else if (url.startsWith(cdnUrl$5)) {
const path = url.slice(cdnUrl$5.length);
const versionIndex = path.indexOf("@");
if (versionIndex === -1) return;
const sepIndex = path.indexOf("/", versionIndex);
const name = path.slice(0, versionIndex);
const version = path.slice(versionIndex + ((vCache[name] = path[versionIndex + 1] === "v") ? 2 : 1), sepIndex === -1 ? path.length : sepIndex);
return {
pkg: {
registry: "denoland",
name,
version
},
subpath: null,
layer: "default"
};
}
}
async function resolveLatestTarget$6(target, _layer, parentUrl) {
let { registry, name, range } = target;
if (denoStdVersion && registry === "deno") return {
registry,
name,
version: denoStdVersion
};
if (range.isExact) return {
registry,
name,
version: range.version.toString()
};
// convert all Denoland ranges into wildcards
// since we don't have an actual semver lookup at the moment
if (!range.isWildcard) range = new SemverRange$2(range.version.toString());
const fetchOpts = {
...this.fetchOpts,
headers: Object.assign({}, this.fetchOpts.headers || {}, {
// For some reason, Deno provides different redirect behaviour for the server
// Which requires us to use the text/html accept
accept: typeof document === "undefined" ? "text/html" : "text/javascript"
})
};
// "mod.ts" addition is necessary for the browser otherwise not resolving an exact module gives a CORS error
const fetchUrl = registry === "denoland" ? cdnUrl$5 + name + "/mod.ts" : stdlibUrl + "/version.ts";
const res = await _fetch(fetchUrl, fetchOpts);
if (!res.ok) throw new Error(`Deno: Unable to lookup ${fetchUrl}`);
const { version } = (await parseUrlPkg$7(res.url)).pkg;
if (registry === "deno") denoStdVersion = version;
return {
registry,
name,
version
};
}
var deno = /*#__PURE__*/Object.freeze({
__proto__: null,
resolveBuiltin: resolveBuiltin$1,
pkgToUrl: pkgToUrl$6,
getPackageConfig: getPackageConfig$3,
parseUrlPkg: parseUrlPkg$7,
resolveLatestTarget: resolveLatestTarget$6
});
const { SemverRange: SemverRange$1 } = sver;
const supportedProtocols = [
"https",
"http",
"data",
"file"
];
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
};
}
}
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
};
}
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$1.isValid(version) ? [
new SemverRange$1(version)
] : version.split("||").map((v)=>convertRange(v));
if (version === "") unstable = true;
} else if (registryIndex === -1 && pkgName) {
name = pkgName;
ranges = SemverRange$1.isValid(target) ? [
new SemverRange$1(target)
] : target.split("||").map((v)=>convertRange(v));
} else {
name = target.slice(registryIndex + 1);
ranges = [
new SemverRange$1("*")
];
}
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
};
}
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.
*/ 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}
*/ 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)}`
};
}
let cdnUrl$4 = "https://ga.jspm.io/";
const systemCdnUrl = "https://ga.system.jspm.io/";
const apiUrl = "https://api.jspm.io/";
const BUILD_POLL_TIME = 60 * 1000;
const BUILD_POLL_INTERVAL = 5 * 1000;
const supportedLayers = [
"default",
"system"
];
async function pkgToUrl$5(pkg, layer) {
return `${layer === "system" ? systemCdnUrl : cdnUrl$4}${pkgToStr(pkg)}/`;
}
function configure(config) {
if (config.cdnUrl) cdnUrl$4 = config.cdnUrl;
}
const exactPkgRegEx$4 = /^(([a-z]+):)?((?:@[^/\\%@]+\/)?[^./\\%@][^/\\%@]*)@([^\/]+)(\/.*)?$/;
function parseUrlPkg$6(url) {
let subpath = null;
let layer;
if (url.startsWith(cdnUrl$4)) layer = "default";
else if (url.startsWith(systemCdnUrl)) layer = "system";
else return;
const [, , registry, name, version] = url.slice((layer === "default" ? cdnUrl$4 : systemCdnUrl).length).match(exactPkgRegEx$4) || [];
if (registry && name && version) {
if (registry === "npm" && name === "@jspm/core" && url.includes("/nodelibs/")) {
subpath = `./nodelibs/${url.slice(url.indexOf("/nodelibs/") + 10).split("/")[1]}`;
if (subpath && subpath.endsWith(".js")) subpath = subpath.slice(0, -3);
else subpath = null;
}
return {
pkg: {
registry,
name,
version
},
layer,
subpath
};
}
}
function getJspmCache(resolver) {
const jspmCache = resolver.context.jspmCache;
if (!resolver.context.jspmCache) {
return resolver.context.jspmCache = {
lookupCache: new Map(),
versionsCacheMap: new Map(),
resolveCache: {},
cachedErrors: new Map(),
buildRequested: new Map()
};
}
return jspmCache;
}
async function checkBuildOrError(resolver, pkgUrl, fetchOpts) {
const pcfg = await resolver.getPackageConfig(pkgUrl);
if (pcfg) {
return true;
}
const { cachedErrors } = getJspmCache(resolver);
// no package.json! Check if there's a build error:
if (cachedErrors.has(pkgUrl)) return cachedErrors.get(pkgUrl);
const cachedErrorPromise = (async ()=>{
try {
const errLog = await _fetch.text(`${pkgUrl}/_error.log`, fetchOpts);
throw new JspmError(`Resolved dependency ${pkgUrl} with error:\n\n${errLog}\nPlease post an issue at jspm/project on GitHub, or by following the link below:\n\nhttps://github.com/jspm/project/issues/new?title=CDN%20build%20error%20for%20${encodeURIComponent(pkgUrl)}&body=_Reporting%20CDN%20Build%20Error._%0A%0A%3C!--%20%20No%20further%20description%20necessary,%20just%20click%20%22Submit%20new%20issue%22%20--%3E`);
} catch (e) {
return false;
}
})();
cachedErrors.set(pkgUrl, cachedErrorPromise);
return cachedErrorPromise;
}
async function ensureBuild(resolver, pkg, fetchOpts) {
if (await checkBuildOrError(resolver, await pkgToUrl$5(pkg, "default"), fetchOpts)) return;
const fullName = `${pkg.name}@${pkg.version}`;
const { buildRequested } = getJspmCache(resolver);
// no package.json AND no build error -> post a build request
// once the build request has been posted, try polling for up to 2 mins
if (buildRequested.has(fullName)) return buildRequested.get(fullName);
const buildPromise = (async ()=>{
const buildRes = await _fetch(`${apiUrl}build/${fullName}`, fetchOpts);
if (!buildRes.ok && buildRes.status !== 403) {
const err = (await buildRes.json()).error;
throw new JspmError(`Unable to request the JSPM API for a build of ${fullName}, with error: ${err}.`);
}
// build requested -> poll on that
let startTime = Date.now();
while(true){
await new Promise((resolve)=>setTimeout(resolve, BUILD_POLL_INTERVAL));
if (await checkBuildOrError(resolver, await pkgToUrl$5(pkg, "default"), fetchOpts)) return;
if (Date.now() - startTime >= BUILD_POLL_TIME) throw new JspmError(`Timed out waiting for the build of ${fullName} to be ready on the JSPM CDN. Try again later, or post a jspm.io project issue at https://github.com/jspm/project if the problem persists.`);
}
})();
buildRequested.set(fullName, buildPromise);
return buildPromise;
}
async function resolveLatestTarget$5(target, layer, parentUrl) {
const { registry, name, range, unstable } = target;
// exact version optimization
if (range.isExact && !range.version.tag) {
const pkg = {
registry,
name,
version: range.version.toString()
};
await ensureBuild(this, pkg, this.fetchOpts);
return pkg;
}
const { resolveCache } = getJspmCache(this);
const cache = resolveCache[target.registry + ":" + target.name] = resolveCache[target.registry + ":" + target.name] || {
latest: null,
majors: Object.create(null),
minors: Object.create(null),
tags: Object.create(null)
};
if (range.isWildcard || range.isExact && range.version.tag === "latest") {
let lookup = await (cache.latest || (cache.latest = lookupRange.call(this, registry, name, "", unstable, parentUrl)));
// Deno wat?
if (lookup instanceof Promise) lookup = await lookup;
if (!lookup) return null;
this.log("jspm/resolveLatestTarget", `${target.registry}:${target.name}@${range} -> WILDCARD ${lookup.version}${parentUrl ? " [" + parentUrl + "]" : ""}`);
await ensureBuild(this, lookup, this.fetchOpts);
return lookup;
}
if (range.isExact && range.version.tag) {
const tag = range.version.tag;
let lookup = await (cache.tags[tag] || (cache.tags[tag] = lookupRange.call(this, registry, name, tag, unstable, parentUrl)));
// Deno wat?
if (lookup instanceof Promise) lookup = await lookup;
if (!lookup) return null;
this.log("jspm/resolveLatestTarget", `${target.registry}:${target.name}@${range} -> TAG ${tag}${parentUrl ? " [" + parentUrl + "]" : ""}`);
await ensureBuild(this, lookup, this.fetchOpts);
return lookup;
}
let stableFallback = false;
if (range.isMajor) {
const major = range.version.major;
let lookup = await (cache.majors[major] || (cache.majors[major] = lookupRange.call(this, registry, name, major, unstable, parentUrl)));
// Deno wat?
if (lookup instanceof Promise) lookup = await lookup;
if (!lookup) return null;
// if the latest major is actually a downgrade, use the latest minor version (fallthrough)
// note this might miss later major prerelease versions, which should strictly be supported via a pkg@X@ unstable major lookup
if (range.version.gt(lookup.version)) {
stableFallback = true;
} else {
this.log("jspm/resolveLatestTarget", `${target.registry}:${target.name}@${range} -> MAJOR ${lookup.version}${parentUrl ? " [" + parentUrl + "]" : ""}`);
await ensureBuild(this, lookup, this.fetchOpts);
return lookup;
}
}
if (stableFallback || range.isStable) {
const minor = `${range.version.major}.${range.version.minor}`;
let lookup = await (cache.minors[minor] || (cache.minors[minor] = lookupRange.call(this, registry, name, minor, unstable, parentUrl)));
// in theory a similar downgrade to the above can happen for stable prerelease ranges ~1.2.3-pre being downgraded to 1.2.2
// this will be solved by the pkg@X.Y@ unstable minor lookup
// Deno wat?
if (lookup instanceof Promise) lookup = await lookup;
if (!lookup) return null;
this.log("jspm/resolveLatestTarget", `${target.registry}:${target.name}@${range} -> MINOR ${lookup.version}${parentUrl ? " [" + parentUrl + "]" : ""}`);
await ensureBuild(this, lookup, this.fetchOpts);
return lookup;
}
return null;
}
function pkgToLookupUrl(pkg, edge = false) {
return `${cdnUrl$4}${pkg.registry}:${pkg.name}${pkg.version ? "@" + pkg.version : edge ? "@" : ""}`;
}
async function lookupRange(registry, name, range, unstable, parentUrl) {
const { lookupCache } = getJspmCache(this);
const url = pkgToLookupUrl({
registry,
name,
version: range
}, unstable);
if (lookupCache.has(url)) return lookupCache.get(url);
const lookupPromise = (async ()=>{
const version = await _fetch.text(url, this.fetchOpts);
if (version) {
return {
registry,
name,
version: version.trim()
};
} else {
// not found
const versions = await fetchVersions.call(this, name);
const semverRange = new SemverRange$2(String(range) || "*", unstable);
const version = semverRange.bestMatch(versions, unstable);
if (version) {
return {
registry,
name,
version: version.toString()
};
}
throw new JspmError(`Unable to resolve ${registry}:${name}@${range} to a valid version${importedFrom(parentUrl)}`);
}
})();
lookupCache.set(url, lookupPromise);
return lookupPromise;
}
async function fetchVersions(name) {
const { versionsCacheMap } = getJspmCache(this);
if (versionsCacheMap.has(name)) {
return versionsCacheMap.get(name);
}
const registryLookup = JSON.parse(await await _fetch.text(`https://npmlookup.jspm.io/${encodeURI(name)}`, {})) || {};
const versions = Object.keys(registryLookup.versions || {});
versionsCacheMap.set(name, versions);
return versions;
}
var jspm = /*#__PURE__*/Object.freeze({
__proto__: null,
supportedLayers: supportedLayers,
pkgToUrl: pkgToUrl$5,
configure: configure,
parseUrlPkg: parseUrlPkg$6,
resolveLatestTarget: resolveLatestTarget$5,
fetchVersions: fetchVersions
});
const cdnUrl$3 = "https://cdn.skypack.dev/";
async function pkgToUrl$4(pkg) {
return `${cdnUrl$3}${pkg.name}@${pkg.version}/`;
}
const exactPkgRegEx$3 = /^((?:@[^/\\%@]+\/)?[^./\\%@][^/\\%@]*)@([^\/]+)(\/.*)?$/;
function parseUrlPkg$5(url) {
if (!url.startsWith(cdnUrl$3)) return;
const [, name, version] = url.slice(cdnUrl$3.length).match(exactPkgRegEx$3) || [];
if (!name || !version) return;
return {
registry: "npm",
name,
version
};
}
async function resolveLatestTarget$4(target, layer, parentUrl) {
const { registry, name, range, unstable } = target;
const versions = await fetchVersions.call(this, name);
const semverRange = new SemverRange$2(String(range) || "*", unstable);
const version = semverRange.bestMatch(versions, unstable);
if (version) {
return {
registry,
name,
version: version.toString()
};
}
throw new JspmError(`Unable to resolve ${registry}:${name}@${range} to a valid version${importedFrom(parentUrl)}`);
}
var skypack = /*#__PURE__*/Object.freeze({
__proto__: null,
pkgToUrl: pkgToUrl$4,
parseUrlPkg: parseUrlPkg$5,
resolveLatestTarget: resolveLatestTarget$4
});
const cdnUrl$2 = "https://cdn.jsdelivr.net/";
async function pkgToUrl$3(pkg) {
return `${cdnUrl$2}${pkg.registry}/${pkg.name}@${pkg.version}/`;
}
const exactPkgRegEx$2 = /^([^\/]+)\/((?:@[^/\\%@]+\/)?[^./\\%@][^/\\%@]*)@([^\/]+)(\/.*)?$/;
function parseUrlPkg$4(url) {
if (!url.startsWith(cdnUrl$2)) return;
const [, registry, name, version] = url.slice(cdnUrl$2.length).match(exactPkgRegEx$2) || [];
return {
registry,
name,
version
};
}
async function resolveLatestTarget$3(target, layer, parentUrl) {
const { registry, name, range, unstable } = target;
const versions = await fetchVersions.call(this, name);
const semverRange = new SemverRange$2(String(range) || "*", unstable);
const version = semverRange.bestMatch(versions, unstable);
if (version) {
return {
registry,
name,
version: version.toString()
};
}
throw new JspmError(`Unable to resolve ${registry}:${name}@${range} to a valid version${importedFrom(parentUrl)}`);
}
var jsdelivr = /*#__PURE__*/Object.freeze({
__proto__: null,
pkgToUrl: pkgToUrl$3,
parseUrlPkg: parseUrlPkg$4,
resolveLatestTarget: resolveLatestTarget$3
});
const cdnUrl$1 = "https://unpkg.com/";
async function pkgToUrl$2(pkg) {
return `${cdnUrl$1}${pkg.name}@${pkg.version}/`;
}
const exactPkgRegEx$1 = /^((?:@[^/\\%@]+\/)?[^./\\%@][^/\\%@]*)@([^\/]+)(\/.*)?$/;
function parseUrlPkg$3(url) {
if (!url.startsWith(cdnUrl$1)) return;
const [, name, version] = url.slice(cdnUrl$1.length).match(exactPkgRegEx$1) || [];
if (name && version) {
return {
registry: "npm",
name,
version
};
}
}
async function resolveLatestTarget$2(target, layer, parentUrl) {
const { registry, name, range, unstable } = target;
const versions = await fetchVersions.call(this, name);
const semverRange = new SemverRange$2(String(range) || "*", unstable);
const version = semverRange.bestMatch(versions, unstable);
if (version) {
return {
registry,
name,
version: version.toString()
};
}
throw new JspmError(`Unable to resolve ${registry}:${name}@${range} to a valid version${importedFrom(parentUrl)}`);
}
var unpkg = /*#__PURE__*/Object.freeze({
__proto__: null,
pkgToUrl: pkgToUrl$2,
parseUrlPkg: parseUrlPkg$3,
resolveLatestTarget: resolveLatestTarget$2
});
const nodeBuiltinSet = new Set([
"_http_agent",
"_http_client",
"_http_common",
"_http_incoming",
"_http_outgoing",
"_http_server",
"_stream_duplex",
"_stream_passthrough",
"_stream_readable",
"_stream_transform",
"_stream_wrap",
"_stream_writable",
"_tls_common",
"_tls_wrap",
"assert",
"assert/strict",
"async_hooks",
"buffer",
"child_process",
"cluster",
"console",
"constants",
"crypto",
"dgram",
"diagnostics_channel",
"dns",
"dns/promises",
"domain",
"events",
"fs",
"fs/promises",
"http",
"http2",
"https",
"inspector",
"module",
"net",
"os",
"path",
"path/posix",
"path/win32",
"perf_hooks",
"process",
"punycode",
"querystring",
"readline",
"repl",
"stream",
"stream/promises",
"string_decoder",
"sys",
"timers",
"timers/promises",
"tls",
"trace_events",
"tty",
"url",
"util",
"util/types",
"v8",
"vm",
"wasi",
"worker_threads",
"zlib"
]);
async function pkgToUrl$1(pkg, layer) {
if (pkg.registry !== "node") return pkgToUrl$5(pkg, layer);
return `node:${pkg.name}/`;
}
function resolveBuiltin(specifier, env) {
let builtin = specifier.startsWith("node:") ? specifier.slice(5) : nodeBuiltinSet.has(specifier) ? specifier : null;
if (!builtin) return;
// Deno supports all node builtins via bare "node:XXX" specifiers. As of
// std@0.178.0, the standard library no longer ships node polyfills, so we
// should always install builtins as base specifiers. This does mean that we
// no longer support old versions of deno unless they use --compat.
if (env.includes("deno") || env.includes("node")) {
return `node:${builtin}`;
}
// Strip the subpath for subpathed builtins
if (builtin.includes("/")) builtin = builtin.split("/")[0];
return {