Compare commits
	
		
			20 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c6ab493efc | |||
| 82ae8a0e4a | |||
| 787becc4d3 | |||
| 746ca8767a | |||
| 55c1a2953a | |||
| 8e9fcb8135 | |||
| 18573c777d | |||
| fa654b83e3 | |||
| aa3c83cd95 | |||
| 20ed41df42 | |||
| 7162476f7f | |||
| 1b012628eb | |||
| 4081086621 | |||
| b9cf09ccba | |||
| 8463fbc78a | |||
| 0164eb51a1 | |||
| a305dd89dd | |||
| fa6b053ee0 | |||
| adfba21c67 | |||
| 050e41cdf9 | 
							
								
								
									
										78
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										78
									
								
								changelog.md
									
									
									
									
									
								
							@@ -1,5 +1,83 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-11-02 - 2.7.0 - feat(tsbuild)
 | 
				
			||||||
 | 
					Add tsconfig.json support and safer compiler option merging; protect critical options; apply path and enum transforms; bump dependencies.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add robust tsconfig.json reading with graceful fallback when no tsconfig is present or it is invalid
 | 
				
			||||||
 | 
					- Merge compiler options in a clear priority order (defaults -> tsconfig -> protected defaults -> programmatic -> CLI flags)
 | 
				
			||||||
 | 
					- Introduce protected (critical) compiler options that cannot be overridden by tsconfig.json: outDir, noEmitOnError, declaration, emitDecoratorMetadata, inlineSourceMap
 | 
				
			||||||
 | 
					- Convert string values from tsconfig (target, module, moduleResolution) to TypeScript enum values where applicable; special-case NodeNext
 | 
				
			||||||
 | 
					- Transform tsconfig path mappings by replacing './ts_' with './dist_ts_' to keep runtime path resolution consistent with compiled output
 | 
				
			||||||
 | 
					- Expose getCriticalDefaults helper and adjust mergeCompilerOptions to apply protected defaults before programmatic and CLI overrides
 | 
				
			||||||
 | 
					- Update README with documentation for tsconfig support, merge order, protected compiler options, and example tsconfig
 | 
				
			||||||
 | 
					- Bump dependencies/devDependencies: @push.rocks/smartcli ^4.0.19, @push.rocks/smartlog ^3.1.10, typescript 5.9.3, @git.zone/tsrun ^1.6.2, @git.zone/tstest ^2.7.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-08-29 - 2.6.8 - fix(tsbuild)
 | 
				
			||||||
 | 
					Avoid process.exit in library, add confirmskiplibcheck flag, improve CLI exit handling and JSON/quiet modes, update test script
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Changed package.json test script from "tsrun test/test.ts --verbose" to "tstest test/test.ts --verbose".
 | 
				
			||||||
 | 
					- Library no longer calls process.exit from compile and compileWithErrorTracking; errors are returned or thrown so callers can decide process termination.
 | 
				
			||||||
 | 
					- skipLibCheck behavior updated: delay/warning only happens when --confirmskiplibcheck is present; otherwise a short informational note is printed (suppressed in --quiet/--json).
 | 
				
			||||||
 | 
					- CLI now awaits compileGlobStringObject calls and inspects a final error summary attached to argv to decide process.exit(1) when errors occurred.
 | 
				
			||||||
 | 
					- compileGlobStringObject/exports now respect --quiet and --json modes, emit a JSON summary when --json is used, and attach the final error summary to argv so the CLI can determine exit behavior.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-08-18 - 2.6.7 - fix(tspublish)
 | 
				
			||||||
 | 
					Bump @git.zone/tspublish dependency to ^1.10.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Updated dependency @git.zone/tspublish from ^1.10.2 to ^1.10.3 in package.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-08-18 - 2.6.6 - fix(dependencies)
 | 
				
			||||||
 | 
					Update dependency @git.zone/tspublish to ^1.10.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Bumped @git.zone/tspublish in package.json from ^1.10.1 to ^1.10.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-08-18 - 2.6.5 - fix(dependencies)
 | 
				
			||||||
 | 
					Bump dependencies and add pnpm-workspace configuration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Updated @git.zone/tspublish from ^1.9.1 to ^1.10.1
 | 
				
			||||||
 | 
					- Updated @push.rocks/smartfile from ^11.2.4 to ^11.2.7
 | 
				
			||||||
 | 
					- Updated @push.rocks/smartpath from ^5.0.18 to ^6.0.0
 | 
				
			||||||
 | 
					- Updated typescript from 5.8.3 to 5.9.2
 | 
				
			||||||
 | 
					- Updated devDependency @git.zone/tstest from ^1.10.1 to ^2.3.4
 | 
				
			||||||
 | 
					- Added pnpm-workspace.yaml with onlyBuiltDependencies list (esbuild, mongodb-memory-server, puppeteer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-05-24 - 2.6.4 - fix(dependencies)
 | 
				
			||||||
 | 
					Add .npmrc and update dependency versions for smartfile and tstest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add .npmrc with registry configuration for npm
 | 
				
			||||||
 | 
					- Bump @push.rocks/smartfile version from ^11.2.3 to ^11.2.4
 | 
				
			||||||
 | 
					- Bump @git.zone/tstest version from ^1.9.0 to ^1.10.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-05-21 - 2.6.3 - fix(tsbuild)
 | 
				
			||||||
 | 
					minor maintenance updates and documentation improvements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Updated commit metadata to align with project version
 | 
				
			||||||
 | 
					- Refined CLI command parsing and diagnostics logging for better clarity
 | 
				
			||||||
 | 
					- Improved code readability in compiler options merging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-05-21 - 2.6.2 - fix(npm configuration)
 | 
				
			||||||
 | 
					Remove .npmrc file to default npm registry behavior
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Deleted .npmrc file that hard-coded the npm registry URL to https://registry.npmjs.org/
 | 
				
			||||||
 | 
					- This change leverages npm's default registry settings and reduces configuration clutter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-05-21 - 2.6.1 - fix(tsbuild.classes)
 | 
				
			||||||
 | 
					Improve error diagnostics handling by removing legacy helper and integrating more robust error summaries in the compilation process
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Removed the handleDiagnostics method and its legacy usage
 | 
				
			||||||
 | 
					- Replaced legacy calls with inline processDiagnostics checks for pre-emit and emit phases
 | 
				
			||||||
 | 
					- Combined error summaries for clearer reporting during emit checks and type validation
 | 
				
			||||||
 | 
					- Enhanced error output to guide users on resolving TypeScript errors before emission
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-05-21 - 2.6.0 - feat(tsbuild)
 | 
				
			||||||
 | 
					Improve task logging and update dependencies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add .npmrc file with npm registry configuration
 | 
				
			||||||
 | 
					- Update test script to use '--verbose' flag
 | 
				
			||||||
 | 
					- Bump dependency versions for @push.rocks packages and TypeScript
 | 
				
			||||||
 | 
					- Enhance TsBuild logging by incorporating task info (e.g. task number, total tasks, output folder, and compile durations)
 | 
				
			||||||
 | 
					- Propagate task info in compileFileArrayWithErrorTracking for better task tracking
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 2025-05-21 - 2.5.2 - fix(tsbuild)
 | 
					## 2025-05-21 - 2.5.2 - fix(tsbuild)
 | 
				
			||||||
Improve diagnostic error handling and summary reporting for TypeScript compilation by refactoring diagnostic processing and adding pre-emit error checks.
 | 
					Improve diagnostic error handling and summary reporting for TypeScript compilation by refactoring diagnostic processing and adding pre-emit error checks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								package.json
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@git.zone/tsbuild",
 | 
					  "name": "@git.zone/tsbuild",
 | 
				
			||||||
  "version": "2.5.2",
 | 
					  "version": "2.7.0",
 | 
				
			||||||
  "private": false,
 | 
					  "private": false,
 | 
				
			||||||
  "description": "A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.",
 | 
					  "description": "A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.",
 | 
				
			||||||
  "main": "dist_ts/index.js",
 | 
					  "main": "dist_ts/index.js",
 | 
				
			||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
    "tsbuild": "./cli.js"
 | 
					    "tsbuild": "./cli.js"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "test": "tsrun test/test.ts",
 | 
					    "test": "tstest test/test.ts --verbose",
 | 
				
			||||||
    "build": "node cli.ts.js --web",
 | 
					    "build": "node cli.ts.js --web",
 | 
				
			||||||
    "buildDocs": "tsdoc"
 | 
					    "buildDocs": "tsdoc"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
@@ -36,20 +36,20 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  "homepage": "https://code.foss.global/git.zone/tsbuild#README",
 | 
					  "homepage": "https://code.foss.global/git.zone/tsbuild#README",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@git.zone/tspublish": "^1.9.1",
 | 
					    "@git.zone/tspublish": "^1.10.3",
 | 
				
			||||||
    "@push.rocks/early": "^4.0.4",
 | 
					    "@push.rocks/early": "^4.0.4",
 | 
				
			||||||
    "@push.rocks/smartcli": "^4.0.11",
 | 
					    "@push.rocks/smartcli": "^4.0.19",
 | 
				
			||||||
    "@push.rocks/smartdelay": "^3.0.5",
 | 
					    "@push.rocks/smartdelay": "^3.0.5",
 | 
				
			||||||
    "@push.rocks/smartfile": "^11.1.5",
 | 
					    "@push.rocks/smartfile": "^11.2.7",
 | 
				
			||||||
    "@push.rocks/smartlog": "^3.0.7",
 | 
					    "@push.rocks/smartlog": "^3.1.10",
 | 
				
			||||||
    "@push.rocks/smartpath": "^5.0.18",
 | 
					    "@push.rocks/smartpath": "^6.0.0",
 | 
				
			||||||
    "@push.rocks/smartpromise": "^4.2.2",
 | 
					    "@push.rocks/smartpromise": "^4.2.3",
 | 
				
			||||||
    "typescript": "5.7.3"
 | 
					    "typescript": "5.9.3"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@git.zone/tsrun": "^1.2.47",
 | 
					    "@git.zone/tsrun": "^1.6.2",
 | 
				
			||||||
    "@push.rocks/tapbundle": "^5.5.6",
 | 
					    "@git.zone/tstest": "^2.7.0",
 | 
				
			||||||
    "@types/node": "^22.12.0"
 | 
					    "@types/node": "^22.15.21"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "files": [
 | 
					  "files": [
 | 
				
			||||||
    "ts/**/*",
 | 
					    "ts/**/*",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8969
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8969
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					onlyBuiltDependencies:
 | 
				
			||||||
 | 
					  - esbuild
 | 
				
			||||||
 | 
					  - mongodb-memory-server
 | 
				
			||||||
 | 
					  - puppeteer
 | 
				
			||||||
							
								
								
									
										47
									
								
								readme.md
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								readme.md
									
									
									
									
									
								
							@@ -184,6 +184,49 @@ Example:
 | 
				
			|||||||
npx tsbuild --skiplibcheck --disallowimplicitany
 | 
					npx tsbuild --skiplibcheck --disallowimplicitany
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Configuration with tsconfig.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`@git.zone/tsbuild` fully supports `tsconfig.json` for compiler configuration. All compiler options from your `tsconfig.json` will be respected and merged with tsbuild's defaults.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Option Priority (Merge Order)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When multiple configuration sources are present, they are merged in the following order (later sources override earlier ones):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. **Default compiler options** - Base defaults for all options
 | 
				
			||||||
 | 
					2. **tsconfig.json** - All compiler options from your project's `tsconfig.json` (if present)
 | 
				
			||||||
 | 
					3. **Protected defaults** - Critical options for build integrity (see below)
 | 
				
			||||||
 | 
					4. **Programmatic options** - Options passed to API functions
 | 
				
			||||||
 | 
					5. **CLI flags** - Command-line arguments (highest priority)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Protected Compiler Options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To ensure build integrity and correct functionality, the following options are protected and cannot be overridden by `tsconfig.json` alone (but can be overridden programmatically or via CLI):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `outDir: 'dist_ts/'` - Required for path transformation logic
 | 
				
			||||||
 | 
					- `noEmitOnError: true` - Prevents broken builds from being emitted
 | 
				
			||||||
 | 
					- `declaration: true` - Ensures .d.ts files for library consumers
 | 
				
			||||||
 | 
					- `emitDecoratorMetadata: true` - Required for dependency injection frameworks
 | 
				
			||||||
 | 
					- `inlineSourceMap: true` - Provides consistent debugging experience
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Working Without tsconfig.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`@git.zone/tsbuild` works perfectly fine without a `tsconfig.json` file. If no `tsconfig.json` is found, it will gracefully fall back to sensible defaults without errors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example `tsconfig.json`:
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "experimentalDecorators": true,
 | 
				
			||||||
 | 
					    "useDefineForClassFields": false,
 | 
				
			||||||
 | 
					    "target": "ES2022",
 | 
				
			||||||
 | 
					    "module": "NodeNext",
 | 
				
			||||||
 | 
					    "moduleResolution": "NodeNext",
 | 
				
			||||||
 | 
					    "esModuleInterop": true,
 | 
				
			||||||
 | 
					    "verbatimModuleSyntax": true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Default Compiler Options
 | 
					## Default Compiler Options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
By default, `@git.zone/tsbuild` uses the following compiler options:
 | 
					By default, `@git.zone/tsbuild` uses the following compiler options:
 | 
				
			||||||
@@ -200,7 +243,7 @@ By default, `@git.zone/tsbuild` uses the following compiler options:
 | 
				
			|||||||
  target: ScriptTarget.ESNext,
 | 
					  target: ScriptTarget.ESNext,
 | 
				
			||||||
  moduleResolution: ModuleResolutionKind.NodeNext,
 | 
					  moduleResolution: ModuleResolutionKind.NodeNext,
 | 
				
			||||||
  lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'],
 | 
					  lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'],
 | 
				
			||||||
  noImplicitAny: false, // Now allowing implicit any by default
 | 
					  noImplicitAny: false,
 | 
				
			||||||
  esModuleInterop: true,
 | 
					  esModuleInterop: true,
 | 
				
			||||||
  useDefineForClassFields: false,
 | 
					  useDefineForClassFields: false,
 | 
				
			||||||
  verbatimModuleSyntax: true,
 | 
					  verbatimModuleSyntax: true,
 | 
				
			||||||
@@ -208,7 +251,7 @@ By default, `@git.zone/tsbuild` uses the following compiler options:
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
These options can be overridden by providing a custom `CompilerOptions` object.
 | 
					These defaults are merged with your `tsconfig.json` options (if present), programmatic options, and CLI flags according to the priority order described above.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Path Resolution
 | 
					## Path Resolution
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import { tap, expect, expectAsync } from '@push.rocks/tapbundle';
 | 
					import { tap, expect } from '@git.zone/tstest/tapbundle';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import * as tsbuild from '../ts/index.js';
 | 
					import * as tsbuild from '../ts/index.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,6 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
export const commitinfo = {
 | 
					export const commitinfo = {
 | 
				
			||||||
  name: '@git.zone/tsbuild',
 | 
					  name: '@git.zone/tsbuild',
 | 
				
			||||||
  version: '2.5.2',
 | 
					  version: '2.7.0',
 | 
				
			||||||
  description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.'
 | 
					  description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,6 +41,7 @@ export class TsBuild {
 | 
				
			|||||||
  private fileNames: string[] = [];
 | 
					  private fileNames: string[] = [];
 | 
				
			||||||
  private options: plugins.typescript.CompilerOptions;
 | 
					  private options: plugins.typescript.CompilerOptions;
 | 
				
			||||||
  private argvArg?: any;
 | 
					  private argvArg?: any;
 | 
				
			||||||
 | 
					  private taskInfo?: any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Create a new TsBuild instance
 | 
					   * Create a new TsBuild instance
 | 
				
			||||||
@@ -48,10 +49,12 @@ export class TsBuild {
 | 
				
			|||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    fileNames: string[] = [], 
 | 
					    fileNames: string[] = [], 
 | 
				
			||||||
    customOptions: CompilerOptions = {}, 
 | 
					    customOptions: CompilerOptions = {}, 
 | 
				
			||||||
    argvArg?: any
 | 
					    argvArg?: any,
 | 
				
			||||||
 | 
					    taskInfo?: any
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    this.fileNames = fileNames;
 | 
					    this.fileNames = fileNames;
 | 
				
			||||||
    this.argvArg = argvArg;
 | 
					    this.argvArg = argvArg;
 | 
				
			||||||
 | 
					    this.taskInfo = taskInfo;
 | 
				
			||||||
    this.options = this.mergeCompilerOptions(customOptions, argvArg);
 | 
					    this.options = this.mergeCompilerOptions(customOptions, argvArg);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -59,41 +62,35 @@ export class TsBuild {
 | 
				
			|||||||
   * Helper function to read and process tsconfig.json
 | 
					   * Helper function to read and process tsconfig.json
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  private getTsConfigOptions(): CompilerOptions {
 | 
					  private getTsConfigOptions(): CompilerOptions {
 | 
				
			||||||
    const tsconfig = plugins.smartfile.fs.toObjectSync(plugins.path.join(paths.cwd, 'tsconfig.json'));
 | 
					    let tsconfig: any;
 | 
				
			||||||
    const returnObject: CompilerOptions = {};
 | 
					
 | 
				
			||||||
 | 
					    // 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) {
 | 
					    if (!tsconfig || !tsconfig.compilerOptions) {
 | 
				
			||||||
      return returnObject;
 | 
					      return {};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Process baseUrl
 | 
					    // Start by copying ALL compiler options from tsconfig.json
 | 
				
			||||||
    if (tsconfig.compilerOptions.baseUrl) {
 | 
					    const returnObject: CompilerOptions = { ...tsconfig.compilerOptions };
 | 
				
			||||||
      returnObject.baseUrl = tsconfig.compilerOptions.baseUrl;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Process paths
 | 
					    // Apply special transformations for string-to-enum conversions
 | 
				
			||||||
    if (tsconfig.compilerOptions.paths) {
 | 
					 | 
				
			||||||
      returnObject.paths = { ...tsconfig.compilerOptions.paths };
 | 
					 | 
				
			||||||
      for (const path of Object.keys(returnObject.paths)) {
 | 
					 | 
				
			||||||
        if (Array.isArray(returnObject.paths[path]) && returnObject.paths[path].length > 0) {
 | 
					 | 
				
			||||||
          returnObject.paths[path][0] = returnObject.paths[path][0].replace('./ts_', './dist_ts_');
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Process target
 | 
					    // Process target (convert string to enum)
 | 
				
			||||||
    if (tsconfig.compilerOptions.target) {
 | 
					    if (tsconfig.compilerOptions.target && typeof tsconfig.compilerOptions.target === 'string') {
 | 
				
			||||||
      if (typeof tsconfig.compilerOptions.target === 'string') {
 | 
					 | 
				
			||||||
      const targetKey = tsconfig.compilerOptions.target.toUpperCase();
 | 
					      const targetKey = tsconfig.compilerOptions.target.toUpperCase();
 | 
				
			||||||
      if (targetKey in plugins.typescript.ScriptTarget) {
 | 
					      if (targetKey in plugins.typescript.ScriptTarget) {
 | 
				
			||||||
        returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget];
 | 
					        returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget];
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Process module
 | 
					    // Process module (convert string to enum)
 | 
				
			||||||
    if (tsconfig.compilerOptions.module) {
 | 
					    if (tsconfig.compilerOptions.module && typeof tsconfig.compilerOptions.module === 'string') {
 | 
				
			||||||
      if (typeof tsconfig.compilerOptions.module === 'string') {
 | 
					 | 
				
			||||||
      const moduleKey = tsconfig.compilerOptions.module.toUpperCase();
 | 
					      const moduleKey = tsconfig.compilerOptions.module.toUpperCase();
 | 
				
			||||||
      if (moduleKey in plugins.typescript.ModuleKind) {
 | 
					      if (moduleKey in plugins.typescript.ModuleKind) {
 | 
				
			||||||
        returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind];
 | 
					        returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind];
 | 
				
			||||||
@@ -101,11 +98,9 @@ export class TsBuild {
 | 
				
			|||||||
        returnObject.module = plugins.typescript.ModuleKind.NodeNext;
 | 
					        returnObject.module = plugins.typescript.ModuleKind.NodeNext;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Process moduleResolution
 | 
					    // Process moduleResolution (convert string to enum)
 | 
				
			||||||
    if (tsconfig.compilerOptions.moduleResolution) {
 | 
					    if (tsconfig.compilerOptions.moduleResolution && typeof tsconfig.compilerOptions.moduleResolution === 'string') {
 | 
				
			||||||
      if (typeof tsconfig.compilerOptions.moduleResolution === 'string') {
 | 
					 | 
				
			||||||
      const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase();
 | 
					      const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase();
 | 
				
			||||||
      if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) {
 | 
					      if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) {
 | 
				
			||||||
        returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[
 | 
					        returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[
 | 
				
			||||||
@@ -115,23 +110,34 @@ export class TsBuild {
 | 
				
			|||||||
        returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.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)) {
 | 
				
			||||||
 | 
					        if (Array.isArray(returnObject.paths[path]) && returnObject.paths[path].length > 0) {
 | 
				
			||||||
 | 
					          returnObject.paths[path][0] = returnObject.paths[path][0].replace('./ts_', './dist_ts_');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // 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;
 | 
					    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
 | 
					   * Process command line arguments and return applicable compiler options
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
@@ -159,6 +165,13 @@ export class TsBuild {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Merges compilerOptions with the default compiler options
 | 
					   * 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(
 | 
					  public mergeCompilerOptions(
 | 
				
			||||||
    customTsOptions: CompilerOptions = {},
 | 
					    customTsOptions: CompilerOptions = {},
 | 
				
			||||||
@@ -166,10 +179,11 @@ export class TsBuild {
 | 
				
			|||||||
  ): CompilerOptions {
 | 
					  ): CompilerOptions {
 | 
				
			||||||
    // create merged options
 | 
					    // create merged options
 | 
				
			||||||
    const mergedOptions: CompilerOptions = {
 | 
					    const mergedOptions: CompilerOptions = {
 | 
				
			||||||
      ...compilerOptionsDefault,
 | 
					      ...compilerOptionsDefault,           // 1. All defaults
 | 
				
			||||||
      ...customTsOptions,
 | 
					      ...this.getTsConfigOptions(),        // 2. User's tsconfig.json (all options)
 | 
				
			||||||
      ...this.getCommandLineOptions(argvArg),
 | 
					      ...this.getCriticalDefaults(),       // 3. Protected overrides
 | 
				
			||||||
      ...this.getTsConfigOptions(),
 | 
					      ...customTsOptions,                  // 4. Programmatic options
 | 
				
			||||||
 | 
					      ...this.getCommandLineOptions(argvArg), // 5. CLI flags (highest priority)
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return mergedOptions;
 | 
					    return mergedOptions;
 | 
				
			||||||
@@ -277,14 +291,6 @@ export class TsBuild {
 | 
				
			|||||||
    console.log('\n' + '='.repeat(80) + '\n');
 | 
					    console.log('\n' + '='.repeat(80) + '\n');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * Helper function to handle and log TypeScript diagnostics (legacy method)
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  private handleDiagnostics(diagnostics: readonly plugins.typescript.Diagnostic[]): boolean {
 | 
					 | 
				
			||||||
    const errorSummary = this.processDiagnostics(diagnostics);
 | 
					 | 
				
			||||||
    this.displayErrorSummary(errorSummary);
 | 
					 | 
				
			||||||
    return errorSummary.totalErrors > 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Creates a TypeScript program from file names and options
 | 
					   * Creates a TypeScript program from file names and options
 | 
				
			||||||
@@ -314,13 +320,30 @@ export class TsBuild {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  public async compileWithErrorTracking(): Promise<{ emittedFiles: any[], errorSummary: IErrorSummary }> {
 | 
					  public async compileWithErrorTracking(): Promise<{ emittedFiles: any[], errorSummary: IErrorSummary }> {
 | 
				
			||||||
    if (this.options.skipLibCheck) {
 | 
					    if (this.options.skipLibCheck) {
 | 
				
			||||||
 | 
					      if (this.argvArg?.confirmskiplibcheck) {
 | 
				
			||||||
        console.log('\n⚠️  WARNING ⚠️');
 | 
					        console.log('\n⚠️  WARNING ⚠️');
 | 
				
			||||||
        console.log('You are skipping libcheck... Is that really wanted?');
 | 
					        console.log('You are skipping libcheck... Is that really wanted?');
 | 
				
			||||||
        console.log('Continuing in 5 seconds...\n');
 | 
					        console.log('Continuing in 5 seconds...\n');
 | 
				
			||||||
        await plugins.smartdelay.delayFor(5000);
 | 
					        await plugins.smartdelay.delayFor(5000);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        // No delay by default; keep a short note unless in quiet/json modes
 | 
				
			||||||
 | 
					        if (!this.argvArg?.quiet && !this.argvArg?.json) {
 | 
				
			||||||
 | 
					          console.log('⚠️  skipLibCheck enabled; use --confirmskiplibcheck to pause with warning.');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    // Enhanced logging with task info
 | 
				
			||||||
 | 
					    const startTime = Date.now();
 | 
				
			||||||
 | 
					    if (this.taskInfo) {
 | 
				
			||||||
 | 
					      const { taskNumber, totalTasks, sourcePattern, destDir, fileCount } = this.taskInfo;
 | 
				
			||||||
 | 
					      const relativeDestDir = destDir.replace(process.cwd(), '').replace(/^\//, '');
 | 
				
			||||||
 | 
					      console.log(`\n🔨 [${taskNumber}/${totalTasks}] Compiling ${fileCount} file${fileCount !== 1 ? 's' : ''} from ${sourcePattern}`);
 | 
				
			||||||
 | 
					      console.log(`   📁 Output: ${relativeDestDir}`);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
      console.log(`🔨 Compiling ${this.fileNames.length} files...`);
 | 
					      console.log(`🔨 Compiling ${this.fileNames.length} files...`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    const done = plugins.smartpromise.defer<{ emittedFiles: any[], errorSummary: IErrorSummary }>();
 | 
					    const done = plugins.smartpromise.defer<{ emittedFiles: any[], errorSummary: IErrorSummary }>();
 | 
				
			||||||
    const program = this.createProgram();
 | 
					    const program = this.createProgram();
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@@ -352,7 +375,15 @@ export class TsBuild {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const exitCode = emitResult.emitSkipped ? 1 : 0;
 | 
					    const exitCode = emitResult.emitSkipped ? 1 : 0;
 | 
				
			||||||
    if (exitCode === 0) {
 | 
					    if (exitCode === 0) {
 | 
				
			||||||
      console.log('\n✅ TypeScript emit succeeded!');
 | 
					      const endTime = Date.now();
 | 
				
			||||||
 | 
					      const duration = endTime - startTime;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      if (this.taskInfo) {
 | 
				
			||||||
 | 
					        const { taskNumber, totalTasks } = this.taskInfo;
 | 
				
			||||||
 | 
					        console.log(`✅ [${taskNumber}/${totalTasks}] Task completed in ${duration}ms`);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        console.log(`✅ TypeScript emit succeeded! (${duration}ms)`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      // Get count of emitted files by type
 | 
					      // Get count of emitted files by type
 | 
				
			||||||
      const jsFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.js')).length || 0;
 | 
					      const jsFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.js')).length || 0;
 | 
				
			||||||
@@ -361,7 +392,7 @@ export class TsBuild {
 | 
				
			|||||||
      
 | 
					      
 | 
				
			||||||
      // If we have emitted files, show a summary
 | 
					      // If we have emitted files, show a summary
 | 
				
			||||||
      if (emitResult.emittedFiles && emitResult.emittedFiles.length > 0) {
 | 
					      if (emitResult.emittedFiles && emitResult.emittedFiles.length > 0) {
 | 
				
			||||||
        console.log(`   Generated ${emitResult.emittedFiles.length} files: ${jsFiles} .js, ${dtsFiles} .d.ts, ${mapFiles} source maps`);
 | 
					        console.log(`   📄 Generated ${emitResult.emittedFiles.length} files: ${jsFiles} .js, ${dtsFiles} .d.ts, ${mapFiles} source maps`);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      done.resolve({ emittedFiles: emitResult.emittedFiles || [], errorSummary: combinedErrorSummary });
 | 
					      done.resolve({ emittedFiles: emitResult.emittedFiles || [], errorSummary: combinedErrorSummary });
 | 
				
			||||||
@@ -369,7 +400,9 @@ export class TsBuild {
 | 
				
			|||||||
      this.displayErrorSummary(combinedErrorSummary);
 | 
					      this.displayErrorSummary(combinedErrorSummary);
 | 
				
			||||||
      console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!');
 | 
					      console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!');
 | 
				
			||||||
      console.error('   No output files have been generated.\n');
 | 
					      console.error('   No output files have been generated.\n');
 | 
				
			||||||
      process.exit(exitCode);
 | 
					      // Do not exit here; return error summary so caller can decide
 | 
				
			||||||
 | 
					      done.resolve({ emittedFiles: [], errorSummary: combinedErrorSummary });
 | 
				
			||||||
 | 
					      return done.promise;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return done.promise;
 | 
					    return done.promise;
 | 
				
			||||||
@@ -380,10 +413,16 @@ export class TsBuild {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  public async compile(): Promise<any[]> {
 | 
					  public async compile(): Promise<any[]> {
 | 
				
			||||||
    if (this.options.skipLibCheck) {
 | 
					    if (this.options.skipLibCheck) {
 | 
				
			||||||
 | 
					      if (this.argvArg?.confirmskiplibcheck) {
 | 
				
			||||||
        console.log('\n⚠️  WARNING ⚠️');
 | 
					        console.log('\n⚠️  WARNING ⚠️');
 | 
				
			||||||
        console.log('You are skipping libcheck... Is that really wanted?');
 | 
					        console.log('You are skipping libcheck... Is that really wanted?');
 | 
				
			||||||
        console.log('Continuing in 5 seconds...\n');
 | 
					        console.log('Continuing in 5 seconds...\n');
 | 
				
			||||||
        await plugins.smartdelay.delayFor(5000);
 | 
					        await plugins.smartdelay.delayFor(5000);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        if (!this.argvArg?.quiet && !this.argvArg?.json) {
 | 
				
			||||||
 | 
					          console.log('⚠️  skipLibCheck enabled; use --confirmskiplibcheck to pause with warning.');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    console.log(`🔨 Compiling ${this.fileNames.length} files...`);
 | 
					    console.log(`🔨 Compiling ${this.fileNames.length} files...`);
 | 
				
			||||||
@@ -392,18 +431,20 @@ export class TsBuild {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    // Check for pre-emit diagnostics first
 | 
					    // Check for pre-emit diagnostics first
 | 
				
			||||||
    const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
					    const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
				
			||||||
    const hasPreEmitErrors = this.handleDiagnostics(preEmitDiagnostics);
 | 
					    const preEmitErrorSummary = this.processDiagnostics(preEmitDiagnostics);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // Only continue to emit phase if no pre-emit errors
 | 
					    // Only continue to emit phase if no pre-emit errors
 | 
				
			||||||
    if (hasPreEmitErrors) {
 | 
					    if (preEmitErrorSummary.totalErrors > 0) {
 | 
				
			||||||
 | 
					      this.displayErrorSummary(preEmitErrorSummary);
 | 
				
			||||||
      console.error('\n❌ TypeScript pre-emit checks failed. Please fix the issues listed above before proceeding.');
 | 
					      console.error('\n❌ TypeScript pre-emit checks failed. Please fix the issues listed above before proceeding.');
 | 
				
			||||||
      console.error('   Type errors must be resolved before the compiler can emit output files.\n');
 | 
					      console.error('   Type errors must be resolved before the compiler can emit output files.\n');
 | 
				
			||||||
      process.exit(1);
 | 
					      // Throw instead of exiting to keep library pure
 | 
				
			||||||
 | 
					      throw new Error('TypeScript pre-emit checks failed.');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // If no pre-emit errors, proceed with emit
 | 
					    // If no pre-emit errors, proceed with emit
 | 
				
			||||||
    const emitResult = program.emit();
 | 
					    const emitResult = program.emit();
 | 
				
			||||||
    const hasEmitErrors = this.handleDiagnostics(emitResult.diagnostics);
 | 
					    const emitErrorSummary = this.processDiagnostics(emitResult.diagnostics);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const exitCode = emitResult.emitSkipped ? 1 : 0;
 | 
					    const exitCode = emitResult.emitSkipped ? 1 : 0;
 | 
				
			||||||
    if (exitCode === 0) {
 | 
					    if (exitCode === 0) {
 | 
				
			||||||
@@ -421,9 +462,11 @@ export class TsBuild {
 | 
				
			|||||||
      
 | 
					      
 | 
				
			||||||
      done.resolve(emitResult.emittedFiles);
 | 
					      done.resolve(emitResult.emittedFiles);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.displayErrorSummary(emitErrorSummary);
 | 
				
			||||||
      console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!');
 | 
					      console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!');
 | 
				
			||||||
      console.error('   No output files have been generated.\n');
 | 
					      console.error('   No output files have been generated.\n');
 | 
				
			||||||
      process.exit(exitCode);
 | 
					      // Throw instead of exiting to keep library pure
 | 
				
			||||||
 | 
					      throw new Error('TypeScript emit failed.');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return done.promise;
 | 
					    return done.promise;
 | 
				
			||||||
@@ -444,18 +487,27 @@ export class TsBuild {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    // Check for pre-emit diagnostics
 | 
					    // Check for pre-emit diagnostics
 | 
				
			||||||
    const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
					    const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
				
			||||||
    const hasPreEmitErrors = this.handleDiagnostics(preEmitDiagnostics);
 | 
					    const preEmitErrorSummary = this.processDiagnostics(preEmitDiagnostics);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // Run the emit phase but with noEmit: true to check for emit errors without producing files
 | 
					    // Run the emit phase but with noEmit: true to check for emit errors without producing files
 | 
				
			||||||
    const emitResult = program.emit(undefined, undefined, undefined, true);
 | 
					    const emitResult = program.emit(undefined, undefined, undefined, true);
 | 
				
			||||||
    const hasEmitErrors = this.handleDiagnostics(emitResult.diagnostics);
 | 
					    const emitErrorSummary = this.processDiagnostics(emitResult.diagnostics);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    const success = !hasPreEmitErrors && !hasEmitErrors && !emitResult.emitSkipped;
 | 
					    // Combine error summaries
 | 
				
			||||||
 | 
					    const combinedErrorSummary: IErrorSummary = {
 | 
				
			||||||
 | 
					      errorsByFile: { ...preEmitErrorSummary.errorsByFile, ...emitErrorSummary.errorsByFile },
 | 
				
			||||||
 | 
					      generalErrors: [...preEmitErrorSummary.generalErrors, ...emitErrorSummary.generalErrors],
 | 
				
			||||||
 | 
					      totalErrors: preEmitErrorSummary.totalErrors + emitErrorSummary.totalErrors,
 | 
				
			||||||
 | 
					      totalFiles: Object.keys({ ...preEmitErrorSummary.errorsByFile, ...emitErrorSummary.errorsByFile }).length
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    const success = combinedErrorSummary.totalErrors === 0 && !emitResult.emitSkipped;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (success) {
 | 
					    if (success) {
 | 
				
			||||||
      console.log('\n✅ TypeScript emit check passed! All files can be emitted successfully.');
 | 
					      console.log('\n✅ TypeScript emit check passed! All files can be emitted successfully.');
 | 
				
			||||||
      console.log(`   ${fileCount} file${fileCount !== 1 ? 's' : ''} ${fileCount !== 1 ? 'are' : 'is'} ready to be compiled.\n`);
 | 
					      console.log(`   ${fileCount} file${fileCount !== 1 ? 's' : ''} ${fileCount !== 1 ? 'are' : 'is'} ready to be compiled.\n`);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.displayErrorSummary(combinedErrorSummary);
 | 
				
			||||||
      console.error('\n❌ TypeScript emit check failed. Please fix the issues listed above.');
 | 
					      console.error('\n❌ TypeScript emit check failed. Please fix the issues listed above.');
 | 
				
			||||||
      console.error('   The compilation cannot proceed until these errors are resolved.\n');
 | 
					      console.error('   The compilation cannot proceed until these errors are resolved.\n');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -478,15 +530,16 @@ export class TsBuild {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    // Check for type errors
 | 
					    // Check for type errors
 | 
				
			||||||
    const diagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
					    const diagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
				
			||||||
    const hasErrors = this.handleDiagnostics(diagnostics);
 | 
					    const errorSummary = this.processDiagnostics(diagnostics);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // Set success flag
 | 
					    // Set success flag
 | 
				
			||||||
    const success = !hasErrors;
 | 
					    const success = errorSummary.totalErrors === 0;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (success) {
 | 
					    if (success) {
 | 
				
			||||||
      console.log('\n✅ TypeScript type check passed! No type errors found.');
 | 
					      console.log('\n✅ TypeScript type check passed! No type errors found.');
 | 
				
			||||||
      console.log(`   All ${fileCount} file${fileCount !== 1 ? 's' : ''} passed type checking successfully.\n`);
 | 
					      console.log(`   All ${fileCount} file${fileCount !== 1 ? 's' : ''} passed type checking successfully.\n`);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.displayErrorSummary(errorSummary);
 | 
				
			||||||
      console.error('\n❌ TypeScript type check failed. Please fix the type errors listed above.');
 | 
					      console.error('\n❌ TypeScript type check failed. Please fix the type errors listed above.');
 | 
				
			||||||
      console.error('   The type checker found issues that need to be resolved.\n');
 | 
					      console.error('   The type checker found issues that need to be resolved.\n');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ export const runCli = async () => {
 | 
				
			|||||||
   * the standard task compiles anything in ts/ directory to dist directory
 | 
					   * the standard task compiles anything in ts/ directory to dist directory
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  tsbuildCli.standardCommand().subscribe(async (argvArg) => {
 | 
					  tsbuildCli.standardCommand().subscribe(async (argvArg) => {
 | 
				
			||||||
    tsbuild.compileGlobStringObject(
 | 
					    await tsbuild.compileGlobStringObject(
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        './ts/**/*.ts': './dist_ts',
 | 
					        './ts/**/*.ts': './dist_ts',
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@@ -17,6 +17,10 @@ export const runCli = async () => {
 | 
				
			|||||||
      process.cwd(),
 | 
					      process.cwd(),
 | 
				
			||||||
      argvArg
 | 
					      argvArg
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    const summary = (argvArg as any)?.__tsbuildFinalErrorSummary;
 | 
				
			||||||
 | 
					    if (summary && summary.totalErrors > 0) {
 | 
				
			||||||
 | 
					      process.exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@@ -30,6 +34,10 @@ export const runCli = async () => {
 | 
				
			|||||||
      compilationCommandObject[`./${directory}/**/*.ts`] = `./dist_${directory}`;
 | 
					      compilationCommandObject[`./${directory}/**/*.ts`] = `./dist_${directory}`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
 | 
					    await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
 | 
				
			||||||
 | 
					    const summary = (argvArg as any)?.__tsbuildFinalErrorSummary;
 | 
				
			||||||
 | 
					    if (summary && summary.totalErrors > 0) {
 | 
				
			||||||
 | 
					      process.exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@@ -182,6 +190,10 @@ export const runCli = async () => {
 | 
				
			|||||||
      compilationCommandObject[`./${tsFolder}/**/*.ts`] = `./dist_${tsFolder}`;
 | 
					      compilationCommandObject[`./${tsFolder}/**/*.ts`] = `./dist_${tsFolder}`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
 | 
					    await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
 | 
				
			||||||
 | 
					    const summary = (argvArg as any)?.__tsbuildFinalErrorSummary;
 | 
				
			||||||
 | 
					    if (summary && summary.totalErrors > 0) {
 | 
				
			||||||
 | 
					      process.exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,16 +6,28 @@ export type { CompilerOptions, ScriptTarget, ModuleKind };
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export * from './tsbuild.classes.tsbuild.js';
 | 
					export * from './tsbuild.classes.tsbuild.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Interface for task information
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface ITaskInfo {
 | 
				
			||||||
 | 
					  taskNumber: number;
 | 
				
			||||||
 | 
					  totalTasks: number;
 | 
				
			||||||
 | 
					  sourcePattern: string;
 | 
				
			||||||
 | 
					  destDir: string;
 | 
				
			||||||
 | 
					  fileCount: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * compile an array of absolute file paths with error tracking
 | 
					 * compile an array of absolute file paths with error tracking
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export let compileFileArrayWithErrorTracking = async (
 | 
					export let compileFileArrayWithErrorTracking = async (
 | 
				
			||||||
  fileStringArrayArg: string[],
 | 
					  fileStringArrayArg: string[],
 | 
				
			||||||
  compilerOptionsArg: CompilerOptions = {},
 | 
					  compilerOptionsArg: CompilerOptions = {},
 | 
				
			||||||
  argvArg?: any
 | 
					  argvArg?: any,
 | 
				
			||||||
 | 
					  taskInfo?: ITaskInfo
 | 
				
			||||||
): Promise<{ emittedFiles: any[], errorSummary: import('./tsbuild.classes.tsbuild.js').IErrorSummary }> => {
 | 
					): Promise<{ emittedFiles: any[], errorSummary: import('./tsbuild.classes.tsbuild.js').IErrorSummary }> => {
 | 
				
			||||||
  const { TsBuild } = await import('./tsbuild.classes.tsbuild.js');
 | 
					  const { TsBuild } = await import('./tsbuild.classes.tsbuild.js');
 | 
				
			||||||
  const tsBuild = new TsBuild(fileStringArrayArg, compilerOptionsArg, argvArg);
 | 
					  const tsBuild = new TsBuild(fileStringArrayArg, compilerOptionsArg, argvArg, taskInfo);
 | 
				
			||||||
  return tsBuild.compileWithErrorTracking();
 | 
					  return tsBuild.compileWithErrorTracking();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -115,12 +127,19 @@ export let compileGlobStringObject = async (
 | 
				
			|||||||
  let compiledFiles: any[] = [];
 | 
					  let compiledFiles: any[] = [];
 | 
				
			||||||
  const errorSummaries: import('./tsbuild.classes.tsbuild.js').IErrorSummary[] = [];
 | 
					  const errorSummaries: import('./tsbuild.classes.tsbuild.js').IErrorSummary[] = [];
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  // Log the compilation tasks in a nice format
 | 
					  const totalTasks = Object.keys(globStringObjectArg).length;
 | 
				
			||||||
  console.log('\n👷 TypeScript Compilation Tasks:');
 | 
					  let currentTask = 0;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Log the compilation tasks in a nice format (skip for --quiet or --json)
 | 
				
			||||||
 | 
					  const isQuiet = argvArg?.quiet === true;
 | 
				
			||||||
 | 
					  const isJson = argvArg?.json === true;
 | 
				
			||||||
 | 
					  if (!isQuiet && !isJson) {
 | 
				
			||||||
 | 
					    console.log(`\n👷 TypeScript Compilation Tasks (${totalTasks} task${totalTasks !== 1 ? 's' : ''}):`);
 | 
				
			||||||
    Object.entries(globStringObjectArg).forEach(([source, dest]) => {
 | 
					    Object.entries(globStringObjectArg).forEach(([source, dest]) => {
 | 
				
			||||||
      console.log(`  📂 ${source} → ${dest}`);
 | 
					      console.log(`  📂 ${source} → ${dest}`);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    console.log('');
 | 
					    console.log('');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  for (const keyArg in globStringObjectArg) {
 | 
					  for (const keyArg in globStringObjectArg) {
 | 
				
			||||||
    // Type safety check for key
 | 
					    // Type safety check for key
 | 
				
			||||||
@@ -153,7 +172,16 @@ export let compileGlobStringObject = async (
 | 
				
			|||||||
      };
 | 
					      };
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      // Compile with error tracking
 | 
					      // Compile with error tracking
 | 
				
			||||||
      const result = await compileFileArrayWithErrorTracking(absoluteFilePathArray, updatedTsOptions, argvArg);
 | 
					      currentTask++;
 | 
				
			||||||
 | 
					      const taskInfo = {
 | 
				
			||||||
 | 
					        taskNumber: currentTask,
 | 
				
			||||||
 | 
					        totalTasks,
 | 
				
			||||||
 | 
					        sourcePattern: keyArg,
 | 
				
			||||||
 | 
					        destDir: globStringObjectArg[keyArg],
 | 
				
			||||||
 | 
					        fileCount: absoluteFilePathArray.length
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      const result = await compileFileArrayWithErrorTracking(absoluteFilePathArray, updatedTsOptions, argvArg, taskInfo);
 | 
				
			||||||
      compiledFiles = compiledFiles.concat(result.emittedFiles);
 | 
					      compiledFiles = compiledFiles.concat(result.emittedFiles);
 | 
				
			||||||
      errorSummaries.push(result.errorSummary);
 | 
					      errorSummaries.push(result.errorSummary);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -161,7 +189,35 @@ export let compileGlobStringObject = async (
 | 
				
			|||||||
  
 | 
					  
 | 
				
			||||||
  // Display final error summary after all compilation tasks
 | 
					  // Display final error summary after all compilation tasks
 | 
				
			||||||
  const finalErrorSummary = mergeErrorSummaries(errorSummaries);
 | 
					  const finalErrorSummary = mergeErrorSummaries(errorSummaries);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Output summary based on mode
 | 
				
			||||||
 | 
					  if (isJson) {
 | 
				
			||||||
 | 
					    const result = {
 | 
				
			||||||
 | 
					      success: finalErrorSummary.totalErrors === 0,
 | 
				
			||||||
 | 
					      totals: {
 | 
				
			||||||
 | 
					        errors: finalErrorSummary.totalErrors,
 | 
				
			||||||
 | 
					        filesWithErrors: finalErrorSummary.totalFiles,
 | 
				
			||||||
 | 
					        tasks: totalTasks,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      errorsByFile: Object.fromEntries(
 | 
				
			||||||
 | 
					        Object.entries(finalErrorSummary.errorsByFile).map(([file, diags]) => [
 | 
				
			||||||
 | 
					          file,
 | 
				
			||||||
 | 
					          diags.map(d => ({
 | 
				
			||||||
 | 
					            code: d.code,
 | 
				
			||||||
 | 
					            message: plugins.typescript.flattenDiagnosticMessageText(d.messageText as any, '\n'),
 | 
				
			||||||
 | 
					          }))
 | 
				
			||||||
 | 
					        ])
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    console.log(JSON.stringify(result));
 | 
				
			||||||
 | 
					  } else if (!isQuiet) {
 | 
				
			||||||
    displayFinalErrorSummary(finalErrorSummary);
 | 
					    displayFinalErrorSummary(finalErrorSummary);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Attach summary to argvArg so CLI can decide exit behavior
 | 
				
			||||||
 | 
					  if (argvArg && typeof argvArg === 'object') {
 | 
				
			||||||
 | 
					    (argvArg as any).__tsbuildFinalErrorSummary = finalErrorSummary;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return compiledFiles;
 | 
					  return compiledFiles;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
		Reference in New Issue
	
	Block a user