@jspm/generator
Version:
Package Import Map Generation Tool
1,264 lines (1,252 loc) • 293 kB
JavaScript
import sver, { SemverRange as SemverRange$2, Semver as Semver$1 } from 'sver';
import { setNetworkFetch, fetch as fetch$1, isVirtualUrl, setVirtualSourceData, setRetryCount, clearCache as clearCache$1 } from '@jspm/fetch';
import { ImportMap, getScopeMatches, getMapMatch as getMapMatch$1 } from '@jspm/import-map';
import { parse } from 'es-module-lexer/js';
import { init, parse as parse$1 } from 'es-module-lexer';
import { minimatch } from 'minimatch';
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 ? '' : '\x10';
}
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$6(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$6(this, "jspmError", true), _define_property$6(this, "code", void 0);
this.code = code;
}
}
function throwInternalError(...args) {
throw new Error('Internal Error' + (args.length ? ' ' + args.join(', ') : ''));
}
function isFetchProtocol(protocol) {
return protocol === 'file:' || protocol === 'https:' || protocol === 'http:' || protocol === 'data:';
}
let baseUrl = undefined;
// @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('/') && rootUrl) return new URL('.' + url.slice(url[1] === '/' ? 1 : 0), rootUrl).href;
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('/');
}
/**
* Replace the underlying network fetch. Virtual sources, protocol handlers,
* pool, retry, in-flight dedup, and caching continue to wrap it.
*/ function setFetch(fn) {
setNetworkFetch(fn);
}
const cdnUrl$4 = '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 subpath = '.';
const slashIndex = name.indexOf('/');
if (slashIndex !== -1) {
name.slice(0, slashIndex);
subpath = `./${name.slice(slashIndex + 1)}`;
}
return {
target: {
registry: 'deno',
name: 'std',
range: new SemverRange$2('*'),
unstable: true
},
subpath
};
}
}
function pkgToUrl$6(pkg) {
if (pkg.registry === 'deno') return `${stdlibUrl}@${pkg.version}/`;
if (pkg.registry === 'denoland') return `${cdnUrl$4}${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$4(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$1(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',
builtin: `deno:${name}/${subpath}`
};
} else if (url.startsWith(cdnUrl$4)) {
const path = url.slice(cdnUrl$4.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
},
builtin: 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$4 + name + '/mod.ts' : stdlibUrl + '/version.ts';
const res = await fetch$1(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,
getPackageConfig: getPackageConfig$4,
parseUrlPkg: parseUrlPkg$7,
pkgToUrl: pkgToUrl$6,
resolveBuiltin: resolveBuiltin$1,
resolveLatestTarget: resolveLatestTarget$6
});
let gaUrl = 'https://ga.jspm.io/';
const systemCdnUrl = 'https://ga.system.jspm.io/';
let apiUrl = 'https://api.jspm.io/';
// the URL we PUT the jspm.io publish to
let publishUrl = 'https://dev.qitkao.com/';
// the URL the published jspm.io packages can be seen
let rawUrl = 'https://jspm.io/';
let authToken;
let versionsCacheMap = {};
const BUILD_POLL_TIME = 60 * 1000;
const BUILD_POLL_INTERVAL = 5 * 1000;
const AUTH_POLL_INTERVAL = 5 * 1000; // 5 seconds between auth polls
// Instance caches — reset on configure()
let lookupCache = {};
let lookupInflight = {};
let cachedErrorsInflight = {};
let buildRequestedInflight = {};
const supportedLayers = [
'default',
'system'
];
function withTrailer(url) {
return url.endsWith('/') ? url : url + '/';
}
function pkgToUrl$5(pkg, layer = 'default') {
if (pkg.registry === 'app') return `${rawUrl}${pkgToStr(pkg)}/`;
return `${layer === 'system' ? systemCdnUrl : gaUrl}${pkgToStr(pkg)}/`;
}
async function getPackageConfig$3(pkgUrl) {
var _res_headers_get;
if (pkgUrl === gaUrl) return null;
try {
var res = await fetch$1(`${pkgUrl}package.json`, this.fetchOpts);
} catch (e) {
return null;
}
switch(res.status){
case 200:
case 204:
case 304:
break;
case 400:
case 401:
case 403:
case 404:
let err;
try {
// if it is a build error, try surface the build error
let errRes = await fetch$1(`${pkgUrl}_error.log`);
if (errRes.ok) err = await errRes.text();
else err = `Unable to fetch ${pkgUrl}package.json`;
} catch {}
if (err) throw new JspmError(err);
case 406:
case 500:
return null;
default:
throw new JspmError(`Invalid status code ${res.status} reading package config for ${pkgUrl}. ${res.statusText}`);
}
if (res.headers && !((_res_headers_get = res.headers.get('Content-Type')) === null || _res_headers_get === void 0 ? void 0 : _res_headers_get.match(/^application\/json(;|$)/))) {
return null;
} else {
try {
return await res.json();
} catch (e) {
return null;
}
}
}
function configure$1(config) {
versionsCacheMap = {};
lookupCache = {};
lookupInflight = {};
cachedErrorsInflight = {};
buildRequestedInflight = {};
if (config.authToken) authToken = config.authToken;
if (config.cdnUrl) {
gaUrl = withTrailer(config.cdnUrl);
clearParseUrlPkgCache(); // Clear cache when CDN URL changes
}
if (config.publishUrl) publishUrl = withTrailer(config.publishUrl);
if (config.rawUrl) rawUrl = withTrailer(config.rawUrl);
if (config.apiUrl) apiUrl = withTrailer(config.apiUrl);
}
const exactPkgRegEx$4 = /^(([a-z]+):)?((?:@[^/\\%@]+\/)?[^./\\%@][^/\\%@]*)@([^\/]+)(\/.*)?$/;
// Cache for parseUrlPkg results - significantly reduces regex and string operations
let parseUrlPkgCache = new Map();
function clearParseUrlPkgCache() {
parseUrlPkgCache = new Map();
}
function parseUrlPkg$6(url) {
const cached = parseUrlPkgCache.get(url);
if (cached !== undefined) return cached;
// Check for cache miss with undefined stored (url doesn't match)
if (parseUrlPkgCache.has(url)) return undefined;
const result = parseUrlPkgUncached(url);
parseUrlPkgCache.set(url, result);
return result;
}
function parseUrlPkgUncached(url) {
let builtin = null;
let layer;
if (url.startsWith(gaUrl)) layer = 'default';
else if (url.startsWith(systemCdnUrl)) layer = 'system';
else return;
const [, , registry, name, version] = url.slice((layer === 'default' ? gaUrl : systemCdnUrl).length).match(exactPkgRegEx$4) || [];
if (registry && name && version) {
if (registry === 'npm' && name === '@jspm/core' && url.includes('/nodelibs/')) {
builtin = url.slice(url.indexOf('/nodelibs/') + 10);
if (builtin.endsWith('.js')) builtin = builtin.slice(0, -3);
}
return {
pkg: {
registry,
name,
version
},
layer,
builtin
};
}
}
function getJspmCache(context) {
const jspmCache = context.context.jspmCache;
if (!context.context.jspmCache) {
return context.context.jspmCache = {
cachedErrors: {},
buildRequested: {}
};
}
return jspmCache;
}
async function checkBuildOrError(context, pkgUrl, fetchOpts, resolver) {
// For backward compatibility, assuming we have an outer resolver that can handle this
// In a fully refactored system, this would likely come from a different method
const pcfg = await (resolver === null || resolver === void 0 ? void 0 : resolver.getPackageConfig(pkgUrl)) || await fetch$1(pkgUrl + 'package.json');
if (pcfg) {
return true;
}
const { cachedErrors } = getJspmCache(context);
// no package.json! Check if there's a build error:
if (pkgUrl in cachedErrors) return cachedErrors[pkgUrl];
if (pkgUrl in cachedErrorsInflight) return cachedErrorsInflight[pkgUrl];
const cachedErrorPromise = (async ()=>{
try {
const errLog = await getTextIfOk(`${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) {
cachedErrors[pkgUrl] = false;
delete cachedErrorsInflight[pkgUrl];
return false;
}
})();
cachedErrorsInflight[pkgUrl] = cachedErrorPromise;
return cachedErrorPromise;
}
async function ensureBuild(context, pkg, fetchOpts, resolver) {
if (await checkBuildOrError(context, pkgToUrl$5(pkg, 'default'), fetchOpts, resolver)) return;
const fullName = `${pkg.name}@${pkg.version}`;
const { buildRequested } = getJspmCache(context);
// 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 (fullName in buildRequested) return;
if (fullName in buildRequestedInflight) return buildRequestedInflight[fullName];
const buildPromise = (async ()=>{
const buildRes = await fetch$1(`${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(context, pkgToUrl$5(pkg, 'default'), fetchOpts, resolver)) {
buildRequested[fullName] = true;
delete buildRequestedInflight[fullName];
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.`);
}
})();
buildRequestedInflight[fullName] = buildPromise;
return buildPromise;
}
async function resolveLatestTarget$5(target, layer, parentUrl, resolver) {
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, resolver);
return pkg;
}
if (range.isWildcard || range.isExact && range.version.tag === 'latest') {
const lookup = await lookupRange.call(this, registry, name, '', unstable, parentUrl);
if (!lookup) return null;
this.log('jspm/resolveLatestTarget', `${target.registry}:${target.name}@${range} -> WILDCARD ${lookup.version}${parentUrl ? ' [' + parentUrl + ']' : ''}`);
await ensureBuild(this, lookup, this.fetchOpts, resolver);
return lookup;
}
if (range.isExact && range.version.tag) {
const lookup = await lookupRange.call(this, registry, name, range.version.tag, unstable, parentUrl);
if (!lookup) return null;
this.log('jspm/resolveLatestTarget', `${target.registry}:${target.name}@${range} -> TAG ${range.version.tag}${parentUrl ? ' [' + parentUrl + ']' : ''}`);
await ensureBuild(this, lookup, this.fetchOpts, resolver);
return lookup;
}
let stableFallback = false;
if (range.isMajor) {
const lookup = await lookupRange.call(this, registry, name, range.version.major, unstable, parentUrl);
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, resolver);
return lookup;
}
}
if (stableFallback || range.isStable) {
const minor = `${range.version.major}.${range.version.minor}`;
const lookup = await 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
if (!lookup) return null;
this.log('jspm/resolveLatestTarget', `${target.registry}:${target.name}@${range} -> MINOR ${lookup.version}${parentUrl ? ' [' + parentUrl + ']' : ''}`);
await ensureBuild(this, lookup, this.fetchOpts, resolver);
return lookup;
}
// Fallback for compound ranges (union, intersection, comparators) that
// don't map to a single JSPM lookup — resolve via full version list:
{
const versions = await fetchVersions.call(this, name);
const version = range.bestMatch(versions, unstable);
if (version) {
const pkg = {
registry,
name,
version: version.toString()
};
this.log('jspm/resolveLatestTarget', `${target.registry}:${target.name}@${range} -> BEST_MATCH ${pkg.version}${parentUrl ? ' [' + parentUrl + ']' : ''}`);
await ensureBuild(this, pkg, this.fetchOpts, resolver);
return pkg;
}
}
return null;
}
function pkgToLookupUrl(pkg, edge = false) {
return `${gaUrl}${pkg.registry}:${pkg.name}${pkg.version ? '@' + pkg.version : edge ? '@' : ''}`;
}
async function lookupRange(registry, name, range, unstable, parentUrl) {
const url = pkgToLookupUrl({
registry,
name,
version: range
}, unstable);
if (url in lookupCache) return lookupCache[url];
if (url in lookupInflight) return lookupInflight[url];
const lookupPromise = (async ()=>{
const version = await getTextIfOk(url, this.fetchOpts);
let result;
if (version) {
result = {
registry,
name,
version: version.trim()
};
} else {
// not found
const versions = await fetchVersions.call(this, name);
const semverRange = new SemverRange$2(String(range) || '*');
const version = semverRange.bestMatch(versions, unstable);
if (version) {
result = {
registry,
name,
version: version.toString()
};
} else {
throw new JspmError(`Unable to resolve ${registry}:${name}@${range} to a valid version${importedFrom(parentUrl)}`);
}
}
lookupCache[url] = result;
delete lookupInflight[url];
return result;
})();
lookupInflight[url] = lookupPromise;
return lookupPromise;
}
async function getTextIfOk(url, fetchOpts) {
const res = await fetch$1(url, fetchOpts);
switch(res.status){
case 200:
case 304:
return await res.text();
// not found = null
case 404:
return null;
default:
throw new Error(`Invalid status code ${res.status}`);
}
}
async function fetchVersions(name) {
if (name in versionsCacheMap) {
return versionsCacheMap[name];
}
const registryLookup = JSON.parse(await getTextIfOk(`https://npmlookup.jspm.io/${encodeURI(name)}`, {
cache: 'no-cache'
})) || {};
const versions = Object.keys(registryLookup.versions || {});
versionsCacheMap[name] = versions;
return versions;
}
async function download(pkg) {
const tar = await import('tar-stream');
const { default: pako } = await import('pako');
const { name, version, registry } = pkg;
if (registry !== 'app') throw new JspmError(`The JSPM provider currently only supports downloading from the jspm.io "app:" registry`);
let tarball;
try {
const tarballRes = await fetch$1(`${rawUrl}tarball/app:${name}@${version}`);
if (tarballRes.ok) {
tarball = await tarballRes.arrayBuffer();
} else {
try {
throw (await tarballRes.json()).error;
} catch {}
throw tarballRes.statusText || tarballRes.status;
}
} catch (e) {
throw new JspmError(`Unable to fetch tarball for ${name}@${version} from ${rawUrl}: ${e}`);
}
const output = pako.inflate(tarball, {
gzip: true
});
const extract = tar.extract();
const fileData = {};
await new Promise((resolve, reject)=>{
extract.on('entry', async function(header, stream, next) {
try {
if (header.type === 'file') {
if (header.name.indexOf('/') === -1) {
next();
return;
}
const name = header.name.slice(header.name.indexOf('/') + 1);
const target = new Uint8Array(header.size);
let offset = 0;
for await (const chunk of stream){
target.set(chunk, offset);
offset += chunk.byteLength;
}
fileData[name] = target;
}
stream.once('end', next);
stream.resume();
next();
} catch (e) {
extract.emit('error', e);
}
});
extract.once('error', reject);
extract.once('finish', resolve);
extract.end(output);
});
return fileData;
}
/**
* Publishes a package to the jspm.io app registry
*
* Input package is already validated by JSPM
*
* @returns Promise that resolves with the package URL
*/ async function publish(pkg, files, importMap, imports, timeout = 30000) {
const { registry, name, version } = pkg;
if (registry !== 'app') {
throw new JspmError(`Invalid registry ${registry}, JSPM can only publish to the jspm.io "app:" registry currently`);
}
// Prepare the URL for the request
const packageUrl = `${publishUrl}app:${name}@${version}`;
// Prepare the package data using tar-stream
const tarball = await createTarball(files, importMap);
// Get or create token
const token = await createPublishToken(name, version);
// Upload the package
const response = await globalThis.fetch(packageUrl, {
method: 'PUT',
headers: {
'Content-Type': 'application/gzip',
Authorization: `Bearer ${token}`
},
// @ts-ignore
body: tarball
});
if (!response.ok) {
let errorMessage;
switch(response.status){
case 413:
errorMessage = `Publish failed - package size of ${tarball.byteLength}B is too large`;
break;
default:
errorMessage = `Publish failed with status ${response.status}`;
}
try {
const errorJson = await response.json();
errorMessage = errorJson.message || errorJson.error || `Publish failed with status ${response.status}`;
} catch {}
throw new JspmError(errorMessage);
}
const result = await response.json();
if (!result.success) {
throw new JspmError(result.message || 'Publish failed');
}
const publicPackageUrl = pkgToUrl$5.call(this, pkg, 'default');
const mapUrl = publicPackageUrl + 'importmap.json';
return {
packageUrl: publicPackageUrl,
mapUrl,
codeSnippet: `<!-- jspm.io import map injection (change to ".hot.js" for hot reloading) -->
<script src="${mapUrl.slice(0, -2)}" crossorigin="anoymous"></script>
<!-- Polyfill for older browsers -->
<script async src="${await latestEsms.call(this, rawUrl)}" crossorigin="anonymous"></script>
${imports.length ? `
<!-- Import entrypoint${imports.length > 1 ? 's' : ''} -->
<script type="module" crossorigin="anonymous">${imports.length > 1 ? '\n' : ''}${imports.map((impt, idx)=>`${idx === 0 ? '' : idx === 1 ? '// Further available import map entrypoints - import as needed:\n// ' : '// '}import '${impt}';`).join('\n')}${imports.length > 1 ? '\n' : ''}</script>` : ''}
`
};
}
async function latestEsms(forUrl) {
// Obtain the latest ES Module Shims version
const esmsPkg = await resolveLatestTarget$5.call(this, {
name: 'es-module-shims',
registry: 'npm',
range: new SemverRange$2('*'),
unstable: false
}, 'default', forUrl, null);
return pkgToUrl$5.call(this, esmsPkg, 'default') + 'dist/es-module-shims.js';
}
/**
* Authenticate with JSPM API to obtain a token
*
* @param options Authentication options
* @returns Promise resolving to an authentication token
*/ async function auth(options) {
// Start token request
const deviceCodeResponse = await globalThis.fetch(`${apiUrl}v1/auth/cli`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
client_id: 'jspm-cli',
scope: 'deployments'
})
});
if (!deviceCodeResponse.ok) {
throw new JspmError(`Failed to start authentication flow: ${deviceCodeResponse.status} ${deviceCodeResponse.statusText}`);
}
const deviceCodeData = await deviceCodeResponse.json();
const { device_code: deviceCode, user_code: userCode, verification_uri_complete: verificationUri, interval = 5 } = deviceCodeData;
// Prepare instructions for the user
const instructions = `Login or signup, using the code: ${userCode}`;
// If a verification callback is provided, use it
options.verify(verificationUri, instructions);
while(true){
// Wait for the polling interval
await new Promise((resolve)=>setTimeout(resolve, AUTH_POLL_INTERVAL));
try {
// Poll the token endpoint
const tokenResponse = await globalThis.fetch(`${apiUrl}v1/auth/cli/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
device_code: deviceCode,
client_id: 'jspm-cli'
})
});
const tokenData = await tokenResponse.json();
// Check for errors
if (tokenResponse.status !== 200) {
// If authorization is pending, continue polling
if (tokenData.error === 'authorization_pending') {
continue;
}
// If another error occurred, stop polling
throw new JspmError(tokenData.error_description || 'Authentication failed');
}
// Success! Store and return the token
authToken = tokenData.access_token;
return {
token: authToken
};
} catch (error) {
// Handle network errors, continue polling
if (error.name === 'FetchError') {
continue;
}
throw error;
}
}
}
/**
* Creates a JWT token for package publishing
*
* @param packageName Name of the package
* @param packageVersion Version of the package
* @returns JWT token for publish authorization
*/ async function createPublishToken(packageName, packageVersion) {
if (!authToken) {
throw new JspmError(`No auth token has been generated for jspm.io. Either set providers['jspm.io'].authToken, or first run "jspm auth jspm.io"`);
}
try {
const response = await globalThis.fetch(`${apiUrl}v1/package/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${authToken}`
},
body: JSON.stringify({
package_name: packageName,
package_version: packageVersion
})
});
if (!response.ok) {
let errJson;
try {
errJson = await response.json();
} catch {
throw new Error(response.status.toString());
}
throw new Error(errJson.error ? errJson.error : JSON.stringify(errJson, null, 2));
}
const data = await response.json();
return data.token;
} catch (error) {
// Fall back to the placeholder token if there's an error
if (error.message.includes('Invalid or expired token')) throw new JspmError(`Invalid or expired token, run "jspm provider auth jspm.io" to regenerate an authentication token.`);
throw new JspmError(error.message);
}
}
/**
* Creates a gzipped tarball from the provided files
* Following npm conventions with a "package" folder at the root
*
* @param files Record of file paths to content
* @param importMap Optional import map to include
* @returns Promise that resolves with the tarball
*/ async function createTarball(files, map) {
const tar = await import('tar-stream');
const { default: pako } = await import('pako');
// Create pack stream
const pack = tar.pack();
// Collect chunks
const deflator = new pako.Deflate({
gzip: true
});
const result = new Promise((resolve, reject)=>{
pack.on('data', (chunk)=>{
deflator.push(chunk, false);
});
pack.on('finish', ()=>{
console.log('wat');
});
pack.on('end', async ()=>{
deflator.push(new Uint8Array([]), true);
if (deflator.err) reject(deflator.err);
else resolve(deflator.result);
});
pack.on('error', (err)=>{
reject(err);
});
});
if (map) {
pack.entry({
name: 'package/importmap.json'
}, new TextEncoder().encode(JSON.stringify(map.toJSON())));
}
// Add files to the tarball, placing them inside a "package" directory
// to follow npm's convention
if (files) {
for (const [path, content] of Object.entries(files)){
let contentBuffer;
if (typeof content === 'string') {
contentBuffer = new TextEncoder().encode(content);
} else {
contentBuffer = new Uint8Array(content);
}
// Prefix with "package/" to follow npm convention
const tarPath = `package/${path}`;
pack.entry({
name: tarPath
}, contentBuffer);
}
}
// Finalize the pack
pack.finalize();
return result;
}
var jspm = /*#__PURE__*/Object.freeze({
__proto__: null,
auth: auth,
clearParseUrlPkgCache: clearParseUrlPkgCache,
configure: configure$1,
download: download,
fetchVersions: fetchVersions,
getPackageConfig: getPackageConfig$3,
parseUrlPkg: parseUrlPkg$6,
pkgToUrl: pkgToUrl$5,
publish: publish,
resolveLatestTarget: resolveLatestTarget$5,
supportedLayers: supportedLayers
});
const cdnUrl$3 = 'https://cdn.skypack.dev/';
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) || '*');
const version = semverRange.bestMatch(versions, unstable);
if (version) {
return {
registry,
name,
version: version.toString()