summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/module_esm.ts
diff options
context:
space:
mode:
Diffstat (limited to 'ext/node/polyfills/module_esm.ts')
-rw-r--r--ext/node/polyfills/module_esm.ts845
1 files changed, 845 insertions, 0 deletions
diff --git a/ext/node/polyfills/module_esm.ts b/ext/node/polyfills/module_esm.ts
new file mode 100644
index 000000000..e9cb38ff1
--- /dev/null
+++ b/ext/node/polyfills/module_esm.ts
@@ -0,0 +1,845 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/**
+ * NOTE(bartlomieju):
+ * Functionality of this file is ported in Rust in `cli/compat/esm_resolver.ts`.
+ * Unfortunately we have no way to call ESM resolution in Rust from TypeScript code.
+ */
+
+import {
+ fileURLToPath,
+ pathToFileURL,
+} from "internal:deno_node/polyfills/url.ts";
+import {
+ ERR_INVALID_MODULE_SPECIFIER,
+ ERR_INVALID_PACKAGE_CONFIG,
+ ERR_INVALID_PACKAGE_TARGET,
+ ERR_MODULE_NOT_FOUND,
+ ERR_PACKAGE_IMPORT_NOT_DEFINED,
+ ERR_PACKAGE_PATH_NOT_EXPORTED,
+ NodeError,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+
+const { hasOwn } = Object;
+
+export const encodedSepRegEx = /%2F|%2C/i;
+
+function throwInvalidSubpath(
+ subpath: string,
+ packageJSONUrl: string,
+ internal: boolean,
+ base: string,
+) {
+ const reason = `request is not a valid subpath for the "${
+ internal ? "imports" : "exports"
+ }" resolution of ${fileURLToPath(packageJSONUrl)}`;
+ throw new ERR_INVALID_MODULE_SPECIFIER(
+ subpath,
+ reason,
+ base && fileURLToPath(base),
+ );
+}
+
+function throwInvalidPackageTarget(
+ subpath: string,
+ // deno-lint-ignore no-explicit-any
+ target: any,
+ packageJSONUrl: string,
+ internal: boolean,
+ base: string,
+) {
+ if (typeof target === "object" && target !== null) {
+ target = JSON.stringify(target, null, "");
+ } else {
+ target = `${target}`;
+ }
+ throw new ERR_INVALID_PACKAGE_TARGET(
+ fileURLToPath(new URL(".", packageJSONUrl)),
+ subpath,
+ target,
+ internal,
+ base && fileURLToPath(base),
+ );
+}
+
+function throwImportNotDefined(
+ specifier: string,
+ packageJSONUrl: URL | undefined,
+ base: string | URL,
+): TypeError & { code: string } {
+ throw new ERR_PACKAGE_IMPORT_NOT_DEFINED(
+ specifier,
+ packageJSONUrl && fileURLToPath(new URL(".", packageJSONUrl)),
+ fileURLToPath(base),
+ );
+}
+
+function throwExportsNotFound(
+ subpath: string,
+ packageJSONUrl: string,
+ base?: string,
+): Error & { code: string } {
+ throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
+ subpath,
+ fileURLToPath(new URL(".", packageJSONUrl)),
+ base && fileURLToPath(base),
+ );
+}
+
+function patternKeyCompare(a: string, b: string): number {
+ const aPatternIndex = a.indexOf("*");
+ const bPatternIndex = b.indexOf("*");
+ const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1;
+ const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1;
+ if (baseLenA > baseLenB) return -1;
+ if (baseLenB > baseLenA) return 1;
+ if (aPatternIndex === -1) return 1;
+ if (bPatternIndex === -1) return -1;
+ if (a.length > b.length) return -1;
+ if (b.length > a.length) return 1;
+ return 0;
+}
+
+function fileExists(url: string | URL): boolean {
+ try {
+ const info = Deno.statSync(url);
+ return info.isFile;
+ } catch {
+ return false;
+ }
+}
+
+function tryStatSync(path: string): { isDirectory: boolean } {
+ try {
+ const info = Deno.statSync(path);
+ return { isDirectory: info.isDirectory };
+ } catch {
+ return { isDirectory: false };
+ }
+}
+
+/**
+ * Legacy CommonJS main resolution:
+ * 1. let M = pkg_url + (json main field)
+ * 2. TRY(M, M.js, M.json, M.node)
+ * 3. TRY(M/index.js, M/index.json, M/index.node)
+ * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
+ * 5. NOT_FOUND
+ */
+function legacyMainResolve(
+ packageJSONUrl: URL,
+ packageConfig: PackageConfig,
+ base: string | URL,
+): URL {
+ let guess;
+ if (packageConfig.main !== undefined) {
+ // Note: fs check redundances will be handled by Descriptor cache here.
+ if (
+ fileExists(guess = new URL(`./${packageConfig.main}`, packageJSONUrl))
+ ) {
+ return guess;
+ } else if (
+ fileExists(guess = new URL(`./${packageConfig.main}.js`, packageJSONUrl))
+ ) {
+ // pass
+ } else if (
+ fileExists(
+ guess = new URL(`./${packageConfig.main}.json`, packageJSONUrl),
+ )
+ ) {
+ // pass
+ } else if (
+ fileExists(
+ guess = new URL(`./${packageConfig.main}.node`, packageJSONUrl),
+ )
+ ) {
+ // pass
+ } else if (
+ fileExists(
+ guess = new URL(`./${packageConfig.main}/index.js`, packageJSONUrl),
+ )
+ ) {
+ // pass
+ } else if (
+ fileExists(
+ guess = new URL(`./${packageConfig.main}/index.json`, packageJSONUrl),
+ )
+ ) {
+ // pass
+ } else if (
+ fileExists(
+ guess = new URL(`./${packageConfig.main}/index.node`, packageJSONUrl),
+ )
+ ) {
+ // pass
+ } else guess = undefined;
+ if (guess) {
+ // TODO(bartlomieju):
+ // emitLegacyIndexDeprecation(guess, packageJSONUrl, base,
+ // packageConfig.main);
+ return guess;
+ }
+ // Fallthrough.
+ }
+ if (fileExists(guess = new URL("./index.js", packageJSONUrl))) {
+ // pass
+ } // So fs.
+ else if (fileExists(guess = new URL("./index.json", packageJSONUrl))) {
+ // pass
+ } else if (fileExists(guess = new URL("./index.node", packageJSONUrl))) {
+ // pass
+ } else guess = undefined;
+ if (guess) {
+ // TODO(bartlomieju):
+ // emitLegacyIndexDeprecation(guess, packageJSONUrl, base, packageConfig.main);
+ return guess;
+ }
+ // Not found.
+ throw new ERR_MODULE_NOT_FOUND(
+ fileURLToPath(new URL(".", packageJSONUrl)),
+ fileURLToPath(base),
+ );
+}
+
+function parsePackageName(
+ specifier: string,
+ base: string | URL,
+): { packageName: string; packageSubpath: string; isScoped: boolean } {
+ let separatorIndex = specifier.indexOf("/");
+ let validPackageName = true;
+ let isScoped = false;
+ if (specifier[0] === "@") {
+ isScoped = true;
+ if (separatorIndex === -1 || specifier.length === 0) {
+ validPackageName = false;
+ } else {
+ separatorIndex = specifier.indexOf("/", separatorIndex + 1);
+ }
+ }
+
+ const packageName = separatorIndex === -1
+ ? specifier
+ : specifier.slice(0, separatorIndex);
+
+ // Package name cannot have leading . and cannot have percent-encoding or
+ // separators.
+ for (let i = 0; i < packageName.length; i++) {
+ if (packageName[i] === "%" || packageName[i] === "\\") {
+ validPackageName = false;
+ break;
+ }
+ }
+
+ if (!validPackageName) {
+ throw new ERR_INVALID_MODULE_SPECIFIER(
+ specifier,
+ "is not a valid package name",
+ fileURLToPath(base),
+ );
+ }
+
+ const packageSubpath = "." +
+ (separatorIndex === -1 ? "" : specifier.slice(separatorIndex));
+
+ return { packageName, packageSubpath, isScoped };
+}
+
+function packageResolve(
+ specifier: string,
+ base: string,
+ conditions: Set<string>,
+): URL | undefined {
+ const { packageName, packageSubpath, isScoped } = parsePackageName(
+ specifier,
+ base,
+ );
+
+ // ResolveSelf
+ const packageConfig = getPackageScopeConfig(base);
+ if (packageConfig.exists) {
+ const packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
+ if (
+ packageConfig.name === packageName &&
+ packageConfig.exports !== undefined && packageConfig.exports !== null
+ ) {
+ return packageExportsResolve(
+ packageJSONUrl.toString(),
+ packageSubpath,
+ packageConfig,
+ base,
+ conditions,
+ );
+ }
+ }
+
+ let packageJSONUrl = new URL(
+ "./node_modules/" + packageName + "/package.json",
+ base,
+ );
+ let packageJSONPath = fileURLToPath(packageJSONUrl);
+ let lastPath;
+ do {
+ const stat = tryStatSync(
+ packageJSONPath.slice(0, packageJSONPath.length - 13),
+ );
+ if (!stat.isDirectory) {
+ lastPath = packageJSONPath;
+ packageJSONUrl = new URL(
+ (isScoped ? "../../../../node_modules/" : "../../../node_modules/") +
+ packageName + "/package.json",
+ packageJSONUrl,
+ );
+ packageJSONPath = fileURLToPath(packageJSONUrl);
+ continue;
+ }
+
+ // Package match.
+ const packageConfig = getPackageConfig(packageJSONPath, specifier, base);
+ if (packageConfig.exports !== undefined && packageConfig.exports !== null) {
+ return packageExportsResolve(
+ packageJSONUrl.toString(),
+ packageSubpath,
+ packageConfig,
+ base,
+ conditions,
+ );
+ }
+ if (packageSubpath === ".") {
+ return legacyMainResolve(packageJSONUrl, packageConfig, base);
+ }
+ return new URL(packageSubpath, packageJSONUrl);
+ // Cross-platform root check.
+ } while (packageJSONPath.length !== lastPath.length);
+
+ // TODO(bartlomieju): this is false positive
+ // deno-lint-ignore no-unreachable
+ throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base));
+}
+
+const invalidSegmentRegEx = /(^|\\|\/)(\.\.?|node_modules)(\\|\/|$)/;
+const patternRegEx = /\*/g;
+
+function resolvePackageTargetString(
+ target: string,
+ subpath: string,
+ match: string,
+ packageJSONUrl: string,
+ base: string,
+ pattern: boolean,
+ internal: boolean,
+ conditions: Set<string>,
+): URL | undefined {
+ if (subpath !== "" && !pattern && target[target.length - 1] !== "/") {
+ throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
+ }
+
+ if (!target.startsWith("./")) {
+ if (
+ internal && !target.startsWith("../") &&
+ !target.startsWith("/")
+ ) {
+ let isURL = false;
+ try {
+ new URL(target);
+ isURL = true;
+ } catch {
+ // pass
+ }
+ if (!isURL) {
+ const exportTarget = pattern
+ ? target.replace(patternRegEx, () => subpath)
+ : target + subpath;
+ return packageResolve(exportTarget, packageJSONUrl, conditions);
+ }
+ }
+ throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
+ }
+
+ if (invalidSegmentRegEx.test(target.slice(2))) {
+ throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
+ }
+
+ const resolved = new URL(target, packageJSONUrl);
+ const resolvedPath = resolved.pathname;
+ const packagePath = new URL(".", packageJSONUrl).pathname;
+
+ if (!resolvedPath.startsWith(packagePath)) {
+ throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
+ }
+
+ if (subpath === "") return resolved;
+
+ if (invalidSegmentRegEx.test(subpath)) {
+ const request = pattern
+ ? match.replace("*", () => subpath)
+ : match + subpath;
+ throwInvalidSubpath(request, packageJSONUrl, internal, base);
+ }
+
+ if (pattern) {
+ return new URL(resolved.href.replace(patternRegEx, () => subpath));
+ }
+ return new URL(subpath, resolved);
+}
+
+function isArrayIndex(key: string): boolean {
+ const keyNum = +key;
+ if (`${keyNum}` !== key) return false;
+ return keyNum >= 0 && keyNum < 0xFFFF_FFFF;
+}
+
+function resolvePackageTarget(
+ packageJSONUrl: string,
+ // deno-lint-ignore no-explicit-any
+ target: any,
+ subpath: string,
+ packageSubpath: string,
+ base: string,
+ pattern: boolean,
+ internal: boolean,
+ conditions: Set<string>,
+): URL | undefined {
+ if (typeof target === "string") {
+ return resolvePackageTargetString(
+ target,
+ subpath,
+ packageSubpath,
+ packageJSONUrl,
+ base,
+ pattern,
+ internal,
+ conditions,
+ );
+ } else if (Array.isArray(target)) {
+ if (target.length === 0) {
+ return undefined;
+ }
+
+ let lastException;
+ for (let i = 0; i < target.length; i++) {
+ const targetItem = target[i];
+ let resolved;
+ try {
+ resolved = resolvePackageTarget(
+ packageJSONUrl,
+ targetItem,
+ subpath,
+ packageSubpath,
+ base,
+ pattern,
+ internal,
+ conditions,
+ );
+ } catch (e: unknown) {
+ lastException = e;
+ if (e instanceof NodeError && e.code === "ERR_INVALID_PACKAGE_TARGET") {
+ continue;
+ }
+ throw e;
+ }
+ if (resolved === undefined) {
+ continue;
+ }
+ if (resolved === null) {
+ lastException = null;
+ continue;
+ }
+ return resolved;
+ }
+ if (lastException === undefined || lastException === null) {
+ return undefined;
+ }
+ throw lastException;
+ } else if (typeof target === "object" && target !== null) {
+ const keys = Object.getOwnPropertyNames(target);
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i];
+ if (isArrayIndex(key)) {
+ throw new ERR_INVALID_PACKAGE_CONFIG(
+ fileURLToPath(packageJSONUrl),
+ base,
+ '"exports" cannot contain numeric property keys.',
+ );
+ }
+ }
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i];
+ if (key === "default" || conditions.has(key)) {
+ const conditionalTarget = target[key];
+ const resolved = resolvePackageTarget(
+ packageJSONUrl,
+ conditionalTarget,
+ subpath,
+ packageSubpath,
+ base,
+ pattern,
+ internal,
+ conditions,
+ );
+ if (resolved === undefined) {
+ continue;
+ }
+ return resolved;
+ }
+ }
+ return undefined;
+ } else if (target === null) {
+ return undefined;
+ }
+ throwInvalidPackageTarget(
+ packageSubpath,
+ target,
+ packageJSONUrl,
+ internal,
+ base,
+ );
+}
+
+export function packageExportsResolve(
+ packageJSONUrl: string,
+ packageSubpath: string,
+ packageConfig: PackageConfig,
+ base: string,
+ conditions: Set<string>,
+ // @ts-ignore `URL` needs to be forced due to control flow
+): URL {
+ let exports = packageConfig.exports;
+ if (isConditionalExportsMainSugar(exports, packageJSONUrl, base)) {
+ exports = { ".": exports };
+ }
+
+ if (
+ hasOwn(exports, packageSubpath) &&
+ !packageSubpath.includes("*") &&
+ !packageSubpath.endsWith("/")
+ ) {
+ const target = exports[packageSubpath];
+ const resolved = resolvePackageTarget(
+ packageJSONUrl,
+ target,
+ "",
+ packageSubpath,
+ base,
+ false,
+ false,
+ conditions,
+ );
+ if (resolved === null || resolved === undefined) {
+ throwExportsNotFound(packageSubpath, packageJSONUrl, base);
+ }
+ return resolved!;
+ }
+
+ let bestMatch = "";
+ let bestMatchSubpath = "";
+ const keys = Object.getOwnPropertyNames(exports);
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i];
+ const patternIndex = key.indexOf("*");
+ if (
+ patternIndex !== -1 &&
+ packageSubpath.startsWith(key.slice(0, patternIndex))
+ ) {
+ // When this reaches EOL, this can throw at the top of the whole function:
+ //
+ // if (StringPrototypeEndsWith(packageSubpath, '/'))
+ // throwInvalidSubpath(packageSubpath)
+ //
+ // To match "imports" and the spec.
+ if (packageSubpath.endsWith("/")) {
+ // TODO(@bartlomieju):
+ // emitTrailingSlashPatternDeprecation(
+ // packageSubpath,
+ // packageJSONUrl,
+ // base,
+ // );
+ }
+ const patternTrailer = key.slice(patternIndex + 1);
+ if (
+ packageSubpath.length >= key.length &&
+ packageSubpath.endsWith(patternTrailer) &&
+ patternKeyCompare(bestMatch, key) === 1 &&
+ key.lastIndexOf("*") === patternIndex
+ ) {
+ bestMatch = key;
+ bestMatchSubpath = packageSubpath.slice(
+ patternIndex,
+ packageSubpath.length - patternTrailer.length,
+ );
+ }
+ }
+ }
+
+ if (bestMatch) {
+ const target = exports[bestMatch];
+ const resolved = resolvePackageTarget(
+ packageJSONUrl,
+ target,
+ bestMatchSubpath,
+ bestMatch,
+ base,
+ true,
+ false,
+ conditions,
+ );
+ if (resolved === null || resolved === undefined) {
+ throwExportsNotFound(packageSubpath, packageJSONUrl, base);
+ }
+ return resolved!;
+ }
+
+ throwExportsNotFound(packageSubpath, packageJSONUrl, base);
+}
+
+export interface PackageConfig {
+ pjsonPath: string;
+ exists: boolean;
+ name?: string;
+ main?: string;
+ // deno-lint-ignore no-explicit-any
+ exports?: any;
+ // deno-lint-ignore no-explicit-any
+ imports?: any;
+ type?: string;
+}
+
+const packageJSONCache = new Map(); /* string -> PackageConfig */
+
+function getPackageConfig(
+ path: string,
+ specifier: string | URL,
+ base?: string | URL,
+): PackageConfig {
+ const existing = packageJSONCache.get(path);
+ if (existing !== undefined) {
+ return existing;
+ }
+
+ let source: string | undefined;
+ try {
+ source = new TextDecoder().decode(
+ Deno.readFileSync(path),
+ );
+ } catch {
+ // pass
+ }
+
+ if (source === undefined) {
+ const packageConfig = {
+ pjsonPath: path,
+ exists: false,
+ main: undefined,
+ name: undefined,
+ type: "none",
+ exports: undefined,
+ imports: undefined,
+ };
+ packageJSONCache.set(path, packageConfig);
+ return packageConfig;
+ }
+
+ let packageJSON;
+ try {
+ packageJSON = JSON.parse(source);
+ } catch (error) {
+ throw new ERR_INVALID_PACKAGE_CONFIG(
+ path,
+ (base ? `"${specifier}" from ` : "") + fileURLToPath(base || specifier),
+ // @ts-ignore there's no assertion for type and `error` is thus `unknown`
+ error.message,
+ );
+ }
+
+ let { imports, main, name, type } = packageJSON;
+ const { exports } = packageJSON;
+ if (typeof imports !== "object" || imports === null) imports = undefined;
+ if (typeof main !== "string") main = undefined;
+ if (typeof name !== "string") name = undefined;
+ // Ignore unknown types for forwards compatibility
+ if (type !== "module" && type !== "commonjs") type = "none";
+
+ const packageConfig = {
+ pjsonPath: path,
+ exists: true,
+ main,
+ name,
+ type,
+ exports,
+ imports,
+ };
+ packageJSONCache.set(path, packageConfig);
+ return packageConfig;
+}
+
+function getPackageScopeConfig(resolved: URL | string): PackageConfig {
+ let packageJSONUrl = new URL("./package.json", resolved);
+ while (true) {
+ const packageJSONPath = packageJSONUrl.pathname;
+ if (packageJSONPath.endsWith("node_modules/package.json")) {
+ break;
+ }
+ const packageConfig = getPackageConfig(
+ fileURLToPath(packageJSONUrl),
+ resolved,
+ );
+ if (packageConfig.exists) return packageConfig;
+
+ const lastPackageJSONUrl = packageJSONUrl;
+ packageJSONUrl = new URL("../package.json", packageJSONUrl);
+
+ // Terminates at root where ../package.json equals ../../package.json
+ // (can't just check "/package.json" for Windows support).
+ if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) break;
+ }
+ const packageJSONPath = fileURLToPath(packageJSONUrl);
+ const packageConfig = {
+ pjsonPath: packageJSONPath,
+ exists: false,
+ main: undefined,
+ name: undefined,
+ type: "none",
+ exports: undefined,
+ imports: undefined,
+ };
+ packageJSONCache.set(packageJSONPath, packageConfig);
+ return packageConfig;
+}
+
+export function packageImportsResolve(
+ name: string,
+ base: string,
+ conditions: Set<string>,
+ // @ts-ignore `URL` needs to be forced due to control flow
+): URL {
+ if (
+ name === "#" || name.startsWith("#/") ||
+ name.startsWith("/")
+ ) {
+ const reason = "is not a valid internal imports specifier name";
+ throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base));
+ }
+ let packageJSONUrl;
+ const packageConfig = getPackageScopeConfig(base);
+ if (packageConfig.exists) {
+ packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
+ const imports = packageConfig.imports;
+ if (imports) {
+ if (
+ hasOwn(imports, name) &&
+ !name.includes("*")
+ ) {
+ const resolved = resolvePackageTarget(
+ packageJSONUrl.toString(),
+ imports[name],
+ "",
+ name,
+ base,
+ false,
+ true,
+ conditions,
+ );
+ if (resolved !== null && resolved !== undefined) {
+ return resolved;
+ }
+ } else {
+ let bestMatch = "";
+ let bestMatchSubpath = "";
+ const keys = Object.getOwnPropertyNames(imports);
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i];
+ const patternIndex = key.indexOf("*");
+ if (
+ patternIndex !== -1 &&
+ name.startsWith(
+ key.slice(0, patternIndex),
+ )
+ ) {
+ const patternTrailer = key.slice(patternIndex + 1);
+ if (
+ name.length >= key.length &&
+ name.endsWith(patternTrailer) &&
+ patternKeyCompare(bestMatch, key) === 1 &&
+ key.lastIndexOf("*") === patternIndex
+ ) {
+ bestMatch = key;
+ bestMatchSubpath = name.slice(
+ patternIndex,
+ name.length - patternTrailer.length,
+ );
+ }
+ }
+ }
+
+ if (bestMatch) {
+ const target = imports[bestMatch];
+ const resolved = resolvePackageTarget(
+ packageJSONUrl.toString(),
+ target,
+ bestMatchSubpath,
+ bestMatch,
+ base,
+ true,
+ true,
+ conditions,
+ );
+ if (resolved !== null && resolved !== undefined) {
+ return resolved;
+ }
+ }
+ }
+ }
+ }
+ throwImportNotDefined(name, packageJSONUrl, base);
+}
+
+function isConditionalExportsMainSugar(
+ // deno-lint-ignore no-explicit-any
+ exports: any,
+ packageJSONUrl: string,
+ base: string,
+): boolean {
+ if (typeof exports === "string" || Array.isArray(exports)) return true;
+ if (typeof exports !== "object" || exports === null) return false;
+
+ const keys = Object.getOwnPropertyNames(exports);
+ let isConditionalSugar = false;
+ let i = 0;
+ for (let j = 0; j < keys.length; j++) {
+ const key = keys[j];
+ const curIsConditionalSugar = key === "" || key[0] !== ".";
+ if (i++ === 0) {
+ isConditionalSugar = curIsConditionalSugar;
+ } else if (isConditionalSugar !== curIsConditionalSugar) {
+ const message =
+ "\"exports\" cannot contain some keys starting with '.' and some not." +
+ " The exports object must either be an object of package subpath keys" +
+ " or an object of main entry condition name keys only.";
+ throw new ERR_INVALID_PACKAGE_CONFIG(
+ fileURLToPath(packageJSONUrl),
+ base,
+ message,
+ );
+ }
+ }
+ return isConditionalSugar;
+}