feat(tsbuild): Add tsconfig.json support and safer compiler option merging; protect critical options; apply path and enum transforms; bump dependencies.
This commit is contained in:
		@@ -62,19 +62,56 @@ export class TsBuild {
 | 
			
		||||
   * Helper function to read and process tsconfig.json
 | 
			
		||||
   */
 | 
			
		||||
  private getTsConfigOptions(): CompilerOptions {
 | 
			
		||||
    const tsconfig = plugins.smartfile.fs.toObjectSync(plugins.path.join(paths.cwd, 'tsconfig.json'));
 | 
			
		||||
    const returnObject: CompilerOptions = {};
 | 
			
		||||
    
 | 
			
		||||
    let tsconfig: any;
 | 
			
		||||
 | 
			
		||||
    // Try to read tsconfig.json, but don't fail if it doesn't exist
 | 
			
		||||
    try {
 | 
			
		||||
      tsconfig = plugins.smartfile.fs.toObjectSync(plugins.path.join(paths.cwd, 'tsconfig.json'));
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      // tsconfig.json doesn't exist or is invalid - use defaults
 | 
			
		||||
      return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!tsconfig || !tsconfig.compilerOptions) {
 | 
			
		||||
      return returnObject;
 | 
			
		||||
      return {};
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Process baseUrl
 | 
			
		||||
    if (tsconfig.compilerOptions.baseUrl) {
 | 
			
		||||
      returnObject.baseUrl = tsconfig.compilerOptions.baseUrl;
 | 
			
		||||
 | 
			
		||||
    // Start by copying ALL compiler options from tsconfig.json
 | 
			
		||||
    const returnObject: CompilerOptions = { ...tsconfig.compilerOptions };
 | 
			
		||||
 | 
			
		||||
    // Apply special transformations for string-to-enum conversions
 | 
			
		||||
 | 
			
		||||
    // Process target (convert string to enum)
 | 
			
		||||
    if (tsconfig.compilerOptions.target && typeof tsconfig.compilerOptions.target === 'string') {
 | 
			
		||||
      const targetKey = tsconfig.compilerOptions.target.toUpperCase();
 | 
			
		||||
      if (targetKey in plugins.typescript.ScriptTarget) {
 | 
			
		||||
        returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Process paths
 | 
			
		||||
 | 
			
		||||
    // Process module (convert string to enum)
 | 
			
		||||
    if (tsconfig.compilerOptions.module && typeof tsconfig.compilerOptions.module === 'string') {
 | 
			
		||||
      const moduleKey = tsconfig.compilerOptions.module.toUpperCase();
 | 
			
		||||
      if (moduleKey in plugins.typescript.ModuleKind) {
 | 
			
		||||
        returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind];
 | 
			
		||||
      } else if (moduleKey === 'NODENEXT') {
 | 
			
		||||
        returnObject.module = plugins.typescript.ModuleKind.NodeNext;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Process moduleResolution (convert string to enum)
 | 
			
		||||
    if (tsconfig.compilerOptions.moduleResolution && typeof tsconfig.compilerOptions.moduleResolution === 'string') {
 | 
			
		||||
      const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase();
 | 
			
		||||
      if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) {
 | 
			
		||||
        returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[
 | 
			
		||||
          moduleResolutionKey as keyof typeof plugins.typescript.ModuleResolutionKind
 | 
			
		||||
        ];
 | 
			
		||||
      } else if (moduleResolutionKey === 'NODENEXT') {
 | 
			
		||||
        returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeNext;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Apply path transformations (ts_ → dist_ts_)
 | 
			
		||||
    if (tsconfig.compilerOptions.paths) {
 | 
			
		||||
      returnObject.paths = { ...tsconfig.compilerOptions.paths };
 | 
			
		||||
      for (const path of Object.keys(returnObject.paths)) {
 | 
			
		||||
@@ -83,58 +120,24 @@ export class TsBuild {
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Process target
 | 
			
		||||
    if (tsconfig.compilerOptions.target) {
 | 
			
		||||
      if (typeof tsconfig.compilerOptions.target === 'string') {
 | 
			
		||||
        const targetKey = tsconfig.compilerOptions.target.toUpperCase();
 | 
			
		||||
        if (targetKey in plugins.typescript.ScriptTarget) {
 | 
			
		||||
          returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget];
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Process module
 | 
			
		||||
    if (tsconfig.compilerOptions.module) {
 | 
			
		||||
      if (typeof tsconfig.compilerOptions.module === 'string') {
 | 
			
		||||
        const moduleKey = tsconfig.compilerOptions.module.toUpperCase();
 | 
			
		||||
        if (moduleKey in plugins.typescript.ModuleKind) {
 | 
			
		||||
          returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind];
 | 
			
		||||
        } else if (moduleKey === 'NODENEXT') {
 | 
			
		||||
          returnObject.module = plugins.typescript.ModuleKind.NodeNext;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Process moduleResolution
 | 
			
		||||
    if (tsconfig.compilerOptions.moduleResolution) {
 | 
			
		||||
      if (typeof tsconfig.compilerOptions.moduleResolution === 'string') {
 | 
			
		||||
        const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase();
 | 
			
		||||
        if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) {
 | 
			
		||||
          returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[
 | 
			
		||||
            moduleResolutionKey as keyof typeof plugins.typescript.ModuleResolutionKind
 | 
			
		||||
          ];
 | 
			
		||||
        } else if (moduleResolutionKey === 'NODENEXT') {
 | 
			
		||||
          returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeNext;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Copy boolean options directly
 | 
			
		||||
    const booleanOptions = [
 | 
			
		||||
      'experimentalDecorators', 'useDefineForClassFields', 
 | 
			
		||||
      'esModuleInterop', 'verbatimModuleSyntax'
 | 
			
		||||
    ];
 | 
			
		||||
    
 | 
			
		||||
    for (const option of booleanOptions) {
 | 
			
		||||
      if (option in tsconfig.compilerOptions) {
 | 
			
		||||
        (returnObject as any)[option] = (tsconfig.compilerOptions as any)[option];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    return returnObject;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns critical default options that should not be overridden by tsconfig.json
 | 
			
		||||
   * These options are essential for tsbuild's functionality and build integrity
 | 
			
		||||
   */
 | 
			
		||||
  private getCriticalDefaults(): CompilerOptions {
 | 
			
		||||
    return {
 | 
			
		||||
      outDir: 'dist_ts/',           // Required for path transformation logic
 | 
			
		||||
      noEmitOnError: true,           // Build integrity - prevent broken builds
 | 
			
		||||
      declaration: true,             // Library consumers depend on .d.ts files
 | 
			
		||||
      emitDecoratorMetadata: true,   // Required for dependency injection frameworks
 | 
			
		||||
      inlineSourceMap: true,         // Consistent debugging experience
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Process command line arguments and return applicable compiler options
 | 
			
		||||
   */
 | 
			
		||||
@@ -162,6 +165,13 @@ export class TsBuild {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Merges compilerOptions with the default compiler options
 | 
			
		||||
   *
 | 
			
		||||
   * Merge order (later overwrites earlier):
 | 
			
		||||
   * 1. compilerOptionsDefault - Base defaults for all options
 | 
			
		||||
   * 2. getTsConfigOptions() - User's tsconfig.json (all options)
 | 
			
		||||
   * 3. getCriticalDefaults() - Protected options that shouldn't be overridden by tsconfig.json
 | 
			
		||||
   * 4. customTsOptions - Programmatic options (can override critical defaults)
 | 
			
		||||
   * 5. getCommandLineOptions() - CLI flags (highest priority)
 | 
			
		||||
   */
 | 
			
		||||
  public mergeCompilerOptions(
 | 
			
		||||
    customTsOptions: CompilerOptions = {},
 | 
			
		||||
@@ -169,10 +179,11 @@ export class TsBuild {
 | 
			
		||||
  ): CompilerOptions {
 | 
			
		||||
    // create merged options
 | 
			
		||||
    const mergedOptions: CompilerOptions = {
 | 
			
		||||
      ...compilerOptionsDefault,
 | 
			
		||||
      ...customTsOptions,
 | 
			
		||||
      ...this.getCommandLineOptions(argvArg),
 | 
			
		||||
      ...this.getTsConfigOptions(),
 | 
			
		||||
      ...compilerOptionsDefault,           // 1. All defaults
 | 
			
		||||
      ...this.getTsConfigOptions(),        // 2. User's tsconfig.json (all options)
 | 
			
		||||
      ...this.getCriticalDefaults(),       // 3. Protected overrides
 | 
			
		||||
      ...customTsOptions,                  // 4. Programmatic options
 | 
			
		||||
      ...this.getCommandLineOptions(argvArg), // 5. CLI flags (highest priority)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return mergedOptions;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user