@jspm/generator
Version:
Package Import Map Generation Tool
712 lines (710 loc) • 36.6 kB
JavaScript
function _define_property(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;
}
import { JspmError } from "../common/err.js";
// @ts-ignore
import { fetch } from "../common/fetch.js";
import { importedFrom } from "../common/url.js";
// @ts-ignore
import { parse } from "es-module-lexer/js";
import { getProvider, defaultProviders, builtinSchemes, mappableSchemes } from "../providers/index.js";
import { createSystemAnalysis, createCjsAnalysis, createEsmAnalysis, createTsAnalysis } from "./analysis.js";
import { SemverRange } from "sver";
import { getIntegrity } from "../common/integrity.js";
let realpath, pathToFileURL;
export function setPathFns(_realpath, _pathToFileURL) {
realpath = _realpath, pathToFileURL = _pathToFileURL;
}
export function isBuiltinScheme(specifier) {
if (specifier.indexOf(":") === -1) return false;
return builtinSchemes.has(specifier.slice(0, specifier.indexOf(":")));
}
export function isMappableScheme(specifier) {
if (specifier.indexOf(":") === -1) return false;
return mappableSchemes.has(specifier.slice(0, specifier.indexOf(":")));
}
export class Resolver {
addCustomProvider(name, provider) {
if (!provider.pkgToUrl) throw new Error('Custom provider "' + name + '" must define a "pkgToUrl" method.');
if (!provider.parseUrlPkg) throw new Error('Custom provider "' + name + '" must define a "parseUrlPkg" method.');
if (!provider.resolveLatestTarget) throw new Error('Custom provider "' + name + '" must define a "resolveLatestTarget" method.');
this.providers = Object.assign({}, this.providers, {
[name]: provider
});
}
providerNameForUrl(url) {
for (const name of Object.keys(this.providers).reverse()){
const provider = this.providers[name];
if (provider.ownsUrl && provider.ownsUrl.call(this, url) || provider.parseUrlPkg.call(this, url)) {
return name;
}
}
}
providerForUrl(url) {
const name = this.providerNameForUrl(url);
return name ? this.providers[name] : null;
}
async parseUrlPkg(url) {
for (const provider of Object.keys(this.providers).reverse()){
const providerInstance = this.providers[provider];
const result = providerInstance.parseUrlPkg.call(this, url);
if (result) return {
pkg: "pkg" in result ? result.pkg : result,
source: {
provider,
layer: "layer" in result ? result.layer : "default"
},
subpath: "subpath" in result ? result.subpath : null
};
}
return null;
}
async pkgToUrl(pkg, { provider, layer }) {
return getProvider(provider, this.providers).pkgToUrl.call(this, pkg, layer);
}
resolveBuiltin(specifier) {
for (const provider of Object.values(this.providers).reverse()){
if (!provider.resolveBuiltin) continue;
const builtin = provider.resolveBuiltin.call(this, specifier, this.env);
if (builtin) return builtin;
}
}
async getPackageBase(url) {
const pkg = await this.parseUrlPkg(url);
if (pkg) return this.pkgToUrl(pkg.pkg, pkg.source);
let testUrl;
try {
testUrl = new URL("./", url);
} catch {
return url;
}
const rootUrl = new URL("/", testUrl).href;
do {
let responseUrl;
if (responseUrl = await this.checkPjson(testUrl.href)) return new URL(".", responseUrl).href;
// No package base -> use directory itself
if (testUrl.href === rootUrl) return new URL("./", url).href;
}while (testUrl = new URL("../", testUrl))
}
// TODO: there are actually two different kinds of "package" in the codebase.
// There's a registry package, which is something that can be pinned exactly
// by name and version against a registry like "npm" or "denoland". Then we
// have a resolver package, which is any URL that has a "package.json" as a
// child. We should only be doing providerForUrl checks for _registry_
// packages, and in resolution contexts we should skip straight to npm-style
// backtracking to find package bases.
async getPackageConfig(pkgUrl) {
if (!pkgUrl.startsWith("file:") && !pkgUrl.startsWith("http:") && !pkgUrl.startsWith("https:") && !pkgUrl.startsWith("node:")) return null;
if (!pkgUrl.endsWith("/")) throw new Error(`Internal Error: Package URL must end in "/". Got ${pkgUrl}`);
let cached = this.pcfgs[pkgUrl];
if (cached) return cached;
if (!this.pcfgPromises[pkgUrl]) this.pcfgPromises[pkgUrl] = (async ()=>{
var _res_headers_get;
const provider = this.providerForUrl(pkgUrl);
if (provider) {
var _provider_getPackageConfig;
const pcfg = await ((_provider_getPackageConfig = provider.getPackageConfig) === null || _provider_getPackageConfig === void 0 ? void 0 : _provider_getPackageConfig.call(this, pkgUrl));
if (pcfg !== undefined) {
this.pcfgs[pkgUrl] = pcfg;
return;
}
}
try {
var res = await fetch(`${pkgUrl}package.json`, this.fetchOpts);
} catch (e) {
// CSP errors can't be detected, but should be treated as missing
// therefore we just ignore errors as none
this.pcfgs[pkgUrl] = null;
return;
}
switch(res.status){
case 200:
case 304:
break;
case 400:
case 401:
case 403:
case 404:
case 406:
case 500:
this.pcfgs[pkgUrl] = null;
return;
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(;|$)/))) {
this.pcfgs[pkgUrl] = null;
} else try {
this.pcfgs[pkgUrl] = await res.json();
} catch (e) {
this.pcfgs[pkgUrl] = null;
}
})();
await this.pcfgPromises[pkgUrl];
return this.pcfgs[pkgUrl];
}
async getDepList(pkgUrl, dev = false) {
const pjson = await this.getPackageConfig(pkgUrl);
if (!pjson) return [];
return [
...new Set([
Object.keys(pjson.dependencies || {}),
Object.keys(dev && pjson.devDependencies || {}),
Object.keys(pjson.peerDependencies || {}),
Object.keys(pjson.optionalDependencies || {}),
Object.keys(pjson.imports || {})
].flat())
];
}
async checkPjson(url) {
if (await this.getPackageConfig(url) === null) return false;
return url;
}
async exists(resolvedUrl) {
try {
await this.analyze(resolvedUrl);
} catch {
// we ignore network errors when doing exists resolutions
return false;
}
// 404 still caches as null, although this is not currently used
return !!this.traceEntries[resolvedUrl];
}
async resolveLatestTarget(target, { provider, layer }, parentUrl) {
// find the range to resolve latest
let range;
for (const possibleRange of target.ranges.sort(target.ranges[0].constructor.compare)){
if (!range) {
range = possibleRange;
} else if (possibleRange.gt(range) && !range.contains(possibleRange)) {
range = possibleRange;
}
}
const latestTarget = {
registry: target.registry,
name: target.name,
range,
unstable: target.unstable
};
const resolveLatestTarget = getProvider(provider, this.providers).resolveLatestTarget;
const pkg = await resolveLatestTarget.call(this, latestTarget, layer, parentUrl);
if (pkg) return pkg;
if (provider === "nodemodules") {
throw new JspmError(`Cannot find package ${target.name} in node_modules from parent ${parentUrl}. Try installing "${target.name}" with npm first adding it to package.json "dependencies" or running "npm install --save ${target.name}".`);
} else {
throw new JspmError(`Unable to resolve package ${latestTarget.registry}:${latestTarget.name} in range "${latestTarget.range}" from parent ${parentUrl}.`);
}
}
async wasCommonJS(url) {
var _pcfg_exports;
// TODO: make this a provider hook
const pkgUrl = await this.getPackageBase(url);
if (!pkgUrl) return false;
const pcfg = await this.getPackageConfig(pkgUrl);
if (!pcfg) return false;
const subpath = "./" + url.slice(pkgUrl.length);
return (pcfg === null || pcfg === void 0 ? void 0 : (_pcfg_exports = pcfg.exports) === null || _pcfg_exports === void 0 ? void 0 : _pcfg_exports[subpath + "!cjs"]) ? true : false;
}
async realPath(url) {
if (!url.startsWith("file:") || this.preserveSymlinks) return url;
let encodedColon = false;
url = url.replace(/%3a/i, ()=>{
encodedColon = true;
return ":";
});
if (!realpath) {
[{ realpath }, { pathToFileURL }] = await Promise.all([
import("fs"),
import("url")
]);
}
const outUrl = pathToFileURL(await new Promise((resolve, reject)=>realpath(new URL(url), (err, result)=>err ? reject(err) : resolve(result)))).href;
if (encodedColon) return "file:" + outUrl.slice(5).replace(":", "%3a");
return outUrl;
}
async finalizeResolve(url, parentIsCjs, exportsResolution, pkgUrl) {
if (parentIsCjs && url.endsWith("/")) url = url.slice(0, -1);
// Only CJS modules do extension searching for relative resolved paths
if (parentIsCjs) url = await (async ()=>{
// subfolder checks before file checks because of fetch
if (await this.exists(url + "/package.json")) {
const pcfg = await this.getPackageConfig(url) || {};
const urlUrl = new URL(url + "/");
if (this.env.includes("browser") && typeof pcfg.browser === "string") return this.finalizeResolve(await legacyMainResolve.call(this, pcfg.browser, urlUrl), parentIsCjs, exportsResolution, pkgUrl);
if (this.env.includes("module") && typeof pcfg.module === "string") return this.finalizeResolve(await legacyMainResolve.call(this, pcfg.module, urlUrl), parentIsCjs, exportsResolution, pkgUrl);
if (typeof pcfg.main === "string") return this.finalizeResolve(await legacyMainResolve.call(this, pcfg.main, urlUrl), parentIsCjs, exportsResolution, pkgUrl);
return this.finalizeResolve(await legacyMainResolve.call(this, null, urlUrl), parentIsCjs, exportsResolution, pkgUrl);
}
if (await this.exists(url + "/index.js")) return url + "/index.js";
if (await this.exists(url + "/index.json")) return url + "/index.json";
if (await this.exists(url + "/index.node")) return url + "/index.node";
if (await this.exists(url)) return url;
if (await this.exists(url + ".js")) return url + ".js";
if (await this.exists(url + ".json")) return url + ".json";
if (await this.exists(url + ".node")) return url + ".node";
return url;
})();
// Only browser maps apply to relative resolved paths
if (this.env.includes("browser")) {
pkgUrl = pkgUrl || await this.getPackageBase(url);
if (url.startsWith(pkgUrl)) {
const pcfg = await this.getPackageConfig(pkgUrl);
if (pcfg && typeof pcfg.browser === "object" && pcfg.browser !== null) {
const subpath = "./" + url.slice(pkgUrl.length);
if (subpath in pcfg.browser) {
const target = pcfg.browser[subpath];
if (target === false) return this.resolveEmpty(parentIsCjs, url, pkgUrl);
if (!target.startsWith("./")) throw new Error(`TODO: External browser map for ${subpath} to ${target} in ${url}`);
// for browser mappings to the same module, avoid a loop
if (pkgUrl + target.slice(2) === url) return url;
return await this.finalizeResolve(pkgUrl + target.slice(2), parentIsCjs, exportsResolution, pkgUrl);
}
}
}
}
// give some compatibility for packages without "exports" field
if (!exportsResolution) {
if (await this.exists(url)) void 0;
else if (await this.exists(url + ".js")) return url + ".js";
else if (await this.exists(url + ".json")) return url + ".json";
else if (await this.exists(url + ".node")) return url + ".node";
}
return url;
}
// reverse exports resolution
// returns _a_ possible export which resolves to the given package URL and subpath
// also handles "imports"
async getExportResolution(pkgUrl, subpath, originalSpecifier) {
const resolvedUrl = subpath === "." ? pkgUrl.slice(0, -1) : pkgUrl + subpath.slice(2);
const pcfg = await this.getPackageConfig(pkgUrl) || {};
if (originalSpecifier[0] === "#") {
if (pcfg.imports === undefined || pcfg.imports === null) return null;
const match = getMapMatch(originalSpecifier, pcfg.imports);
if (!match) return null;
const targets = enumeratePackageTargets(pcfg.imports[match]);
for (const curTarget of targets){
try {
if (await this.finalizeResolve(curTarget, false, true, pkgUrl) === resolvedUrl) {
return ".";
}
} catch {}
}
return null;
}
if (pcfg.exports !== undefined && pcfg.exports !== null) {
if (typeof pcfg.exports === "string") {
if (subpath !== ".") return null;
const url = new URL(pcfg.exports, pkgUrl).href;
try {
if (await this.finalizeResolve(url, false, true, pkgUrl) === resolvedUrl) return ".";
} catch {}
return null;
} else if (!allDotKeys(pcfg.exports)) {
if (subpath !== ".") return null;
const targets = enumeratePackageTargets(pcfg.exports);
for (const curTarget of targets){
try {
if (await this.finalizeResolve(new URL(curTarget, pkgUrl).href, false, true, pkgUrl) === resolvedUrl) return ".";
} catch {}
}
return null;
} else {
let bestMatch;
for (const expt of Object.keys(pcfg.exports)){
const targets = enumeratePackageTargets(pcfg.exports[expt]);
for (const curTarget of targets){
if (curTarget.indexOf("*") === -1) {
if (await this.finalizeResolve(new URL(curTarget, pkgUrl).href, false, true, pkgUrl) === resolvedUrl) {
if (bestMatch) {
if (originalSpecifier.endsWith(bestMatch.slice(2))) {
if (!originalSpecifier.endsWith(expt.slice(2))) continue;
} else if (!originalSpecifier.endsWith(expt.slice(2))) {
// Normal precedence = shortest export!
if (expt.length < bestMatch.length) bestMatch = expt;
}
}
bestMatch = expt;
}
} else {
const parts = curTarget.split("*");
if (!subpath.startsWith(parts[0])) continue;
const matchEndIndex = subpath.indexOf(parts[1], parts[0].length);
if (matchEndIndex === -1) continue;
const match = subpath.slice(parts[0].length, matchEndIndex);
const substitutedTarget = curTarget.replace(/\*/g, match);
if (subpath === substitutedTarget) {
const prefix = expt.slice(0, expt.indexOf("*"));
const suffix = expt.slice(expt.indexOf("*") + 1);
if (bestMatch) {
if (originalSpecifier.endsWith(bestMatch.slice(2))) {
if (!originalSpecifier.endsWith(expt.slice(2).replace("*", match)) || bestMatch.startsWith(prefix) && bestMatch.endsWith(suffix)) continue;
} else if (!originalSpecifier.endsWith(expt.slice(2).replace("*", match))) {
if (bestMatch.startsWith(prefix) && bestMatch.endsWith(suffix)) continue;
}
}
bestMatch = expt.replace("*", match);
}
}
}
}
return bestMatch;
}
} else {
try {
if (typeof pcfg.main === "string" && await this.finalizeResolve(await legacyMainResolve.call(this, pcfg.main, new URL(pkgUrl), originalSpecifier, pkgUrl), false, false, pkgUrl) === resolvedUrl) return ".";
} catch {}
try {
if (await this.finalizeResolve(await legacyMainResolve.call(this, null, new URL(pkgUrl), originalSpecifier, pkgUrl), false, false, pkgUrl) === resolvedUrl) return ".";
} catch {}
try {
if (typeof pcfg.browser === "string" && await this.finalizeResolve(await legacyMainResolve.call(this, pcfg.browser, new URL(pkgUrl), originalSpecifier, pkgUrl), false, false, pkgUrl) === resolvedUrl) return ".";
} catch {}
try {
if (typeof pcfg.module === "string" && await this.finalizeResolve(await legacyMainResolve.call(this, pcfg.module, new URL(pkgUrl), originalSpecifier, pkgUrl), false, false, pkgUrl) === resolvedUrl) return ".";
} catch {}
try {
if (await this.finalizeResolve(new URL(subpath, new URL(pkgUrl)).href, false, false, pkgUrl) === resolvedUrl) return subpath;
} catch {}
}
}
async resolveEmpty(cjsEnv, originalSpecifier, parentUrl) {
const stdlibTarget = {
registry: "npm",
name: "@jspm/core",
ranges: [
new SemverRange("*")
],
unstable: true
};
const provider = this.installer.getProvider(stdlibTarget);
const pkg = await this.resolveLatestTarget(stdlibTarget, provider, parentUrl);
return this.resolveExport(await this.pkgToUrl(pkg, provider), "./nodelibs/@empty", cjsEnv, false, originalSpecifier, parentUrl);
}
// Note: updates here must be tracked in function above
async resolveExport(pkgUrl, subpath, cjsEnv, parentIsCjs, originalSpecifier, parentUrl) {
const env = cjsEnv ? this.cjsEnv : this.env;
const pcfg = await this.getPackageConfig(pkgUrl) || {};
// If the package has no exports then we resolve against "node:@empty":
if (typeof pcfg.exports === "object" && pcfg.exports !== null && Object.keys(pcfg.exports).length === 0) {
return this.resolveEmpty(cjsEnv, originalSpecifier, parentUrl);
}
function throwExportNotDefined() {
throw new JspmError(`No '${subpath}' exports subpath defined in ${pkgUrl} resolving ${originalSpecifier}${importedFrom(parentUrl)}.`, "MODULE_NOT_FOUND");
}
if (pcfg.exports !== undefined && pcfg.exports !== null) {
function allDotKeys(exports) {
for(let p in exports){
if (p[0] !== ".") return false;
}
return true;
}
if (typeof pcfg.exports === "string") {
if (subpath === ".") return this.finalizeResolve(new URL(pcfg.exports, pkgUrl).href, parentIsCjs, true, pkgUrl);
else throwExportNotDefined();
} else if (!allDotKeys(pcfg.exports)) {
if (subpath === ".") {
const url = this.resolvePackageTarget(pcfg.exports, pkgUrl, cjsEnv, "", false);
if (url === null) throwExportNotDefined();
return this.finalizeResolve(url, parentIsCjs, true, pkgUrl);
} else throwExportNotDefined();
} else {
const match = getMapMatch(subpath, pcfg.exports);
if (match) {
let replacement = "";
const wildcardIndex = match.indexOf("*");
if (wildcardIndex !== -1) {
replacement = subpath.slice(wildcardIndex, subpath.length - (match.length - wildcardIndex - 1));
} else if (match.endsWith("/")) {
replacement = subpath.slice(match.length);
}
const resolved = this.resolvePackageTarget(pcfg.exports[match], pkgUrl, cjsEnv, replacement, false);
if (resolved === null) throwExportNotDefined();
return this.finalizeResolve(resolved, parentIsCjs, true, pkgUrl);
}
throwExportNotDefined();
}
} else {
if (subpath === "." || parentIsCjs && subpath === "./") {
if (env.includes("browser") && typeof pcfg.browser === "string") return this.finalizeResolve(await legacyMainResolve.call(this, pcfg.browser, new URL(pkgUrl), originalSpecifier, pkgUrl), parentIsCjs, false, pkgUrl);
if (env.includes("module") && typeof pcfg.module === "string") return this.finalizeResolve(await legacyMainResolve.call(this, pcfg.module, new URL(pkgUrl), originalSpecifier, pkgUrl), parentIsCjs, false, pkgUrl);
if (typeof pcfg.main === "string") return this.finalizeResolve(await legacyMainResolve.call(this, pcfg.main, new URL(pkgUrl), originalSpecifier, pkgUrl), parentIsCjs, false, pkgUrl);
return this.finalizeResolve(await legacyMainResolve.call(this, null, new URL(pkgUrl), originalSpecifier, pkgUrl), parentIsCjs, false, pkgUrl);
} else {
return this.finalizeResolve(new URL(subpath, new URL(pkgUrl)).href, parentIsCjs, false, pkgUrl);
}
}
}
getAnalysis(resolvedUrl) {
const traceEntry = this.traceEntries[resolvedUrl];
if (traceEntry === null || traceEntry === void 0 ? void 0 : traceEntry.parseError) throw traceEntry.parseError;
return traceEntry;
}
async analyze(resolvedUrl) {
if (!this.traceEntryPromises[resolvedUrl]) this.traceEntryPromises[resolvedUrl] = (async ()=>{
let traceEntry = null;
const analysis = await getAnalysis(this, resolvedUrl);
if (analysis) {
traceEntry = {
parseError: null,
wasCjs: false,
usesCjs: false,
deps: null,
dynamicDeps: null,
cjsLazyDeps: null,
hasStaticParent: true,
size: NaN,
integrity: "",
format: undefined
};
if ("parseError" in analysis) {
traceEntry.parseError = analysis.parseError;
} else {
const { deps, dynamicDeps, cjsLazyDeps, size, format, integrity } = analysis;
traceEntry.integrity = integrity;
traceEntry.format = format;
traceEntry.size = size;
traceEntry.deps = deps.sort();
traceEntry.dynamicDeps = dynamicDeps.sort();
traceEntry.cjsLazyDeps = cjsLazyDeps ? cjsLazyDeps.sort() : cjsLazyDeps;
// wasCJS distinct from CJS because it applies to CJS transformed into ESM
// from the resolver perspective
const wasCJS = format === "commonjs" || await this.wasCommonJS(resolvedUrl);
if (wasCJS) traceEntry.wasCjs = true;
}
}
this.traceEntries[resolvedUrl] = traceEntry;
})();
await this.traceEntryPromises[resolvedUrl];
const traceEntry = this.traceEntries[resolvedUrl];
if (traceEntry === null || traceEntry === void 0 ? void 0 : traceEntry.parseError) throw traceEntry.parseError;
return traceEntry;
}
// Note: changes to this function must be updated enumeratePackageTargets too
resolvePackageTarget(target, packageUrl, cjsEnv, subpath, isImport) {
if (typeof target === "string") {
if (target === ".") {
// special dot export for file packages
return packageUrl.slice(0, -1);
}
if (!target.startsWith("./")) {
if (isImport) return target;
throw new Error(`Invalid exports target ${target} resolving ./${subpath} in ${packageUrl}`);
}
if (!target.startsWith("./")) throw new Error("Invalid ");
if (subpath === "") return new URL(target, packageUrl).href;
if (target.indexOf("*") !== -1) {
return new URL(target.replace(/\*/g, subpath), packageUrl).href;
} else if (target.endsWith("/")) {
return new URL(target + subpath, packageUrl).href;
} else {
throw new Error(`Expected pattern or path export resolving ./${subpath} in ${packageUrl}`);
}
} else if (typeof target === "object" && target !== null && !Array.isArray(target)) {
for(const condition in target){
if (condition === "default" || (cjsEnv ? this.cjsEnv : this.env).includes(condition)) {
const resolved = this.resolvePackageTarget(target[condition], packageUrl, cjsEnv, subpath, isImport);
if (resolved) return resolved;
}
}
} else if (Array.isArray(target)) {
// TODO: Validation for arrays
for (const targetFallback of target){
return this.resolvePackageTarget(targetFallback, packageUrl, cjsEnv, subpath, isImport);
}
}
return null;
}
constructor({ env, log, fetchOpts, preserveSymlinks = false, traceCjs = true, traceTs = true, traceSystem = true }){
_define_property(this, "log", void 0);
_define_property(this, "pcfgPromises", Object.create(null));
_define_property(this, "analysisPromises", Object.create(null));
_define_property(this, "pcfgs", Object.create(null));
_define_property(this, "fetchOpts", void 0);
_define_property(this, "preserveSymlinks", void 0);
_define_property(this, "providers", defaultProviders);
// null implies "not found"
_define_property(this, "traceEntries", Object.create(null));
// any trace error is retained in this promise
_define_property(this, "traceEntryPromises", Object.create(null));
_define_property(this, "env", void 0);
_define_property(this, "cjsEnv", void 0);
_define_property(this, "traceCjs", void 0);
_define_property(this, "traceTs", void 0);
_define_property(this, "traceSystem", void 0);
_define_property(this, "context", void 0);
_define_property(this, "installer", void 0);
if (env.includes("require")) throw new Error("Cannot manually pass require condition");
if (!env.includes("import")) env.push("import");
this.env = env;
this.cjsEnv = this.env.map((e)=>e === "import" ? "require" : e);
this.log = log;
this.fetchOpts = fetchOpts;
this.preserveSymlinks = preserveSymlinks;
this.traceCjs = traceCjs;
this.traceTs = traceTs;
this.traceSystem = traceSystem;
this.context = {};
}
}
export function enumeratePackageTargets(target, targets = new Set()) {
if (typeof target === "string") {
targets.add(target);
} else if (typeof target === "object" && target !== null && !Array.isArray(target)) {
for(const condition in target){
enumeratePackageTargets(target[condition], targets);
}
return targets;
} else if (Array.isArray(target)) {
// TODO: Validation for arrays
for (const targetFallback of target){
enumeratePackageTargets(targetFallback, targets);
return targets;
}
}
return targets;
}
async function legacyMainResolve(main, pkgUrl, originalSpecifier, parentUrl) {
let guess;
if (main === null || main === void 0 ? void 0 : main.endsWith("index.js")) {
if (await this.exists(guess = new URL(`./${main}`, pkgUrl).href)) return guess;
} else if (main) {
if (await this.exists(guess = new URL(`./${main}/index.js`, pkgUrl).href)) return guess;
if (await this.exists(guess = new URL(`./${main}/index.json`, pkgUrl).href)) return guess;
if (await this.exists(guess = new URL(`./${main}/index.node`, pkgUrl).href)) return guess;
if (await this.exists(guess = new URL(`./${main}`, pkgUrl).href)) return guess;
if (await this.exists(guess = new URL(`./${main}.js`, pkgUrl).href)) return guess;
if (await this.exists(guess = new URL(`./${main}.json`, pkgUrl).href)) return guess;
if (await this.exists(guess = new URL(`./${main}.node`, pkgUrl).href)) return guess;
} else {
if (pkgUrl.protocol !== "file:" && await this.exists(guess = new URL("./mod.ts", pkgUrl).href)) return guess;
if (await this.exists(guess = new URL("./index.js", pkgUrl).href)) return guess;
if (await this.exists(guess = new URL("./index.json", pkgUrl).href)) return guess;
if (await this.exists(guess = new URL("./index.node", pkgUrl).href)) return guess;
}
// Not found.
throw new JspmError(`Unable to resolve ${main ? main + " in " : ""}${pkgUrl} resolving ${originalSpecifier !== null && originalSpecifier !== void 0 ? originalSpecifier : ""}${importedFrom(parentUrl)}.`, "MODULE_NOT_FOUND");
}
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;
}
// TODO: Refactor legacy intermediate Analysis type into TraceEntry directly
async function getAnalysis(resolver, resolvedUrl) {
const parentIsRequire = false;
const source = await fetch.arrayBuffer(resolvedUrl, resolver.fetchOpts);
if (!source) return null;
// TODO: headers over extensions for non-file URLs
try {
if (resolvedUrl.endsWith(".wasm")) {
try {
var compiled = await WebAssembly.compile(source);
} catch (e) {
throw e;
}
return {
deps: WebAssembly.Module.imports(compiled).map(({ module })=>module),
dynamicDeps: [],
cjsLazyDeps: null,
size: source.byteLength,
format: "wasm",
integrity: await getIntegrity(new Uint8Array(source))
};
}
var sourceText = new TextDecoder().decode(source);
if (resolver.traceTs && (resolvedUrl.endsWith(".ts") || resolvedUrl.endsWith(".tsx") || resolvedUrl.endsWith(".jsx"))) return await createTsAnalysis(sourceText, resolvedUrl);
if (resolvedUrl.endsWith(".json")) {
try {
JSON.parse(sourceText);
return {
deps: [],
dynamicDeps: [],
cjsLazyDeps: null,
size: sourceText.length,
format: "json",
integrity: await getIntegrity(sourceText)
};
} catch {}
}
if (resolvedUrl.endsWith(".css")) {
try {
return {
deps: [],
dynamicDeps: [],
cjsLazyDeps: null,
size: sourceText.length,
format: "css",
integrity: await getIntegrity(sourceText)
};
} catch {}
}
const [imports, exports] = parse(sourceText);
if (imports.every((impt)=>impt.d > 0) && !exports.length && resolvedUrl.startsWith("file:")) {
var _this;
// Support CommonJS package boundary checks for non-ESM on file: protocol only
if (parentIsRequire) {
var _this1;
if (resolver.traceCjs && !(resolvedUrl.endsWith(".mjs") || resolvedUrl.endsWith(".js") && ((_this1 = await resolver.getPackageConfig(await resolver.getPackageBase(resolvedUrl))) === null || _this1 === void 0 ? void 0 : _this1.type) === "module")) {
return createCjsAnalysis(imports, sourceText, resolvedUrl);
}
} else if (resolver.traceCjs && (resolvedUrl.endsWith(".cjs") || resolvedUrl.endsWith(".js") && ((_this = await resolver.getPackageConfig(await resolver.getPackageBase(resolvedUrl))) === null || _this === void 0 ? void 0 : _this.type) !== "module")) {
return createCjsAnalysis(imports, sourceText, resolvedUrl);
}
}
return resolver.traceSystem ? createSystemAnalysis(sourceText, imports, resolvedUrl) : createEsmAnalysis(imports, sourceText, resolvedUrl);
} catch (e) {
if (!e.message || !e.message.startsWith("Parse error @:")) {
return {
parseError: e
};
}
// TODO: better parser errors
if (e.message && e.message.startsWith("Parse error @:")) {
const [topline] = e.message.split("\n", 1);
const pos = topline.slice(14);
let [line, col] = pos.split(":");
const lines = sourceText.split("\n");
let errStack = "";
if (line > 1) errStack += "\n " + lines[line - 2];
errStack += "\n> " + lines[line - 1];
errStack += "\n " + " ".repeat(col - 1) + "^";
if (lines.length > 1) errStack += "\n " + lines[line];
return {
parseError: new JspmError(`${errStack}\n\nError parsing ${resolvedUrl}:${pos}`)
};
}
throw e;
}
}
//# sourceMappingURL=resolver.js.map