UNPKG

@jspm/generator

Version:

Package Import Map Generation Tool

1,202 lines (1,191 loc) 254 kB
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