UNPKG

@patchworkdev/pdk

Version:

Patchwork Development Kit

186 lines (185 loc) 7.74 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.tsLoaderSync = tsLoaderSync; exports.tsLoader = tsLoader; const fs = __importStar(require("fs")); const module_1 = require("module"); const path = __importStar(require("path")); const ts_morph_1 = require("ts-morph"); const error_1 = require("./error"); const logger_1 = require("./logger"); // Added to grab the files dependencies so they can be added to the compilation function collectDependencies(filePath) { const deps = new Set(); const queue = [filePath]; while (queue.length > 0) { const currentPath = queue.pop(); if (deps.has(currentPath)) continue; deps.add(currentPath); try { const source = fs.readFileSync(currentPath, 'utf-8'); // Very basic import scanning - you might want to make this more robust const importMatches = source.matchAll(/from\s+['"](\.[^'"]+)['"]/g); for (const match of importMatches) { const importPath = match[1]; try { // Try to resolve the TypeScript file directly const resolvedPath = tryResolveTypescript(importPath, path.dirname(currentPath)); if (resolvedPath) { queue.push(resolvedPath); } } catch (error) { logger_1.logger.debug(`Could not resolve import ${importPath}: ${error}`); } } } catch (error) { logger_1.logger.debug(`Error processing dependency ${currentPath}: ${error}`); } } return deps; } function tryResolveTypescript(request, containingPath) { const extensions = ['.ts', '.tsx', '.d.ts']; const possiblePaths = []; // Try exact path with extensions, check for index.* for (const ext of extensions) { possiblePaths.push(path.resolve(containingPath, request + ext), path.resolve(containingPath, request, `index${ext}`)); } // Also try exact path in case it already has an extension possiblePaths.push(path.resolve(containingPath, request)); for (const possiblePath of possiblePaths) { if (fs.existsSync(possiblePath)) { return possiblePath; } } return undefined; } function tryResolveCompiled(request, containingPath, compiledFiles) { const tsPath = tryResolveTypescript(request, containingPath); if (tsPath && compiledFiles.has(tsPath)) { return tsPath; } return undefined; } function tsLoaderSync(filePath, options) { try { logger_1.logger.debug(`Attempting to access ${filePath}`); fs.accessSync(filePath); } catch (error) { throw new error_1.PDKError(error_1.ErrorCode.FILE_NOT_FOUND, `Unable to access file at ${filePath}`); } // Collect all dependencies first const dependencies = collectDependencies(filePath); logger_1.logger.debug(`Found ${dependencies.size} dependencies`); // Create a new project instance with in-memory filesystem const project = new ts_morph_1.Project({ compilerOptions: { target: ts_morph_1.ScriptTarget.Latest, module: ts_morph_1.ModuleKind.CommonJS, moduleResolution: ts_morph_1.ts.ModuleResolutionKind.NodeNext, ...options?.compilerOptions, }, skipLoadingLibFiles: true, useInMemoryFileSystem: true, }); // Add all files to the in-memory filesystem for (const depPath of dependencies) { const source = fs.readFileSync(depPath, 'utf-8'); project.createSourceFile(depPath, source); } // Get all output files const compiledFiles = new Map(); project.getSourceFiles().forEach((sourceFile) => { const output = sourceFile.getEmitOutput(); const compiled = output.getOutputFiles()[0].getText(); compiledFiles.set(sourceFile.getFilePath(), compiled); }); // Create a new module object for the main file const moduleObj = new module_1.Module(filePath); moduleObj.filename = filePath; moduleObj.paths = module.paths; // Set up module interception let originalRequire; if (options?.moduleOverrides || compiledFiles.size > 1) { logger_1.logger.debug(`Setting up module interception for ${compiledFiles.size} files`); originalRequire = module_1.Module.prototype.require; const newRequire = function (id) { // First check explicit overrides const override = options?.moduleOverrides?.[id]; if (override) { return require(override); } // Then check if it's a relative import if (id.startsWith('.')) { // First try to resolve as a TypeScript file const resolvedTsPath = tryResolveCompiled(id, path.dirname(this.filename), compiledFiles); if (resolvedTsPath) { const compiledCode = compiledFiles.get(resolvedTsPath); const mod = new module_1.Module(resolvedTsPath); mod.filename = resolvedTsPath; mod.paths = this.paths; mod._compile(compiledCode, resolvedTsPath); return mod.exports; } // If not found as TypeScript, try normal require try { return originalRequire.call(this, id); } catch (error) { // If normal require fails, try one more time with .js extension // This handles cases where TypeScript emits require('./file') but Node expects require('./file.js') if (error.code === 'MODULE_NOT_FOUND') { return originalRequire.call(this, id + '.js'); } throw error; } } // Fall back to normal require for non-relative imports return originalRequire.call(this, id); }; Object.assign(newRequire, originalRequire); module_1.Module.prototype.require = newRequire; } try { // Execute the compiled code const compiledCode = compiledFiles.get(filePath); moduleObj._compile(compiledCode, filePath); logger_1.logger.debug(`File compiled successfully: ${filePath}`); return moduleObj.exports; } finally { if (originalRequire) { module_1.Module.prototype.require = originalRequire; } } } async function tsLoader(path, options) { return Promise.resolve(tsLoaderSync(path, options)); }