@jspm/generator
Version:
Package Import Map Generation Tool
1,202 lines (1,191 loc) • 254 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 { 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 ? '' : '*';
}
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(', ') : ''));
}
// @ts-ignore
let retryCount = 5, poolSize = 100;
function setRetryCount(count) {
retryCount = count;
}
/**
* Allows customizing the fetch implementation used by the generator.
*/ function setFetch(fetch) {
_fetch = wrappedFetch(fetch);
}
const virtualSources = {};
/**
* Allows virtual sources to be defined into the wrapped fetch implementation.
*/ function setVirtualSourceData(urlBase, sourceData) {
virtualSources[urlBase.endsWith('/') ? urlBase : urlBase + '/'] = sourceData;
}
const emptyHeaders = new Headers();
const jsonHeaders = new Headers([
[
'content-type',
'application/json'
]
]);
function sourceResponse(url, buffer) {
return {
url,
ok: true,
headers: url.endsWith('.json') ? jsonHeaders : emptyHeaders,
status: 200,
async text () {
return buffer.toString();
},
async json () {
return JSON.parse(buffer.toString());
},
arrayBuffer () {
if (typeof buffer === 'string') return new TextEncoder().encode(buffer.toString()).buffer;
return new Uint8Array(buffer);
}
};
}
/**
* Wraps a fetch request with pooling, retry logic on exceptions (emfile / network errors),
* and source virtualization.
*/ function wrappedFetch(fetch) {
const wrappedFetch = async function(url, ...args) {
url = url.toString();
let matchedVirtual = false;
for (const virtualBase of Object.keys(virtualSources)){
if (url.startsWith(virtualBase)) {
const virtualFileData = virtualSources[virtualBase];
let subdir = url.slice(virtualBase.length);
const source = virtualFileData[subdir];
if (source) return sourceResponse(url, source);
// check if we have files within this virtual source path as a folder
// and if so return the file listing as a 204 listing (internal non-public convention)
let dirFiles = null;
if (!subdir.endsWith('/') && subdir.length) subdir += '/';
for (const file of Object.keys(virtualFileData)){
if (file.startsWith(subdir)) {
dirFiles = dirFiles || [];
let filename = file.slice(subdir.length);
if (filename.indexOf('/') !== -1) {
filename = filename.slice(0, filename.indexOf('/'));
if (dirFiles.includes(filename)) continue;
}
dirFiles.push(filename);
}
}
if (dirFiles) {
return {
// we use a 204 status for directory responses on the filesystem
// which support listing. This is only a local internal convention,
// not intended for external URLs.
ok: true,
status: 204,
headers: emptyHeaders,
async text () {
return '';
},
async json () {
return dirFiles;
},
arrayBuffer () {
return new ArrayBuffer(0);
}
};
}
// we allow fallthrough to other virtual source bases
// that is, virtual source bases are allowed to nest eachother
// this may not be useful in which case we can remove
matchedVirtual = true;
}
}
if (matchedVirtual) {
return {
url,
ok: false,
headers: emptyHeaders,
status: 404,
statusText: 'Virtual source not found'
};
}
let retries = 0;
try {
await pushFetchPool();
while(true){
try {
return await fetch(url, ...args);
} catch (e) {
if (retries++ >= retryCount) throw e;
}
}
} finally{
popFetchPool();
}
};
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()();
}
let _fetch = wrappedFetch(fetch$1);
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('/');
}
function getMapMatch(specifier, map) {
if (specifier in map) return specifier;
let bestMatch;
for (const match of Object.keys(map)){
const wildcardIndex = match.indexOf('*');
if (!match.endsWith('/') && wildcardIndex === -1) continue;
if (match.endsWith('/')) {
if (specifier.startsWith(match)) {
if (!bestMatch || match.length > bestMatch.length) bestMatch = match;
}
} else {
const prefix = match.slice(0, wildcardIndex);
const suffix = match.slice(wildcardIndex + 1);
if (specifier.startsWith(prefix) && specifier.endsWith(suffix) && specifier.length > prefix.length + suffix.length) {
if (!bestMatch || !bestMatch.startsWith(prefix) || !bestMatch.endsWith(suffix)) bestMatch = match;
}
}
}
return bestMatch;
}
function allDotKeys(exports) {
for(let p in exports){
if (p[0] !== '.') return false;
}
return true;
}
/**
* Expand a package exports field into its set of subpaths and resolution
* With an optional file list for expanding globs
*/ function expandExportsResolutions(exports, env, files, exportsResolutions = new Map()) {
if (typeof exports !== 'object' || exports === null || !allDotKeys(exports)) {
let targetList = new Set();
expandTargetResolutions(exports, files, env, targetList, [], true);
for (const target of targetList){
if (target.startsWith('./')) {
const targetFile = target.slice(2);
if (!files || files.has(targetFile)) exportsResolutions.set('.', targetFile);
}
}
} else {
for (const subpath of Object.keys(exports)){
let targetList = new Set();
expandTargetResolutions(exports[subpath], files, env, targetList, [], true);
for (const target of targetList){
expandExportsTarget(exports, subpath, target, files, exportsResolutions);
}
}
}
}
/**
* Expand the given exports target into its possible resolution list,
* given an environment union.
* Unknown environment conditions are expanded, with handling for
* mutual exclusions between environment conditions - i.e. if env is [], and we
* expand into a "production" branch of the environment, then "development" branches
* will be excluded on that walk of the branch further.
*/ const conditionMutualExclusions = {
production: 'development',
development: 'production',
import: 'require',
require: 'import'
};
function expandTargetResolutions(exports, files, env, targetList, envExclusions = env.map((condition)=>conditionMutualExclusions[condition]).filter((c)=>c), firstOnly) {
if (typeof exports === 'string') {
if (exports.startsWith('./')) targetList.add(exports);
return true;
} else if (Array.isArray(exports)) {
for (const item of exports){
if (expandTargetResolutions(item, files, env, targetList, envExclusions, firstOnly)) return true;
}
return false;
} else if (exports === null) {
// the null resolution target is a match for not resolving
return true;
} else {
let hasSomeResolution = false;
for (const condition of Object.keys(exports)){
if (condition.startsWith('.')) continue;
if (condition === 'default' || env.includes(condition)) {
if (expandTargetResolutions(exports[condition], files, env, targetList, envExclusions, firstOnly)) {
return true;
}
}
if (envExclusions.includes(condition)) continue;
const maybeNewExclusion = conditionMutualExclusions[condition];
const newExclusions = maybeNewExclusion && !envExclusions.includes(maybeNewExclusion) ? [
...envExclusions,
maybeNewExclusion
] : envExclusions;
// if we did match the condition, then we know any subsequent condition checks are under exclusion as well
if (expandTargetResolutions(exports[condition], files, env, targetList, newExclusions, firstOnly)) {
if (firstOnly) return true;
hasSomeResolution = true;
envExclusions = newExclusions;
}
}
return hasSomeResolution;
}
}
/**
* Expands the given target string into the entries list,
* handling wildcard globbing
*/ function expandExportsTarget(exports, subpath, target, files, entriesMap) {
if (!target.startsWith('./') || !(subpath.startsWith('./') || subpath === '.')) return;
if (target.indexOf('*') === -1 || subpath.indexOf('*') === -1) {
const targetFile = target.slice(2);
if (!files || files.has(targetFile)) entriesMap.set(subpath, target.slice(2));
return;
}
if (!files) return;
// First determine the list of files that could match the target glob
const lhs = target.slice(2, target.indexOf('*'));
const rhs = target.slice(target.indexOf('*') + 1);
const fileMatches = new Set();
for (const file of files){
if (file.startsWith(lhs) && file.endsWith(rhs) && file.length > lhs.length + rhs.length) {
fileMatches.add(file);
}
}
// Backtrack to determine their original subpaths and
// re-resolve those subpaths to verify they do indeed resolve to our target glob
// since they could be shadowed by other subpath resolutions
for (const fileMatch of fileMatches){
const pattern = fileMatch.slice(lhs.length, fileMatch.length - rhs.length);
const originalSubpath = subpath.replace('*', pattern);
const matchedSubpath = getMapMatch(originalSubpath, exports);
if (matchedSubpath === subpath) entriesMap.set(originalSubpath, fileMatch);
}
}
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 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$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$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$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
},
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$4 + 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',
'pkg'
];
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 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;
const BUILD_POLL_TIME = 60 * 1000;
const BUILD_POLL_INTERVAL = 5 * 1000;
const AUTH_POLL_INTERVAL = 5 * 1000; // 5 seconds between auth polls
const supportedLayers = [
'default',
'system'
];
function withTrailer(url) {
return url.endsWith('/') ? url : url + '/';
}
async function pkgToUrl$5(pkg, layer = 'default') {
if (pkg.registry === 'app') return `${rawUrl}${pkgToStr(pkg)}/`;
return `${layer === 'system' ? systemCdnUrl : gaUrl}${pkgToStr(pkg)}/`;
}
function configure$1(config) {
if (config.authToken) authToken = config.authToken;
if (config.cdnUrl) gaUrl = withTrailer(config.cdnUrl);
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]+):)?((?:@[^/\\%@]+\/)?[^./\\%@][^/\\%@]*)@([^\/]+)(\/.*)?$/;
function parseUrlPkg$6(url) {
let subpath = 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/')) {
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(context) {
const jspmCache = context.context.jspmCache;
if (!context.context.jspmCache) {
return context.context.jspmCache = {
lookupCache: new Map(),
versionsCacheMap: new Map(),
resolveCache: {},
cachedErrors: new Map(),
buildRequested: new Map()
};
}
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(pkgUrl + 'package.json');
if (pcfg) {
return true;
}
const { cachedErrors } = getJspmCache(context);
// 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 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) {
return false;
}
})();
cachedErrors.set(pkgUrl, cachedErrorPromise);
return cachedErrorPromise;
}
async function ensureBuild(context, pkg, fetchOpts, resolver) {
if (await checkBuildOrError(context, await 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 (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(context, await pkgToUrl$5(pkg, 'default'), fetchOpts, resolver)) 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, 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;
}
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, resolver);
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, resolver);
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 prerelea