|
@@ -10,6 +10,7 @@ import { Logger, PathAdapter, PluginInfo } from '../types.js';
|
|
|
|
|
|
|
|
import { findConfigExport } from './ast-utils.js';
|
|
import { findConfigExport } from './ast-utils.js';
|
|
|
import { noopLogger } from './logger.js';
|
|
import { noopLogger } from './logger.js';
|
|
|
|
|
+import { createPathTransformer } from './path-transformer.js';
|
|
|
import { discoverPlugins } from './plugin-discovery.js';
|
|
import { discoverPlugins } from './plugin-discovery.js';
|
|
|
import { findTsConfigPaths } from './tsconfig-utils.js';
|
|
import { findTsConfigPaths } from './tsconfig-utils.js';
|
|
|
|
|
|
|
@@ -118,8 +119,10 @@ export async function compile(options: CompilerOptions): Promise<CompileResult>
|
|
|
let config: any;
|
|
let config: any;
|
|
|
try {
|
|
try {
|
|
|
config = await import(compiledConfigFilePath).then(m => m[exportedSymbolName]);
|
|
config = await import(compiledConfigFilePath).then(m => m[exportedSymbolName]);
|
|
|
- } catch (e) {
|
|
|
|
|
- logger.error(`Error loading config: ${e instanceof Error ? e.message : String(e)}`);
|
|
|
|
|
|
|
+ } catch (e: any) {
|
|
|
|
|
+ const errorMessage =
|
|
|
|
|
+ e instanceof Error ? `${e.message}\n${e.stack ?? ''}` : JSON.stringify(e, null, 2);
|
|
|
|
|
+ logger.error(`Error loading config: ${errorMessage}`);
|
|
|
}
|
|
}
|
|
|
if (!config) {
|
|
if (!config) {
|
|
|
throw new Error(
|
|
throw new Error(
|
|
@@ -149,12 +152,20 @@ async function compileTypeScript({
|
|
|
}): Promise<void> {
|
|
}): Promise<void> {
|
|
|
await fs.ensureDir(outputPath);
|
|
await fs.ensureDir(outputPath);
|
|
|
|
|
|
|
|
- // Find tsconfig paths first
|
|
|
|
|
- const tsConfigInfo = await findTsConfigPaths(
|
|
|
|
|
|
|
+ // Find tsconfig paths - we need BOTH original and transformed versions
|
|
|
|
|
+ // Original paths: Used by TypeScript for module resolution during compilation
|
|
|
|
|
+ // Transformed paths: Used by the path transformer for rewriting output imports
|
|
|
|
|
+ const originalTsConfigInfo = await findTsConfigPaths(
|
|
|
inputPath,
|
|
inputPath,
|
|
|
logger,
|
|
logger,
|
|
|
'compiling',
|
|
'compiling',
|
|
|
- transformTsConfigPathMappings,
|
|
|
|
|
|
|
+ ({ patterns }) => patterns, // No transformation - use original paths
|
|
|
|
|
+ );
|
|
|
|
|
+ const transformedTsConfigInfo = await findTsConfigPaths(
|
|
|
|
|
+ inputPath,
|
|
|
|
|
+ logger,
|
|
|
|
|
+ 'compiling',
|
|
|
|
|
+ transformTsConfigPathMappings, // Apply user's transformation
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
const compilerOptions: ts.CompilerOptions = {
|
|
const compilerOptions: ts.CompilerOptions = {
|
|
@@ -183,32 +194,55 @@ async function compileTypeScript({
|
|
|
|
|
|
|
|
logger.debug(`Compiling ${inputPath} to ${outputPath} using TypeScript...`);
|
|
logger.debug(`Compiling ${inputPath} to ${outputPath} using TypeScript...`);
|
|
|
|
|
|
|
|
- // Add path mappings if found
|
|
|
|
|
- if (tsConfigInfo) {
|
|
|
|
|
|
|
+ // Add path mappings if found - use ORIGINAL paths for TypeScript module resolution
|
|
|
|
|
+ if (originalTsConfigInfo) {
|
|
|
// We need to set baseUrl and paths for TypeScript to resolve the imports
|
|
// We need to set baseUrl and paths for TypeScript to resolve the imports
|
|
|
- compilerOptions.baseUrl = tsConfigInfo.baseUrl;
|
|
|
|
|
- compilerOptions.paths = tsConfigInfo.paths;
|
|
|
|
|
|
|
+ compilerOptions.baseUrl = originalTsConfigInfo.baseUrl;
|
|
|
|
|
+ compilerOptions.paths = originalTsConfigInfo.paths;
|
|
|
// This is critical - it tells TypeScript to preserve the paths in the output
|
|
// This is critical - it tells TypeScript to preserve the paths in the output
|
|
|
- // compilerOptions.rootDir = tsConfigInfo.baseUrl;
|
|
|
|
|
|
|
+ // compilerOptions.rootDir = originalTsConfigInfo.baseUrl;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ logger.debug(`tsConfig original paths: ${JSON.stringify(originalTsConfigInfo?.paths, null, 2)}`);
|
|
|
|
|
+ logger.debug(`tsConfig transformed paths: ${JSON.stringify(transformedTsConfigInfo?.paths, null, 2)}`);
|
|
|
|
|
+ logger.debug(`tsConfig baseUrl: ${originalTsConfigInfo?.baseUrl ?? 'UNKNOWN'}`);
|
|
|
|
|
+
|
|
|
|
|
+ // Build custom transformers
|
|
|
|
|
+ const afterTransformers: Array<ts.TransformerFactory<ts.SourceFile>> = [];
|
|
|
|
|
+
|
|
|
|
|
+ // Add path transformer for ESM mode when there are path mappings
|
|
|
|
|
+ // This is necessary because tsconfig-paths.register() only works for CommonJS require(),
|
|
|
|
|
+ // not for ESM import(). We need to transform the import paths during compilation.
|
|
|
|
|
+ //
|
|
|
|
|
+ // IMPORTANT: We use 'after' transformers because:
|
|
|
|
|
+ // 1. 'before' runs before TypeScript resolves modules - changing paths there breaks resolution
|
|
|
|
|
+ // 2. 'after' runs after module resolution but before emit - paths are transformed in output only
|
|
|
|
|
+ //
|
|
|
|
|
+ // We use TRANSFORMED paths here because the output directory structure may differ from source
|
|
|
|
|
+ if (module === 'esm' && transformedTsConfigInfo) {
|
|
|
|
|
+ logger.debug('Adding path transformer for ESM mode');
|
|
|
|
|
+ afterTransformers.push(
|
|
|
|
|
+ createPathTransformer({
|
|
|
|
|
+ baseUrl: transformedTsConfigInfo.baseUrl,
|
|
|
|
|
+ paths: transformedTsConfigInfo.paths,
|
|
|
|
|
+ }),
|
|
|
|
|
+ );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- logger.debug(`tsConfig paths: ${JSON.stringify(tsConfigInfo?.paths, null, 2)}`);
|
|
|
|
|
- logger.debug(`tsConfig baseUrl: ${tsConfigInfo?.baseUrl ?? 'UNKNOWN'}`);
|
|
|
|
|
|
|
+ // Add the existing transformer for non-entry-point files
|
|
|
|
|
+ afterTransformers.push(context => {
|
|
|
|
|
+ return sourceFile => {
|
|
|
|
|
+ // Only transform files that are not the entry point
|
|
|
|
|
+ if (sourceFile.fileName === inputPath) {
|
|
|
|
|
+ return sourceFile;
|
|
|
|
|
+ }
|
|
|
|
|
+ sourceFile.fileName = path.join(outputPath, path.basename(sourceFile.fileName));
|
|
|
|
|
+ return sourceFile;
|
|
|
|
|
+ };
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- // Create a custom transformer to rewrite the output paths
|
|
|
|
|
const customTransformers: ts.CustomTransformers = {
|
|
const customTransformers: ts.CustomTransformers = {
|
|
|
- after: [
|
|
|
|
|
- context => {
|
|
|
|
|
- return sourceFile => {
|
|
|
|
|
- // Only transform files that are not the entry point
|
|
|
|
|
- if (sourceFile.fileName === inputPath) {
|
|
|
|
|
- return sourceFile;
|
|
|
|
|
- }
|
|
|
|
|
- sourceFile.fileName = path.join(outputPath, path.basename(sourceFile.fileName));
|
|
|
|
|
- return sourceFile;
|
|
|
|
|
- };
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
|
|
+ after: afterTransformers,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const program = ts.createProgram([inputPath], compilerOptions);
|
|
const program = ts.createProgram([inputPath], compilerOptions);
|