diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..74e3b8d --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,10 @@ +# This configuration file was automatically generated by Gitpod. +# Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) +# and commit this file to your remote git repository to share the goodness with others. + +# Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart + +tasks: + - init: npm install && npm run build + + diff --git a/src/index.ts b/src/index.ts index 01ffb4d..ea88442 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,8 @@ import { GetSourceContext, GetSourceHook, GetSourceResponse, + LoadContext, + LoadResponse, ModuleFormat, ResolveContext, ResolveHook, @@ -71,6 +73,7 @@ export async function resolve( // specifiers ending in the TypeScript file extensions. return { url: resolvedUrl.href, + shortCircuit: true, }; } @@ -87,6 +90,7 @@ export async function resolve( return { url: file.href, + shortCircuit: true, }; } @@ -253,6 +257,117 @@ ${isDefault ? `export default cjs['default'];` : 'export default cjs;'} return defaultGetSource(url, context, defaultGetSource); } +export async function load( + url: string, + context: LoadContext, + nextLoad: (specifier: string, context: LoadContext) => Promise +): Promise { + const resolvedUrl = new URL(url); + const fileName = basename(resolvedUrl.pathname); + + let format: string = 'commonjs'; + + if (extensionsRegex.test(fileName)) format = 'module'; + + const response = await nextLoad(url, context); + + if (format === 'module') { + const sourceFilePath = fileURLToPath(url); + + // Load the closest `tsconfig.json` to the source file + const tsConfig = await getTSConfig(dirname(sourceFilePath)); + TSConfig = tsConfig; + + // Transpile the source code that Node passed to us. + const transpiledModule = ts.transpileModule(response.source.toString(), { + compilerOptions: TSConfig, + reportDiagnostics: true, + fileName: resolvedUrl.pathname, + moduleName: fileName, + }); + + return { + format: 'module', + source: transpiledModule.outputText, + shortCircuit: true + } + } + + if (response.format === 'commonjs') { + + + const urlParts = url.split('/node_modules/'); + + // Extract the module name after node_modules. + const moduleName = urlParts.pop()!; + + const nodeModulesPath = urlParts.join('/node_modules/'); + + // Create a require function next to node_module, and import the CommonJS module. + const require = createRequire(`${nodeModulesPath}/noop.js`); + const dynModule = require(moduleName); + let isDefault = false; + + let defaultKeys: string[] = []; + + const moduleKeys = Object.keys(dynModule); + + if (dynModule.default) { + if (dynModule.default !== dynModule) { + isDefault = true; + defaultKeys = Object.keys(dynModule.default).filter( + (defaultKey) => !moduleKeys.includes(defaultKey), + ); + } + } + + // Export as ES Module. + const linkKeys = Object.keys(dynModule).filter((key) => key !== 'default'); + + return { + format: 'module', + source: ` + import {createRequire} from 'module'; + + const require = createRequire('${nodeModulesPath}/noop.js'); + const cjs = require('${moduleName}'); + + ${linkKeys + .map((prop) => `let $${prop} = cjs[${JSON.stringify(prop)}];`) + .join(';\n')} + + ${defaultKeys + .map((prop) => `let $default${prop} = cjs.default[${JSON.stringify(prop)}];`) + .join(';\n')} + + export { + ${linkKeys.map((prop) => ` $${prop} as ${prop},`).join('\n')} + } + + export { + ${defaultKeys.map((prop) => ` $default${prop} as ${prop},`).join('\n')} + } + + ${isDefault ? `export default cjs['default'];` : 'export default cjs;'} + `, + shortCircuit: false + } + } + + + // return { + // format: 'commonjs', + // shortCircuit: false, + // source: '' + // } + + + + // console.log('Response from load', response) + + return response; +} + export async function transformSource( source: Source, context: TransformContext, diff --git a/src/types.ts b/src/types.ts index 5e0db8a..5850432 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,9 +14,26 @@ export interface ResolveContext { parentURL?: string; } +export interface LoadContext { + conditions: string[]; + + format?: string + + importAssertions: object; +} + +export interface LoadResponse { + format: string; + + shortCircuit?: boolean; + + source: string | ArrayBuffer; +} + export interface ResolveResponse { url: string; format?: string; + shortCircuit?: boolean; } export type ResolveHook = (