From 9f90711677673e74b802c320de80f85601dfced4 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 4 Oct 2024 15:58:33 +0200 Subject: [PATCH 1/4] fix: skip interopDefault if default is not extensible --- package.json | 3 ++- pnpm-lock.yaml | 8 ++++++++ src/utils.ts | 10 +++++++--- test/fixtures/deps/index.ts | 1 + test/fixtures/deps/zod.ts | 4 ++++ 5 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/deps/zod.ts diff --git a/package.json b/package.json index 432a4cec..7827db5f 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,8 @@ "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", "webpack-license-plugin": "^4.5.0", - "yoctocolors": "^2.1.1" + "yoctocolors": "^2.1.1", + "zod": "^3.23.8" }, "packageManager": "pnpm@9.11.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cef46ba6..0ea5a774 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -188,6 +188,9 @@ importers: yoctocolors: specifier: ^2.1.1 version: 2.1.1 + zod: + specifier: ^3.23.8 + version: 3.23.8 packages: @@ -2477,6 +2480,9 @@ packages: resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} engines: {node: '>=18'} + zod@3.23.8: + resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + snapshots: '@ampproject/remapping@2.3.0': @@ -4827,3 +4833,5 @@ snapshots: yocto-queue@0.1.0: {} yoctocolors@2.1.1: {} + + zod@3.23.8: {} diff --git a/src/utils.ts b/src/utils.ts index 2198637b..988bf401 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -111,7 +111,11 @@ function interopDefault( return sourceModule; } const defaultValue = sourceModule.default; - if (defaultValue === undefined || defaultValue === null) { + if ( + defaultValue === undefined || + defaultValue === null || + !Object.isExtensible(defaultValue) + ) { return sourceModule; } const _defaultType = typeof defaultValue; @@ -132,8 +136,8 @@ function interopDefault( }, }); } - } catch { - // Ignore error + } catch (error_) { + console.log(error_); } } return defaultValue; diff --git a/test/fixtures/deps/index.ts b/test/fixtures/deps/index.ts index 27896c0f..8bbcefdd 100644 --- a/test/fixtures/deps/index.ts +++ b/test/fixtures/deps/index.ts @@ -4,3 +4,4 @@ import "./etag"; import "./mime"; import "./typescript"; import "./moment"; +import "./zod"; diff --git a/test/fixtures/deps/zod.ts b/test/fixtures/deps/zod.ts new file mode 100644 index 00000000..4b40f318 --- /dev/null +++ b/test/fixtures/deps/zod.ts @@ -0,0 +1,4 @@ +// @ts-ignore +import { z } from "zod"; + +console.log("npm:zod:", z.string().parse("hello world") === "hello world"); From 61613f3eb964dc5b8f5abe3e653e65672feaa998 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 4 Oct 2024 17:08:30 +0200 Subject: [PATCH 2/4] feat: use smarter proxy for `interopDefault` --- package.json | 1 + pnpm-lock.yaml | 3 + src/utils.ts | 77 +++++++++++++----------- test/__snapshots__/fixtures.test.ts.snap | 9 ++- test/fixtures/deps/defu.ts | 4 ++ test/fixtures/deps/destr.ts | 7 +++ test/fixtures/deps/index.ts | 2 + 7 files changed, 65 insertions(+), 38 deletions(-) create mode 100644 test/fixtures/deps/defu.ts create mode 100644 test/fixtures/deps/destr.ts diff --git a/package.json b/package.json index 7827db5f..9aa336a3 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "changelogen": "^0.5.7", "config": "^3.3.12", "consola": "^3.2.3", + "defu": "^6.1.4", "destr": "^2.0.3", "escape-string-regexp": "^5.0.0", "eslint": "^9.11.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ea5a774..2f801aaa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,6 +92,9 @@ importers: consola: specifier: ^3.2.3 version: 3.2.3 + defu: + specifier: ^6.1.4 + version: 6.1.4 destr: specifier: ^2.0.3 version: 2.0.3 diff --git a/src/utils.ts b/src/utils.ts index 988bf401..d4e50662 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -102,45 +102,52 @@ export function jitiInteropDefault(ctx: Context, mod: any) { return ctx.opts.interopDefault ? interopDefault(mod) : mod; } -// Source: https://github.com/unjs/mlly/blob/2348417d25522b98ed60ccc10eb030abb2f65744/src/cjs.ts#L59C1-L93C2 -function interopDefault( - sourceModule: any, - opts: { preferNamespace?: boolean } = {}, -): any { - if (!isObject(sourceModule) || !("default" in sourceModule)) { - return sourceModule; +function interopDefault(mod: any): any { + if (!mod || !("default" in mod)) { + return mod; } - const defaultValue = sourceModule.default; - if ( - defaultValue === undefined || - defaultValue === null || - !Object.isExtensible(defaultValue) - ) { - return sourceModule; + + const defaultExport = mod.default; + if (defaultExport === undefined || defaultExport === null) { + return mod; } - const _defaultType = typeof defaultValue; - if ( - _defaultType !== "object" && - !(_defaultType === "function" && !opts.preferNamespace) - ) { - return opts.preferNamespace ? sourceModule : defaultValue; + + const defaultExportType = typeof defaultExport; + if (defaultExportType !== "object" && defaultExportType !== "function") { + return mod; } - for (const key in sourceModule) { - try { - if (!(key in defaultValue)) { - Object.defineProperty(defaultValue, key, { - enumerable: key !== "default", - configurable: key !== "default", - get() { - return sourceModule[key]; - }, - }); - } - } catch (error_) { - console.log(error_); - } + + const modKeys = Object.getOwnPropertyNames(mod); + if (modKeys.length === 1) { + return defaultExport; } - return defaultValue; + + return new Proxy(mod, { + get(target, prop, receiver) { + if (prop === "__esModule") { + return true; // Bypass other interops + } + if (Reflect.has(target, prop)) { + return Reflect.get(target, prop, receiver); + } + let fallback = + prop === "default" + ? defaultExport + : Reflect.get(defaultExport, prop, receiver); + if (typeof fallback === "function") { + fallback = fallback.bind(defaultExport); + } + return fallback; + }, + apply(target, thisArg, args) { + if (typeof target === "function") { + return Reflect.apply(target, thisArg, args); + } + if (defaultExportType === "function") { + return Reflect.apply(defaultExport, thisArg, args); + } + }, + }); } export function normalizeWindowsImportId(id: string) { diff --git a/test/__snapshots__/fixtures.test.ts.snap b/test/__snapshots__/fixtures.test.ts.snap index 8b4771f7..4d026afc 100644 --- a/test/__snapshots__/fixtures.test.ts.snap +++ b/test/__snapshots__/fixtures.test.ts.snap @@ -8,10 +8,13 @@ exports[`fixtures > data-uri > stdout 1`] = `""`; exports[`fixtures > deps > stdout 1`] = ` "npm:config: true +npm:defu {} +npm:destr true npm:etag: true npm:mime: true npm:typescript: true -npm:moment-timezone true" +npm:moment-timezone true +npm:zod: true" `; exports[`fixtures > env > stdout 1`] = ` @@ -35,8 +38,8 @@ exports[`fixtures > error-runtime > stderr 1`] = `"test error"`; exports[`fixtures > error-runtime > stdout 1`] = `""`; exports[`fixtures > esm > stdout 1`] = ` -"{ utilsLib: { utils: { default: 'default' }, version: '123' } } -{ utils: { default: 'default' } } +"{ utilsLib: { utils: { a: 'a', default: 'default' }, version: '123' } } +{ utils: { a: 'a', default: 'default' } } { file: '/test.js', dir: '', diff --git a/test/fixtures/deps/defu.ts b/test/fixtures/deps/defu.ts new file mode 100644 index 00000000..dc853157 --- /dev/null +++ b/test/fixtures/deps/defu.ts @@ -0,0 +1,4 @@ +import defuDefault from "defu"; +import { defu } from "defu"; + +console.log("npm:defu", defu({}) && defuDefault({})); diff --git a/test/fixtures/deps/destr.ts b/test/fixtures/deps/destr.ts new file mode 100644 index 00000000..e24c4876 --- /dev/null +++ b/test/fixtures/deps/destr.ts @@ -0,0 +1,7 @@ +import { destr } from "destr"; +import destrDefault from "destr"; + +console.log( + "npm:destr", + destr("true") === true && destrDefault("true") === true, +); diff --git a/test/fixtures/deps/index.ts b/test/fixtures/deps/index.ts index 8bbcefdd..0eae1d36 100644 --- a/test/fixtures/deps/index.ts +++ b/test/fixtures/deps/index.ts @@ -1,5 +1,7 @@ import "./config"; import "./consola"; +import "./defu"; +import "./destr"; import "./etag"; import "./mime"; import "./typescript"; From 43df73a9fd284ef52e57be4d7b1eae41407d97c4 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 4 Oct 2024 17:17:58 +0200 Subject: [PATCH 3/4] handle default + __esModule --- src/utils.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index d4e50662..9940b3be 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -112,16 +112,16 @@ function interopDefault(mod: any): any { return mod; } + const modKeys = Object.getOwnPropertyNames(mod); + if (modKeys.length === 1 || (modKeys.length === 2 && "__esModule" in mod)) { + return defaultExport; + } + const defaultExportType = typeof defaultExport; if (defaultExportType !== "object" && defaultExportType !== "function") { return mod; } - const modKeys = Object.getOwnPropertyNames(mod); - if (modKeys.length === 1) { - return defaultExport; - } - return new Proxy(mod, { get(target, prop, receiver) { if (prop === "__esModule") { From c0c04dcfc713241a205c60ec48e7216ad9c9ddfd Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 4 Oct 2024 17:25:34 +0200 Subject: [PATCH 4/4] simplify logic --- src/utils.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 9940b3be..25087b2f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -125,15 +125,15 @@ function interopDefault(mod: any): any { return new Proxy(mod, { get(target, prop, receiver) { if (prop === "__esModule") { - return true; // Bypass other interops + return true; + } + if (prop === "default") { + return defaultExport; } if (Reflect.has(target, prop)) { return Reflect.get(target, prop, receiver); } - let fallback = - prop === "default" - ? defaultExport - : Reflect.get(defaultExport, prop, receiver); + let fallback = Reflect.get(defaultExport, prop, receiver); if (typeof fallback === "function") { fallback = fallback.bind(defaultExport); }