diff --git a/lib/jiti-native.mjs b/lib/jiti-native.mjs new file mode 100644 index 00000000..07598e93 --- /dev/null +++ b/lib/jiti-native.mjs @@ -0,0 +1,90 @@ +/** + * @typedef {import('./types').Jiti} Jiti + * @typedef {import('./types').JitiOptions} JitiOptions + */ + +/** + * @param {string} parentURL + * @param {JitiOptions} [_opts] + * @returns {Jiti} + */ +export function createJiti(parentURL = "./_.js", _opts) { + if (isDir(parentURL)) { + parentURL += "/_.js"; + } + + /** @type {Jiti} */ + function jiti() { + throw unsupportedError( + "`jiti()` is not supported in native mode, use `jiti.import()` instead.", + ); + } + + jiti.resolve = () => { + throw unsupportedError("`jiti.resolve()` is not supported in native mode."); + }; + + jiti.esmResolve = (id, opts) => { + try { + console.log("resolve", { id, from: opts?.parentURL || parentURL }); + return import.meta.resolve(id, opts?.parentURL || parentURL); + } catch (error) { + if (opts?.try) { + return undefined; + } else { + throw error; + } + } + }; + + jiti.import = async function (id, opts) { + const resolved = await this.esmResolve(id, opts); + if (!resolved) { + if (opts?.try) { + return undefined; + } else { + throw new Error(`Cannot resolve module '${id}'`); + } + } + return import(resolved); + }; + + jiti.transform = () => { + throw unsupportedError( + "`jiti.transform()` is not supported in native mode.", + ); + }; + + jiti.evalModule = () => { + throw unsupportedError( + "`jiti.evalModule()` is not supported in native mode.", + ); + }; + + jiti.main = undefined; + jiti.extensions = Object.create(null); + jiti.cache = Object.create(null); + + return jiti; +} + +export default createJiti; + +/** + * @param {string} message + */ +function unsupportedError(message) { + throw new Error( + `[jiti] ${message} (import or require \`jiti/node\` for more features).`, + ); +} + +function isDir(filename) { + if (filename instanceof URL || filename.startsWith("file://")) { + return false; + } + if (filename.endsWith("/")) { + return true; + } + return !filename.split("/").pop().includes("."); +} diff --git a/package.json b/package.json index 6d3cb3d1..0a66c93d 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,21 @@ "types": "./lib/jiti-register.d.mts", "import": "./lib/jiti-register.mjs" }, + "./native": { + "bun": "./lib/jiti-native.mjs", + "deno": "./lib/jiti-native.mjs", + "node": { + "import": { + "types": "./lib/jiti.d.mts", + "default": "./lib/jiti.mjs" + }, + "require": { + "types": "./lib/jiti.d.cts", + "default": "./lib/jiti.cjs" + } + }, + "default": "./lib/jiti-native.mjs" + }, "./package.json": "./package.json" }, "main": "./lib/jiti.cjs", diff --git a/test/bun-native.test.ts b/test/bun-native.test.ts new file mode 100644 index 00000000..a33f61c3 --- /dev/null +++ b/test/bun-native.test.ts @@ -0,0 +1,26 @@ +import { fileURLToPath } from "node:url"; +import { readdir } from "node:fs/promises"; +// @ts-ignore +import { test } from "bun:test"; + +import { createJiti } from "../lib/jiti-native.mjs"; + +const fixturesDir = fileURLToPath(new URL("fixtures", import.meta.url)); + +const fixtures = await readdir(fixturesDir); + +const _jiti = createJiti(fixturesDir); + +for (const fixture of fixtures) { + if ( + fixture === "error-runtime" || + fixture === "error-parse" || + fixture === "typescript" + ) { + continue; + } + + test("fixtures/" + fixture + " (ESM) (Native)", async () => { + await _jiti.import("./" + fixture); + }); +} diff --git a/vitest.config.ts b/vitest.config.ts index 1745be76..cc612de2 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -5,7 +5,7 @@ export default defineConfig({ exclude: [ "**/test.{ts,mjs,cjs,js}", "node_modules/**/*", - "test/bun.test.ts", + "test/bun*.test.ts", ], }, });