Compare commits
	
		
			40 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c6ab493efc | |||
| 82ae8a0e4a | |||
| 787becc4d3 | |||
| 746ca8767a | |||
| 55c1a2953a | |||
| 8e9fcb8135 | |||
| 18573c777d | |||
| fa654b83e3 | |||
| aa3c83cd95 | |||
| 20ed41df42 | |||
| 7162476f7f | |||
| 1b012628eb | |||
| 4081086621 | |||
| b9cf09ccba | |||
| 8463fbc78a | |||
| 0164eb51a1 | |||
| a305dd89dd | |||
| fa6b053ee0 | |||
| adfba21c67 | |||
| 050e41cdf9 | |||
| f220a11caa | |||
| 0909fa306a | |||
| 88c0601c03 | |||
| 9645f27942 | |||
| b73aa4f21f | |||
| d9d6878a9f | |||
| 30506da84c | |||
| 52b4d8f944 | |||
| 57d2726f6b | |||
| 960fc5f213 | |||
| 6d68f35a9a | |||
| 0378b9feca | |||
| 5ecf4b7125 | |||
| 2aa6348cdd | |||
| 9f42670865 | |||
| 6cc9f41bd2 | |||
| 5d32ac85e0 | |||
| 4f2ac6922a | |||
| 31834e0b3e | |||
| c6c94866bb | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -18,3 +18,4 @@ dist/
 | 
			
		||||
dist_*/
 | 
			
		||||
 | 
			
		||||
# custom
 | 
			
		||||
.claude
 | 
			
		||||
							
								
								
									
										148
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								changelog.md
									
									
									
									
									
								
							@@ -1,5 +1,153 @@
 | 
			
		||||
# 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)
 | 
			
		||||
Improve diagnostic error handling and summary reporting for TypeScript compilation by refactoring diagnostic processing and adding pre-emit error checks.
 | 
			
		||||
 | 
			
		||||
- Introduce a dedicated processDiagnostics function that categorizes errors by file and computes error totals.
 | 
			
		||||
- Refactor displayErrorSummary to provide clearer, color-coded output of error details.
 | 
			
		||||
- Add pre-emit error checking in compileWithErrorTracking to prevent emission when errors exist.
 | 
			
		||||
- Consolidate error summary merging in compileFileArrayWithErrorTracking for improved reporting.
 | 
			
		||||
 | 
			
		||||
## 2025-05-15 - 2.5.1 - fix(commitinfo)
 | 
			
		||||
Update commit information and metadata to synchronize release data
 | 
			
		||||
 | 
			
		||||
- Regenerated the commitinfo file with current version details
 | 
			
		||||
- Maintained existing functionality with no functional code changes
 | 
			
		||||
 | 
			
		||||
## 2025-05-15 - 2.5.0 - feat(cli)
 | 
			
		||||
Enhance type checking in CLI by adding default file pattern handling
 | 
			
		||||
 | 
			
		||||
- When no TypeScript file or glob pattern is provided, the CLI now performs a default type checking sequence.
 | 
			
		||||
- First checks 'ts/**/*' files with standard options, then checks 'test/**/*' files with skiplibcheck enabled.
 | 
			
		||||
- Improved logging to indicate file discovery and check results, ensuring clear feedback for users.
 | 
			
		||||
 | 
			
		||||
## 2025-05-15 - 2.4.1 - fix(cli)
 | 
			
		||||
Improve TS folder compilation order display in CLI
 | 
			
		||||
 | 
			
		||||
- Refactor folder compilation output to use a bordered, tabular format with order numbering
 | 
			
		||||
- Enhance readability of TS folder compilation plan in the CLI output
 | 
			
		||||
 | 
			
		||||
## 2025-05-15 - 2.4.0 - feat(cli)
 | 
			
		||||
Add new 'check' command for type checking and update compiler options handling
 | 
			
		||||
 | 
			
		||||
- Introduced a new 'check' command to verify TypeScript files without emitting output
 | 
			
		||||
- Updated CLI error messages and logging for better clarity
 | 
			
		||||
- Replaced '--allowimplicitany' flag with '--disallowimplicitany' to reflect new default behavior
 | 
			
		||||
- Modified compiler options default settings (noImplicitAny now set to false) for more flexible type handling
 | 
			
		||||
- Refined diagnostic output in tsbuild class for improved error reporting
 | 
			
		||||
- Updated .gitignore to exclude the .claude file
 | 
			
		||||
- Enhanced documentation in readme and implementation plan files
 | 
			
		||||
 | 
			
		||||
## 2025-03-20 - 2.3.2 - fix(compileGlobStringObject)
 | 
			
		||||
Fix duplicate file outputs in glob pattern processing
 | 
			
		||||
 | 
			
		||||
- Removed duplicate concatenation of compiled files in compileGlobStringObject
 | 
			
		||||
- Ensured unique file paths are used during TypeScript compilation
 | 
			
		||||
 | 
			
		||||
## 2025-03-20 - 2.3.1 - fix(compiler)
 | 
			
		||||
Refactor compiler implementation with consolidated TsBuild class and improved diagnostics handling
 | 
			
		||||
 | 
			
		||||
- Removed legacy tsbuild.classes.compiler.ts and introduced tsbuild.classes.tsbuild.ts
 | 
			
		||||
- Unified compiler options merging, reading tsconfig.json, and diagnostics reporting within the TsBuild class
 | 
			
		||||
- Updated exports to reference the new compiler class implementation for backward compatibility
 | 
			
		||||
 | 
			
		||||
## 2025-03-20 - 2.3.0 - feat(cli)
 | 
			
		||||
Add emitcheck command to validate TS file emission without generating output
 | 
			
		||||
 | 
			
		||||
- Implemented the emitcheck CLI command to allow checking if TypeScript files can be emitted without producing files
 | 
			
		||||
- Updated tsbuild.classes.compiler.ts to include the emitCheck function
 | 
			
		||||
- Enhanced documentation in readme.md to describe the new emitcheck usage with examples
 | 
			
		||||
 | 
			
		||||
## 2025-03-17 - 2.2.7 - fix(compiler)
 | 
			
		||||
Improve diagnostic checking and error handling in the TypeScript compiler integration
 | 
			
		||||
 | 
			
		||||
- Added pre-emit diagnostics check to log errors before emitting
 | 
			
		||||
- Process exits on encountering pre-emit errors to ensure build correctness
 | 
			
		||||
- Enhanced logging for emit diagnostics to aid debugging
 | 
			
		||||
 | 
			
		||||
## 2025-03-04 - 2.2.6 - fix(package)
 | 
			
		||||
Fix repository URL in package.json
 | 
			
		||||
 | 
			
		||||
- Updated repository URL in package.json to point to the correct Git repository.
 | 
			
		||||
 | 
			
		||||
## 2025-03-04 - 2.2.5 - fix(package.json)
 | 
			
		||||
Update repository URLs in package metadata.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								package.json
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@git.zone/tsbuild",
 | 
			
		||||
  "version": "2.2.5",
 | 
			
		||||
  "version": "2.7.0",
 | 
			
		||||
  "private": false,
 | 
			
		||||
  "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",
 | 
			
		||||
@@ -10,13 +10,13 @@
 | 
			
		||||
    "tsbuild": "./cli.js"
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "test": "tsrun test/test.ts",
 | 
			
		||||
    "build": "node cli.ts.js --web --allowimplicitany",
 | 
			
		||||
    "test": "tstest test/test.ts --verbose",
 | 
			
		||||
    "build": "node cli.ts.js --web",
 | 
			
		||||
    "buildDocs": "tsdoc"
 | 
			
		||||
  },
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "git+ssh://git@gitlab.com/pushrocks/tsn.git"
 | 
			
		||||
    "url": "https://code.foss.global/git.zone/tsbuild.git"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "TypeScript",
 | 
			
		||||
@@ -36,20 +36,20 @@
 | 
			
		||||
  },
 | 
			
		||||
  "homepage": "https://code.foss.global/git.zone/tsbuild#README",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@git.zone/tspublish": "^1.9.1",
 | 
			
		||||
    "@git.zone/tspublish": "^1.10.3",
 | 
			
		||||
    "@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/smartfile": "^11.1.5",
 | 
			
		||||
    "@push.rocks/smartlog": "^3.0.7",
 | 
			
		||||
    "@push.rocks/smartpath": "^5.0.18",
 | 
			
		||||
    "@push.rocks/smartpromise": "^4.2.2",
 | 
			
		||||
    "typescript": "5.7.3"
 | 
			
		||||
    "@push.rocks/smartfile": "^11.2.7",
 | 
			
		||||
    "@push.rocks/smartlog": "^3.1.10",
 | 
			
		||||
    "@push.rocks/smartpath": "^6.0.0",
 | 
			
		||||
    "@push.rocks/smartpromise": "^4.2.3",
 | 
			
		||||
    "typescript": "5.9.3"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@git.zone/tsrun": "^1.2.47",
 | 
			
		||||
    "@push.rocks/tapbundle": "^5.5.6",
 | 
			
		||||
    "@types/node": "^22.12.0"
 | 
			
		||||
    "@git.zone/tsrun": "^1.6.2",
 | 
			
		||||
    "@git.zone/tstest": "^2.7.0",
 | 
			
		||||
    "@types/node": "^22.15.21"
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
    "ts/**/*",
 | 
			
		||||
@@ -65,5 +65,6 @@
 | 
			
		||||
  ],
 | 
			
		||||
  "browserslist": [
 | 
			
		||||
    "last 1 chrome versions"
 | 
			
		||||
  ]
 | 
			
		||||
  ],
 | 
			
		||||
  "packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
							
								
								
									
										101
									
								
								readme.md
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								readme.md
									
									
									
									
									
								
							@@ -121,17 +121,110 @@ compiling in this order:
 | 
			
		||||
[ 'ts_interfaces', 'ts_shared', 'ts_core', 'ts_utils', 'ts_modules' ]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### EmitCheck Command
 | 
			
		||||
 | 
			
		||||
Checks if TypeScript files can be emitted without actually emitting them:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npx tsbuild emitcheck <file_or_glob_pattern> [additional_patterns ...]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This command:
 | 
			
		||||
1. Performs type checking on the specified TypeScript file(s)
 | 
			
		||||
2. Supports both direct file paths and glob patterns
 | 
			
		||||
3. Reports any errors that would prevent successful compilation
 | 
			
		||||
4. Exits with code 0 if all files can be emitted, or 1 if any cannot
 | 
			
		||||
5. Doesn't produce any output files
 | 
			
		||||
 | 
			
		||||
Example usage with specific files:
 | 
			
		||||
```bash
 | 
			
		||||
npx tsbuild emitcheck src/main.ts src/utils.ts
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Example usage with glob patterns:
 | 
			
		||||
```bash
 | 
			
		||||
npx tsbuild emitcheck "src/**/*.ts" "test/**/*.ts"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Check Command
 | 
			
		||||
 | 
			
		||||
Performs type checking on TypeScript files specified by glob patterns without emitting them:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npx tsbuild check <glob_pattern> [additional_patterns ...]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This command:
 | 
			
		||||
1. Efficiently type checks TypeScript files matching the given glob patterns
 | 
			
		||||
2. Supports multiple glob patterns and direct file paths
 | 
			
		||||
3. Reports any type errors found in the matched files
 | 
			
		||||
4. Exits with code 0 if all files pass type checking, or 1 if any have errors
 | 
			
		||||
5. Doesn't produce any output files
 | 
			
		||||
 | 
			
		||||
Example usage:
 | 
			
		||||
```bash
 | 
			
		||||
npx tsbuild check ts/**/*
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Example usage with multiple patterns:
 | 
			
		||||
```bash
 | 
			
		||||
npx tsbuild check "src/**/*.ts" "test/**/*.ts"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Compiler Options
 | 
			
		||||
 | 
			
		||||
Additional flags can be passed to any command to modify the compilation behavior:
 | 
			
		||||
 | 
			
		||||
- `--skiplibcheck`: Skip type checking of declaration files (shows warning)
 | 
			
		||||
- `--allowimplicitany`: Allow variables to be implicitly typed as `any`
 | 
			
		||||
- `--disallowimplicitany`: Disallow variables to be implicitly typed as `any` (implicit any is allowed by default)
 | 
			
		||||
- `--commonjs`: Use CommonJS module format instead of ESNext
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
```bash
 | 
			
		||||
npx tsbuild --skiplibcheck --allowimplicitany
 | 
			
		||||
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
 | 
			
		||||
@@ -150,7 +243,7 @@ By default, `@git.zone/tsbuild` uses the following compiler options:
 | 
			
		||||
  target: ScriptTarget.ESNext,
 | 
			
		||||
  moduleResolution: ModuleResolutionKind.NodeNext,
 | 
			
		||||
  lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'],
 | 
			
		||||
  noImplicitAny: true,
 | 
			
		||||
  noImplicitAny: false,
 | 
			
		||||
  esModuleInterop: true,
 | 
			
		||||
  useDefineForClassFields: false,
 | 
			
		||||
  verbatimModuleSyntax: true,
 | 
			
		||||
@@ -158,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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										45
									
								
								readme.plan.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								readme.plan.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
# Implementation Plan for tsbuild `check` Command
 | 
			
		||||
 | 
			
		||||
## Overview
 | 
			
		||||
Add a new `check` command to tsbuild that allows checking TypeScript files against a glob pattern without emitting them, similar to running the TypeScript compiler with the `--noEmit` flag.
 | 
			
		||||
 | 
			
		||||
## Implementation Steps
 | 
			
		||||
 | 
			
		||||
1. **Reread CLAUDE.md** to ensure we follow project guidelines
 | 
			
		||||
 | 
			
		||||
2. **Extend TsBuild Class**
 | 
			
		||||
   - The existing `TsBuild` class already has a `checkEmit()` method
 | 
			
		||||
   - We can leverage this method for our implementation
 | 
			
		||||
 | 
			
		||||
3. **Implement Check Command in CLI**
 | 
			
		||||
   - Add a new `check` command to `tsbuild.cli.ts`
 | 
			
		||||
   - Command should accept glob patterns as arguments
 | 
			
		||||
   - Process glob patterns to find matching TypeScript files
 | 
			
		||||
   - Use the `TsBuild` class to check the files without emitting
 | 
			
		||||
 | 
			
		||||
4. **Update Exports**
 | 
			
		||||
   - Ensure any new functionality is properly exported
 | 
			
		||||
 | 
			
		||||
5. **Testing**
 | 
			
		||||
   - Test the command with various glob patterns
 | 
			
		||||
   - Verify error reporting works correctly
 | 
			
		||||
 | 
			
		||||
## Differences from Existing `emitcheck` Command
 | 
			
		||||
The `emitcheck` command already exists and checks specific files without emitting. Our new `check` command will:
 | 
			
		||||
- Be designed specifically for checking files against glob patterns
 | 
			
		||||
- Use a simpler, more intuitive command name
 | 
			
		||||
- Potentially add additional benefits (like summary statistics of checked files)
 | 
			
		||||
 | 
			
		||||
## Example Usage
 | 
			
		||||
Once implemented, the command would work like this:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npx tsbuild check ts/**/* 
 | 
			
		||||
npx tsbuild check "src/**/*.ts" "test/**/*.ts"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Expected Output
 | 
			
		||||
The command should:
 | 
			
		||||
- Report any TypeScript errors in the matched files
 | 
			
		||||
- Provide a count of files checked and any errors found
 | 
			
		||||
- Exit with code 0 if successful, or 1 if errors are found
 | 
			
		||||
@@ -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';
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,6 @@
 | 
			
		||||
 */
 | 
			
		||||
export const commitinfo = {
 | 
			
		||||
  name: '@git.zone/tsbuild',
 | 
			
		||||
  version: '2.2.5',
 | 
			
		||||
  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.'
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,128 +0,0 @@
 | 
			
		||||
// import all the stuff we need
 | 
			
		||||
import * as plugins from './plugins.js';
 | 
			
		||||
import * as paths from './paths.js';
 | 
			
		||||
import type { CompilerOptions, ScriptTarget, ModuleKind } from './tsbuild.exports.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * the default typescript compilerOptions
 | 
			
		||||
 */
 | 
			
		||||
export const compilerOptionsDefault: CompilerOptions = {
 | 
			
		||||
  declaration: true,
 | 
			
		||||
  emitDecoratorMetadata: true,
 | 
			
		||||
  experimentalDecorators: true,
 | 
			
		||||
  inlineSourceMap: true,
 | 
			
		||||
  noEmitOnError: true,
 | 
			
		||||
  outDir: 'dist_ts/',
 | 
			
		||||
  module: plugins.typescript.ModuleKind.NodeNext,
 | 
			
		||||
  target: plugins.typescript.ScriptTarget.ESNext,
 | 
			
		||||
  moduleResolution: plugins.typescript.ModuleResolutionKind.NodeNext,
 | 
			
		||||
  lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'],
 | 
			
		||||
  noImplicitAny: true,
 | 
			
		||||
  esModuleInterop: true,
 | 
			
		||||
  useDefineForClassFields: false,
 | 
			
		||||
  verbatimModuleSyntax: true,
 | 
			
		||||
  baseUrl: './',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * merges compilerOptions with the default compiler options
 | 
			
		||||
 */
 | 
			
		||||
export const mergeCompilerOptions = (
 | 
			
		||||
  customTsOptions: CompilerOptions,
 | 
			
		||||
  argvArg?: any
 | 
			
		||||
): CompilerOptions => {
 | 
			
		||||
  // create merged options
 | 
			
		||||
  const mergedOptions: CompilerOptions = {
 | 
			
		||||
    ...compilerOptionsDefault,
 | 
			
		||||
    ...customTsOptions,
 | 
			
		||||
    ...(argvArg && argvArg.skiplibcheck
 | 
			
		||||
      ? {
 | 
			
		||||
          skipLibCheck: true,
 | 
			
		||||
        }
 | 
			
		||||
      : {}),
 | 
			
		||||
    ...(argvArg && argvArg.allowimplicitany
 | 
			
		||||
      ? {
 | 
			
		||||
          noImplicitAny: false,
 | 
			
		||||
        }
 | 
			
		||||
      : {}),
 | 
			
		||||
    ...(argvArg && argvArg.commonjs
 | 
			
		||||
      ? {
 | 
			
		||||
          module: plugins.typescript.ModuleKind.CommonJS,
 | 
			
		||||
          moduleResolution: plugins.typescript.ModuleResolutionKind.NodeJs,
 | 
			
		||||
        }
 | 
			
		||||
      : {}),
 | 
			
		||||
    ...(() => {
 | 
			
		||||
      const returnObject: CompilerOptions = {};
 | 
			
		||||
      console.log(`looking at tsconfig.json at ${paths.cwd}`);
 | 
			
		||||
      const tsconfig = plugins.smartfile.fs.toObjectSync(plugins.path.join(paths.cwd, 'tsconfig.json'));
 | 
			
		||||
      if (tsconfig && tsconfig.compilerOptions && tsconfig.compilerOptions.baseUrl) {
 | 
			
		||||
        console.log('baseUrl found in tsconfig.json');
 | 
			
		||||
        returnObject.baseUrl = tsconfig.compilerOptions.baseUrl;
 | 
			
		||||
      }
 | 
			
		||||
      if (tsconfig && tsconfig.compilerOptions && tsconfig.compilerOptions.paths) {
 | 
			
		||||
        console.log('paths found in tsconfig.json');
 | 
			
		||||
        returnObject.paths = tsconfig.compilerOptions.paths;
 | 
			
		||||
        for (const path of Object.keys(tsconfig.compilerOptions.paths)) {
 | 
			
		||||
          returnObject.paths[path][0] = returnObject.paths[path][0].replace('./ts_', './dist_ts_');
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return returnObject;
 | 
			
		||||
    })(),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  console.log(mergedOptions);
 | 
			
		||||
 | 
			
		||||
  return mergedOptions;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * the internal main compiler function that compiles the files
 | 
			
		||||
 */
 | 
			
		||||
export const compiler = async (
 | 
			
		||||
  fileNames: string[],
 | 
			
		||||
  options: plugins.typescript.CompilerOptions,
 | 
			
		||||
  argvArg?: any
 | 
			
		||||
): Promise<any[]> => {
 | 
			
		||||
  if (options.skipLibCheck) {
 | 
			
		||||
    console.log('? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?');
 | 
			
		||||
    console.log('You are skipping libcheck... Is that really wanted?');
 | 
			
		||||
    console.log('continuing in 5 seconds...');
 | 
			
		||||
    console.log('? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?');
 | 
			
		||||
    await plugins.smartdelay.delayFor(5000);
 | 
			
		||||
  }
 | 
			
		||||
  console.log(`Compiling ${fileNames.length} files...`);
 | 
			
		||||
  const done = plugins.smartpromise.defer<any[]>();
 | 
			
		||||
  const program = plugins.typescript.createProgram(fileNames, options);
 | 
			
		||||
  const emitResult = program.emit();
 | 
			
		||||
 | 
			
		||||
  // implement check only
 | 
			
		||||
  /*let emitResult = program.emit(undefined,(args) => {
 | 
			
		||||
    console.log(args)
 | 
			
		||||
  });*/
 | 
			
		||||
 | 
			
		||||
  const allDiagnostics = plugins.typescript
 | 
			
		||||
    .getPreEmitDiagnostics(program)
 | 
			
		||||
    .concat(emitResult.diagnostics);
 | 
			
		||||
  allDiagnostics.forEach((diagnostic) => {
 | 
			
		||||
    if (diagnostic.file) {
 | 
			
		||||
      const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
 | 
			
		||||
      const message = plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
 | 
			
		||||
      console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
 | 
			
		||||
    } else {
 | 
			
		||||
      console.log(
 | 
			
		||||
        `${plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const exitCode = emitResult.emitSkipped ? 1 : 0;
 | 
			
		||||
  if (exitCode === 0) {
 | 
			
		||||
    console.log('TypeScript emit succeeded!');
 | 
			
		||||
    done.resolve(emitResult.emittedFiles);
 | 
			
		||||
  } else {
 | 
			
		||||
    console.error('TypeScript emit failed. Please investigate!');
 | 
			
		||||
    process.exit(exitCode);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return done.promise;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										596
									
								
								ts/tsbuild.classes.tsbuild.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										596
									
								
								ts/tsbuild.classes.tsbuild.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,596 @@
 | 
			
		||||
// import all the stuff we need
 | 
			
		||||
import * as plugins from './plugins.js';
 | 
			
		||||
import * as paths from './paths.js';
 | 
			
		||||
import type { CompilerOptions, ScriptTarget, ModuleKind } from './tsbuild.exports.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface for error summary data
 | 
			
		||||
 */
 | 
			
		||||
export interface IErrorSummary {
 | 
			
		||||
  errorsByFile: Record<string, plugins.typescript.Diagnostic[]>;
 | 
			
		||||
  generalErrors: plugins.typescript.Diagnostic[];
 | 
			
		||||
  totalErrors: number;
 | 
			
		||||
  totalFiles: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Default compiler options for TypeScript compilation
 | 
			
		||||
 */
 | 
			
		||||
export const compilerOptionsDefault: CompilerOptions = {
 | 
			
		||||
  declaration: true,
 | 
			
		||||
  emitDecoratorMetadata: true,
 | 
			
		||||
  experimentalDecorators: true,
 | 
			
		||||
  inlineSourceMap: true,
 | 
			
		||||
  noEmitOnError: true,
 | 
			
		||||
  outDir: 'dist_ts/',
 | 
			
		||||
  module: plugins.typescript.ModuleKind.NodeNext,
 | 
			
		||||
  target: plugins.typescript.ScriptTarget.ESNext,
 | 
			
		||||
  moduleResolution: plugins.typescript.ModuleResolutionKind.NodeNext,
 | 
			
		||||
  lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'],
 | 
			
		||||
  noImplicitAny: false, // Allow implicit any by default
 | 
			
		||||
  esModuleInterop: true,
 | 
			
		||||
  useDefineForClassFields: false,
 | 
			
		||||
  verbatimModuleSyntax: true,
 | 
			
		||||
  baseUrl: './',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TsBuild class for handling TypeScript compilation
 | 
			
		||||
 */
 | 
			
		||||
export class TsBuild {
 | 
			
		||||
  private fileNames: string[] = [];
 | 
			
		||||
  private options: plugins.typescript.CompilerOptions;
 | 
			
		||||
  private argvArg?: any;
 | 
			
		||||
  private taskInfo?: any;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Create a new TsBuild instance
 | 
			
		||||
   */
 | 
			
		||||
  constructor(
 | 
			
		||||
    fileNames: string[] = [], 
 | 
			
		||||
    customOptions: CompilerOptions = {}, 
 | 
			
		||||
    argvArg?: any,
 | 
			
		||||
    taskInfo?: any
 | 
			
		||||
  ) {
 | 
			
		||||
    this.fileNames = fileNames;
 | 
			
		||||
    this.argvArg = argvArg;
 | 
			
		||||
    this.taskInfo = taskInfo;
 | 
			
		||||
    this.options = this.mergeCompilerOptions(customOptions, argvArg);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Helper function to read and process tsconfig.json
 | 
			
		||||
   */
 | 
			
		||||
  private getTsConfigOptions(): 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 {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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 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)) {
 | 
			
		||||
        if (Array.isArray(returnObject.paths[path]) && returnObject.paths[path].length > 0) {
 | 
			
		||||
          returnObject.paths[path][0] = returnObject.paths[path][0].replace('./ts_', './dist_ts_');
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
   */
 | 
			
		||||
  private getCommandLineOptions(argvArg?: any): CompilerOptions {
 | 
			
		||||
    if (!argvArg) return {};
 | 
			
		||||
    
 | 
			
		||||
    const options: CompilerOptions = {};
 | 
			
		||||
    
 | 
			
		||||
    if (argvArg.skiplibcheck) {
 | 
			
		||||
      options.skipLibCheck = true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Changed behavior: --disallowimplicitany instead of --allowimplicitany
 | 
			
		||||
    if (argvArg.disallowimplicitany) {
 | 
			
		||||
      options.noImplicitAny = true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (argvArg.commonjs) {
 | 
			
		||||
      options.module = plugins.typescript.ModuleKind.CommonJS;
 | 
			
		||||
      options.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeJs;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return 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(
 | 
			
		||||
    customTsOptions: CompilerOptions = {},
 | 
			
		||||
    argvArg?: any
 | 
			
		||||
  ): CompilerOptions {
 | 
			
		||||
    // create merged options
 | 
			
		||||
    const mergedOptions: CompilerOptions = {
 | 
			
		||||
      ...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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Helper function to process TypeScript diagnostics and return error summary
 | 
			
		||||
   */
 | 
			
		||||
  private processDiagnostics(diagnostics: readonly plugins.typescript.Diagnostic[]): IErrorSummary {
 | 
			
		||||
    const errorsByFile: Record<string, plugins.typescript.Diagnostic[]> = {};
 | 
			
		||||
    const generalErrors: plugins.typescript.Diagnostic[] = [];
 | 
			
		||||
    
 | 
			
		||||
    // Categorize diagnostics
 | 
			
		||||
    diagnostics.forEach((diagnostic) => {
 | 
			
		||||
      if (diagnostic.file) {
 | 
			
		||||
        const fileName = diagnostic.file.fileName;
 | 
			
		||||
        if (!errorsByFile[fileName]) {
 | 
			
		||||
          errorsByFile[fileName] = [];
 | 
			
		||||
        }
 | 
			
		||||
        errorsByFile[fileName].push(diagnostic);
 | 
			
		||||
      } else {
 | 
			
		||||
        generalErrors.push(diagnostic);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    return {
 | 
			
		||||
      errorsByFile,
 | 
			
		||||
      generalErrors,
 | 
			
		||||
      totalErrors: diagnostics.length,
 | 
			
		||||
      totalFiles: Object.keys(errorsByFile).length
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Helper function to display error summary
 | 
			
		||||
   */
 | 
			
		||||
  private displayErrorSummary(errorSummary: IErrorSummary): void {
 | 
			
		||||
    if (errorSummary.totalErrors === 0) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const { errorsByFile, generalErrors, totalErrors, totalFiles } = errorSummary;
 | 
			
		||||
    
 | 
			
		||||
    // Print error summary header
 | 
			
		||||
    console.log('\n' + '='.repeat(80));
 | 
			
		||||
    console.log(`❌ Found ${totalErrors} error${totalErrors !== 1 ? 's' : ''} in ${totalFiles} file${totalFiles !== 1 ? 's' : ''}:`);
 | 
			
		||||
    console.log('='.repeat(80));
 | 
			
		||||
    
 | 
			
		||||
    // Color codes for error formatting
 | 
			
		||||
    const colors = {
 | 
			
		||||
      reset: '\x1b[0m',
 | 
			
		||||
      red: '\x1b[31m',
 | 
			
		||||
      yellow: '\x1b[33m',
 | 
			
		||||
      cyan: '\x1b[36m',
 | 
			
		||||
      white: '\x1b[37m',
 | 
			
		||||
      brightRed: '\x1b[91m'
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    // Print file-specific errors
 | 
			
		||||
    Object.entries(errorsByFile).forEach(([fileName, fileErrors]) => {
 | 
			
		||||
      // Show relative path if possible for cleaner output
 | 
			
		||||
      const displayPath = fileName.replace(process.cwd(), '').replace(/^\//, '');
 | 
			
		||||
      
 | 
			
		||||
      console.log(`\n${colors.cyan}File: ${displayPath} ${colors.yellow}(${fileErrors.length} error${fileErrors.length !== 1 ? 's' : ''})${colors.reset}`);
 | 
			
		||||
      console.log('-'.repeat(80));
 | 
			
		||||
      
 | 
			
		||||
      fileErrors.forEach((diagnostic) => {
 | 
			
		||||
        if (diagnostic.file && diagnostic.start !== undefined) {
 | 
			
		||||
          const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
 | 
			
		||||
          const message = plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
 | 
			
		||||
          const errorCode = diagnostic.code ? `TS${diagnostic.code}` : 'Error';
 | 
			
		||||
          
 | 
			
		||||
          console.log(`${colors.white}Line ${line + 1}, Col ${character + 1}${colors.reset}: ${colors.brightRed}${errorCode}${colors.reset} - ${message}`);
 | 
			
		||||
          
 | 
			
		||||
          // Try to show the code snippet if possible
 | 
			
		||||
          try {
 | 
			
		||||
            const lineContent = diagnostic.file.text.split('\n')[line];
 | 
			
		||||
            if (lineContent) {
 | 
			
		||||
              // Show the line of code
 | 
			
		||||
              console.log(`  ${lineContent.trimRight()}`);
 | 
			
		||||
              
 | 
			
		||||
              // Show the error position indicator
 | 
			
		||||
              const indicator = ' '.repeat(character) + `${colors.red}^${colors.reset}`;
 | 
			
		||||
              console.log(`  ${indicator}`);
 | 
			
		||||
            }
 | 
			
		||||
          } catch (e) {
 | 
			
		||||
            // Failed to get source text, skip showing the code snippet
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    // Print general errors
 | 
			
		||||
    if (generalErrors.length > 0) {
 | 
			
		||||
      console.log(`\n${colors.yellow}General Errors:${colors.reset}`);
 | 
			
		||||
      console.log('-'.repeat(80));
 | 
			
		||||
      
 | 
			
		||||
      generalErrors.forEach((diagnostic) => {
 | 
			
		||||
        const message = plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
 | 
			
		||||
        const errorCode = diagnostic.code ? `TS${diagnostic.code}` : 'Error';
 | 
			
		||||
        console.log(`${colors.brightRed}${errorCode}${colors.reset}: ${message}`);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    console.log('\n' + '='.repeat(80) + '\n');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Creates a TypeScript program from file names and options
 | 
			
		||||
   */
 | 
			
		||||
  private createProgram(
 | 
			
		||||
    options: plugins.typescript.CompilerOptions = this.options
 | 
			
		||||
  ): plugins.typescript.Program {
 | 
			
		||||
    return plugins.typescript.createProgram(this.fileNames, options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Set file names to be compiled
 | 
			
		||||
   */
 | 
			
		||||
  public setFileNames(fileNames: string[]): void {
 | 
			
		||||
    this.fileNames = fileNames;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Set compiler options
 | 
			
		||||
   */
 | 
			
		||||
  public setOptions(options: CompilerOptions): void {
 | 
			
		||||
    this.options = { ...this.options, ...options };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The main compiler function that compiles the files and returns error summary
 | 
			
		||||
   */
 | 
			
		||||
  public async compileWithErrorTracking(): Promise<{ emittedFiles: any[], errorSummary: IErrorSummary }> {
 | 
			
		||||
    if (this.options.skipLibCheck) {
 | 
			
		||||
      if (this.argvArg?.confirmskiplibcheck) {
 | 
			
		||||
        console.log('\n⚠️  WARNING ⚠️');
 | 
			
		||||
        console.log('You are skipping libcheck... Is that really wanted?');
 | 
			
		||||
        console.log('Continuing in 5 seconds...\n');
 | 
			
		||||
        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...`);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const done = plugins.smartpromise.defer<{ emittedFiles: any[], errorSummary: IErrorSummary }>();
 | 
			
		||||
    const program = this.createProgram();
 | 
			
		||||
    
 | 
			
		||||
    // Check for pre-emit diagnostics first
 | 
			
		||||
    const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
			
		||||
    const preEmitErrorSummary = this.processDiagnostics(preEmitDiagnostics);
 | 
			
		||||
    
 | 
			
		||||
    // Only continue to emit phase if no pre-emit errors
 | 
			
		||||
    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('   Type errors must be resolved before the compiler can emit output files.\n');
 | 
			
		||||
      // Return error summary instead of exiting to allow final summary display
 | 
			
		||||
      done.resolve({ emittedFiles: [], errorSummary: preEmitErrorSummary });
 | 
			
		||||
      return done.promise;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // If no pre-emit errors, proceed with emit
 | 
			
		||||
    const emitResult = program.emit();
 | 
			
		||||
    const emitErrorSummary = this.processDiagnostics(emitResult.diagnostics);
 | 
			
		||||
    
 | 
			
		||||
    // 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 exitCode = emitResult.emitSkipped ? 1 : 0;
 | 
			
		||||
    if (exitCode === 0) {
 | 
			
		||||
      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
 | 
			
		||||
      const jsFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.js')).length || 0;
 | 
			
		||||
      const dtsFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.d.ts')).length || 0;
 | 
			
		||||
      const mapFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.map')).length || 0;
 | 
			
		||||
      
 | 
			
		||||
      // If we have emitted files, show a summary
 | 
			
		||||
      if (emitResult.emittedFiles && emitResult.emittedFiles.length > 0) {
 | 
			
		||||
        console.log(`   📄 Generated ${emitResult.emittedFiles.length} files: ${jsFiles} .js, ${dtsFiles} .d.ts, ${mapFiles} source maps`);
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      done.resolve({ emittedFiles: emitResult.emittedFiles || [], errorSummary: combinedErrorSummary });
 | 
			
		||||
    } else {
 | 
			
		||||
      this.displayErrorSummary(combinedErrorSummary);
 | 
			
		||||
      console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!');
 | 
			
		||||
      console.error('   No output files have been generated.\n');
 | 
			
		||||
      // Do not exit here; return error summary so caller can decide
 | 
			
		||||
      done.resolve({ emittedFiles: [], errorSummary: combinedErrorSummary });
 | 
			
		||||
      return done.promise;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return done.promise;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The main compiler function that compiles the files
 | 
			
		||||
   */
 | 
			
		||||
  public async compile(): Promise<any[]> {
 | 
			
		||||
    if (this.options.skipLibCheck) {
 | 
			
		||||
      if (this.argvArg?.confirmskiplibcheck) {
 | 
			
		||||
        console.log('\n⚠️  WARNING ⚠️');
 | 
			
		||||
        console.log('You are skipping libcheck... Is that really wanted?');
 | 
			
		||||
        console.log('Continuing in 5 seconds...\n');
 | 
			
		||||
        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...`);
 | 
			
		||||
    const done = plugins.smartpromise.defer<any[]>();
 | 
			
		||||
    const program = this.createProgram();
 | 
			
		||||
    
 | 
			
		||||
    // Check for pre-emit diagnostics first
 | 
			
		||||
    const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
			
		||||
    const preEmitErrorSummary = this.processDiagnostics(preEmitDiagnostics);
 | 
			
		||||
    
 | 
			
		||||
    // Only continue to emit phase if no pre-emit errors
 | 
			
		||||
    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('   Type errors must be resolved before the compiler can emit output files.\n');
 | 
			
		||||
      // Throw instead of exiting to keep library pure
 | 
			
		||||
      throw new Error('TypeScript pre-emit checks failed.');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // If no pre-emit errors, proceed with emit
 | 
			
		||||
    const emitResult = program.emit();
 | 
			
		||||
    const emitErrorSummary = this.processDiagnostics(emitResult.diagnostics);
 | 
			
		||||
 | 
			
		||||
    const exitCode = emitResult.emitSkipped ? 1 : 0;
 | 
			
		||||
    if (exitCode === 0) {
 | 
			
		||||
      console.log('\n✅ TypeScript emit succeeded!');
 | 
			
		||||
      
 | 
			
		||||
      // Get count of emitted files by type
 | 
			
		||||
      const jsFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.js')).length || 0;
 | 
			
		||||
      const dtsFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.d.ts')).length || 0;
 | 
			
		||||
      const mapFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.map')).length || 0;
 | 
			
		||||
      
 | 
			
		||||
      // If we have emitted files, show a summary
 | 
			
		||||
      if (emitResult.emittedFiles && emitResult.emittedFiles.length > 0) {
 | 
			
		||||
        console.log(`   Generated ${emitResult.emittedFiles.length} files: ${jsFiles} .js, ${dtsFiles} .d.ts, ${mapFiles} source maps`);
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      done.resolve(emitResult.emittedFiles);
 | 
			
		||||
    } else {
 | 
			
		||||
      this.displayErrorSummary(emitErrorSummary);
 | 
			
		||||
      console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!');
 | 
			
		||||
      console.error('   No output files have been generated.\n');
 | 
			
		||||
      // Throw instead of exiting to keep library pure
 | 
			
		||||
      throw new Error('TypeScript emit failed.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return done.promise;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Function to check if files can be emitted without actually emitting them
 | 
			
		||||
   */
 | 
			
		||||
  public async checkEmit(): Promise<boolean> {
 | 
			
		||||
    const fileCount = this.fileNames.length;
 | 
			
		||||
    console.log(`\n🔍 Checking if ${fileCount} file${fileCount !== 1 ? 's' : ''} can be emitted...`);
 | 
			
		||||
    
 | 
			
		||||
    // Create a program with noEmit option
 | 
			
		||||
    const program = this.createProgram({
 | 
			
		||||
      ...this.options,
 | 
			
		||||
      noEmit: true
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    // Check for pre-emit diagnostics
 | 
			
		||||
    const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
			
		||||
    const preEmitErrorSummary = this.processDiagnostics(preEmitDiagnostics);
 | 
			
		||||
    
 | 
			
		||||
    // 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 emitErrorSummary = this.processDiagnostics(emitResult.diagnostics);
 | 
			
		||||
    
 | 
			
		||||
    // 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) {
 | 
			
		||||
      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`);
 | 
			
		||||
    } else {
 | 
			
		||||
      this.displayErrorSummary(combinedErrorSummary);
 | 
			
		||||
      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');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return success;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  /**
 | 
			
		||||
   * Function to check TypeScript files for type errors without emission
 | 
			
		||||
   */
 | 
			
		||||
  public async checkTypes(): Promise<boolean> {
 | 
			
		||||
    const fileCount = this.fileNames.length;
 | 
			
		||||
    console.log(`\n🔍 Type checking ${fileCount} TypeScript file${fileCount !== 1 ? 's' : ''}...`);
 | 
			
		||||
    
 | 
			
		||||
    // Create a program with noEmit option explicitly set
 | 
			
		||||
    const program = this.createProgram({
 | 
			
		||||
      ...this.options,
 | 
			
		||||
      noEmit: true
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    // Check for type errors
 | 
			
		||||
    const diagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
			
		||||
    const errorSummary = this.processDiagnostics(diagnostics);
 | 
			
		||||
    
 | 
			
		||||
    // Set success flag
 | 
			
		||||
    const success = errorSummary.totalErrors === 0;
 | 
			
		||||
    
 | 
			
		||||
    if (success) {
 | 
			
		||||
      console.log('\n✅ TypeScript type check passed! No type errors found.');
 | 
			
		||||
      console.log(`   All ${fileCount} file${fileCount !== 1 ? 's' : ''} passed type checking successfully.\n`);
 | 
			
		||||
    } else {
 | 
			
		||||
      this.displayErrorSummary(errorSummary);
 | 
			
		||||
      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');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return success;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Merges compilerOptions with the default compiler options (backward compatibility)
 | 
			
		||||
 */
 | 
			
		||||
export const mergeCompilerOptions = (
 | 
			
		||||
  customTsOptions: CompilerOptions,
 | 
			
		||||
  argvArg?: any
 | 
			
		||||
): CompilerOptions => {
 | 
			
		||||
  const tsBuild = new TsBuild();
 | 
			
		||||
  return tsBuild.mergeCompilerOptions(customTsOptions, argvArg);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The internal main compiler function that compiles the files (backward compatibility)
 | 
			
		||||
 */
 | 
			
		||||
export const compiler = async (
 | 
			
		||||
  fileNames: string[],
 | 
			
		||||
  options: plugins.typescript.CompilerOptions,
 | 
			
		||||
  argvArg?: any
 | 
			
		||||
): Promise<any[]> => {
 | 
			
		||||
  const tsBuild = new TsBuild(fileNames, options, argvArg);
 | 
			
		||||
  return tsBuild.compile();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Function to check if a TypeScript file can be emitted without actually emitting it (backward compatibility)
 | 
			
		||||
 */
 | 
			
		||||
export const emitCheck = async (
 | 
			
		||||
  fileNames: string[],
 | 
			
		||||
  options: plugins.typescript.CompilerOptions = {},
 | 
			
		||||
  argvArg?: any
 | 
			
		||||
): Promise<boolean> => {
 | 
			
		||||
  const tsBuild = new TsBuild(fileNames, options, argvArg);
 | 
			
		||||
  return tsBuild.checkEmit();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Function to check TypeScript files for type errors without emission (backward compatibility)
 | 
			
		||||
 */
 | 
			
		||||
export const checkTypes = async (
 | 
			
		||||
  fileNames: string[],
 | 
			
		||||
  options: plugins.typescript.CompilerOptions = {},
 | 
			
		||||
  argvArg?: any
 | 
			
		||||
): Promise<boolean> => {
 | 
			
		||||
  const tsBuild = new TsBuild(fileNames, options, argvArg);
 | 
			
		||||
  return tsBuild.checkTypes();
 | 
			
		||||
};
 | 
			
		||||
@@ -9,7 +9,7 @@ export const runCli = async () => {
 | 
			
		||||
   * the standard task compiles anything in ts/ directory to dist directory
 | 
			
		||||
   */
 | 
			
		||||
  tsbuildCli.standardCommand().subscribe(async (argvArg) => {
 | 
			
		||||
    tsbuild.compileGlobStringObject(
 | 
			
		||||
    await tsbuild.compileGlobStringObject(
 | 
			
		||||
      {
 | 
			
		||||
        './ts/**/*.ts': './dist_ts',
 | 
			
		||||
      },
 | 
			
		||||
@@ -17,6 +17,10 @@ export const runCli = async () => {
 | 
			
		||||
      process.cwd(),
 | 
			
		||||
      argvArg
 | 
			
		||||
    );
 | 
			
		||||
    const summary = (argvArg as any)?.__tsbuildFinalErrorSummary;
 | 
			
		||||
    if (summary && summary.totalErrors > 0) {
 | 
			
		||||
      process.exit(1);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@@ -30,6 +34,94 @@ export const runCli = async () => {
 | 
			
		||||
      compilationCommandObject[`./${directory}/**/*.ts`] = `./dist_${directory}`;
 | 
			
		||||
    }
 | 
			
		||||
    await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
 | 
			
		||||
    const summary = (argvArg as any)?.__tsbuildFinalErrorSummary;
 | 
			
		||||
    if (summary && summary.totalErrors > 0) {
 | 
			
		||||
      process.exit(1);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * the emitcheck command checks if a TypeScript file can be emitted without actually emitting it
 | 
			
		||||
   */
 | 
			
		||||
  tsbuildCli.addCommand('emitcheck').subscribe(async (argvArg) => {
 | 
			
		||||
    const patterns = argvArg._.slice(1); // Remove the first element which is 'emitcheck'
 | 
			
		||||
    
 | 
			
		||||
    if (patterns.length === 0) {
 | 
			
		||||
      console.error('\n❌ Error: Please provide at least one TypeScript file path or glob pattern');
 | 
			
		||||
      console.error('   Usage: tsbuild emitcheck <file_or_glob_pattern> [additional_patterns ...]\n');
 | 
			
		||||
      console.error('   Example: tsbuild emitcheck "src/**/*.ts" "test/**/*.ts"\n');
 | 
			
		||||
      process.exit(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const cwd = process.cwd();
 | 
			
		||||
    let allFiles: string[] = [];
 | 
			
		||||
 | 
			
		||||
    // Process each pattern - could be a direct file path or a glob pattern
 | 
			
		||||
    for (const pattern of patterns) {
 | 
			
		||||
      // Check if the pattern looks like a glob pattern
 | 
			
		||||
      if (pattern.includes('*') || pattern.includes('{') || pattern.includes('?')) {
 | 
			
		||||
        // Handle as glob pattern
 | 
			
		||||
        console.log(`Processing glob pattern: ${pattern}`);
 | 
			
		||||
        try {
 | 
			
		||||
          const matchedFiles = await plugins.smartfile.fs.listFileTree(cwd, pattern);
 | 
			
		||||
          
 | 
			
		||||
          // Ensure matchedFiles contains only strings
 | 
			
		||||
          const stringMatchedFiles = Array.isArray(matchedFiles) 
 | 
			
		||||
            ? matchedFiles.filter((item): item is string => typeof item === 'string')
 | 
			
		||||
            : [];
 | 
			
		||||
            
 | 
			
		||||
          if (stringMatchedFiles.length === 0) {
 | 
			
		||||
            console.warn(`⚠️  Warning: No files matched the pattern '${pattern}'`);
 | 
			
		||||
          } else {
 | 
			
		||||
            console.log(`📂 Found ${stringMatchedFiles.length} files matching pattern '${pattern}'`);
 | 
			
		||||
            
 | 
			
		||||
            // Transform to absolute paths
 | 
			
		||||
            const absoluteMatchedFiles = plugins.smartpath.transform.toAbsolute(
 | 
			
		||||
              stringMatchedFiles,
 | 
			
		||||
              cwd
 | 
			
		||||
            ) as string[];
 | 
			
		||||
            
 | 
			
		||||
            // Add to the list of all files to check
 | 
			
		||||
            allFiles = allFiles.concat(absoluteMatchedFiles);
 | 
			
		||||
          }
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
          console.error(`❌ Error processing glob pattern '${pattern}': ${err}`);
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        // Handle as direct file path
 | 
			
		||||
        const filePath = plugins.path.isAbsolute(pattern) 
 | 
			
		||||
          ? pattern 
 | 
			
		||||
          : plugins.path.join(cwd, pattern);
 | 
			
		||||
          
 | 
			
		||||
        try {
 | 
			
		||||
          await plugins.smartfile.fs.fileExists(filePath);
 | 
			
		||||
          allFiles.push(filePath);
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
          console.error(`❌ Error: File not found: ${filePath}`);
 | 
			
		||||
          process.exit(1);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Filter to only TypeScript files
 | 
			
		||||
    allFiles = allFiles.filter(file => file.endsWith('.ts') || file.endsWith('.tsx'));
 | 
			
		||||
    
 | 
			
		||||
    if (allFiles.length === 0) {
 | 
			
		||||
      console.error('\n❌ Error: No TypeScript files found to check');
 | 
			
		||||
      console.error('   Please verify your file paths or glob patterns.\n');
 | 
			
		||||
      process.exit(1);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    console.log(`\n🔎 Found ${allFiles.length} TypeScript file${allFiles.length !== 1 ? 's' : ''} to check`);
 | 
			
		||||
 | 
			
		||||
    // Process compiler options
 | 
			
		||||
    const compilerOptions = tsbuild.mergeCompilerOptions({}, argvArg);
 | 
			
		||||
    
 | 
			
		||||
    // Run emit check
 | 
			
		||||
    const success = await tsbuild.emitCheck(allFiles, compilerOptions, argvArg);
 | 
			
		||||
    
 | 
			
		||||
    // Exit with appropriate code
 | 
			
		||||
    process.exit(success ? 0 : 1);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@@ -80,12 +172,167 @@ export const runCli = async () => {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    const compilationCommandObject: { [key: string]: string } = {};
 | 
			
		||||
    console.log(`compiling in this order:`);
 | 
			
		||||
    console.log(sortedTsFolders);
 | 
			
		||||
    const folderCount = sortedTsFolders.length;
 | 
			
		||||
    console.log(`\n📂 TypeScript Folder Compilation Plan (${folderCount} folder${folderCount !== 1 ? 's' : ''})`);
 | 
			
		||||
    console.log('┌' + '─'.repeat(60) + '┐');
 | 
			
		||||
    console.log('│ 🔄 Compilation Order                                     │');
 | 
			
		||||
    console.log('├' + '─'.repeat(60) + '┤');
 | 
			
		||||
    
 | 
			
		||||
    sortedTsFolders.forEach((folder, index) => {
 | 
			
		||||
      const prefix = index === folderCount - 1 ? '└─' : '├─';
 | 
			
		||||
      const position = `${index + 1}/${folderCount}`;
 | 
			
		||||
      console.log(`│ ${prefix} ${position.padStart(5)} ${folder.padEnd(46)} │`);
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    console.log('└' + '─'.repeat(60) + '┘\n');
 | 
			
		||||
    
 | 
			
		||||
    for (const tsFolder of sortedTsFolders) {
 | 
			
		||||
      compilationCommandObject[`./${tsFolder}/**/*.ts`] = `./dist_${tsFolder}`;
 | 
			
		||||
    }
 | 
			
		||||
    await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
 | 
			
		||||
    const summary = (argvArg as any)?.__tsbuildFinalErrorSummary;
 | 
			
		||||
    if (summary && summary.totalErrors > 0) {
 | 
			
		||||
      process.exit(1);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  
 | 
			
		||||
  /**
 | 
			
		||||
   * the check command checks TypeScript files against a glob pattern without emitting them
 | 
			
		||||
   */
 | 
			
		||||
  tsbuildCli.addCommand('check').subscribe(async (argvArg) => {
 | 
			
		||||
    const patterns = argvArg._.slice(1); // Remove the first element which is 'check'
 | 
			
		||||
    
 | 
			
		||||
    // If no patterns provided, default to checking ts/**/* and then test/**/*
 | 
			
		||||
    if (patterns.length === 0) {
 | 
			
		||||
      console.log('\n🔬 Running default type checking sequence...\n');
 | 
			
		||||
      
 | 
			
		||||
      // First check ts/**/* without skiplibcheck
 | 
			
		||||
      console.log('📂 Checking ts/**/* files...');
 | 
			
		||||
      const tsFiles = await plugins.smartfile.fs.listFileTree(process.cwd(), 'ts/**/*.ts');
 | 
			
		||||
      const tsTsFiles = Array.isArray(tsFiles) 
 | 
			
		||||
        ? tsFiles.filter((item): item is string => typeof item === 'string')
 | 
			
		||||
        : [];
 | 
			
		||||
      
 | 
			
		||||
      if (tsTsFiles.length > 0) {
 | 
			
		||||
        console.log(`   Found ${tsTsFiles.length} TypeScript files in ts/`);
 | 
			
		||||
        const tsAbsoluteFiles = plugins.smartpath.transform.toAbsolute(
 | 
			
		||||
          tsTsFiles,
 | 
			
		||||
          process.cwd()
 | 
			
		||||
        ) as string[];
 | 
			
		||||
        
 | 
			
		||||
        const tsCompilerOptions = tsbuild.mergeCompilerOptions({}, argvArg);
 | 
			
		||||
        const tsSuccess = await tsbuild.checkTypes(tsAbsoluteFiles, tsCompilerOptions, argvArg);
 | 
			
		||||
        
 | 
			
		||||
        if (!tsSuccess) {
 | 
			
		||||
          console.error('❌ Type checking failed for ts/**/*');
 | 
			
		||||
          process.exit(1);
 | 
			
		||||
        }
 | 
			
		||||
        console.log('✅ Type checking passed for ts/**/*\n');
 | 
			
		||||
      } else {
 | 
			
		||||
        console.log('   No TypeScript files found in ts/\n');
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      // Then check test/**/* with skiplibcheck
 | 
			
		||||
      console.log('📂 Checking test/**/* files with --skiplibcheck...');
 | 
			
		||||
      const testFiles = await plugins.smartfile.fs.listFileTree(process.cwd(), 'test/**/*.ts');
 | 
			
		||||
      const testTsFiles = Array.isArray(testFiles) 
 | 
			
		||||
        ? testFiles.filter((item): item is string => typeof item === 'string')
 | 
			
		||||
        : [];
 | 
			
		||||
      
 | 
			
		||||
      if (testTsFiles.length > 0) {
 | 
			
		||||
        console.log(`   Found ${testTsFiles.length} TypeScript files in test/`);
 | 
			
		||||
        const testAbsoluteFiles = plugins.smartpath.transform.toAbsolute(
 | 
			
		||||
          testTsFiles,
 | 
			
		||||
          process.cwd()
 | 
			
		||||
        ) as string[];
 | 
			
		||||
        
 | 
			
		||||
        // Create new argvArg with skiplibcheck for test files
 | 
			
		||||
        const testArgvArg = { ...argvArg, skiplibcheck: true };
 | 
			
		||||
        const testCompilerOptions = tsbuild.mergeCompilerOptions({}, testArgvArg);
 | 
			
		||||
        const testSuccess = await tsbuild.checkTypes(testAbsoluteFiles, testCompilerOptions, testArgvArg);
 | 
			
		||||
        
 | 
			
		||||
        if (!testSuccess) {
 | 
			
		||||
          console.error('❌ Type checking failed for test/**/*');
 | 
			
		||||
          process.exit(1);
 | 
			
		||||
        }
 | 
			
		||||
        console.log('✅ Type checking passed for test/**/*\n');
 | 
			
		||||
      } else {
 | 
			
		||||
        console.log('   No TypeScript files found in test/\n');
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      console.log('✅ All default type checks passed!\n');
 | 
			
		||||
      process.exit(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const cwd = process.cwd();
 | 
			
		||||
    let allFiles: string[] = [];
 | 
			
		||||
 | 
			
		||||
    // Process each pattern - could be a direct file path or a glob pattern
 | 
			
		||||
    for (const pattern of patterns) {
 | 
			
		||||
      // Check if the pattern looks like a glob pattern
 | 
			
		||||
      if (pattern.includes('*') || pattern.includes('{') || pattern.includes('?')) {
 | 
			
		||||
        // Handle as glob pattern
 | 
			
		||||
        console.log(`Processing glob pattern: ${pattern}`);
 | 
			
		||||
        try {
 | 
			
		||||
          const matchedFiles = await plugins.smartfile.fs.listFileTree(cwd, pattern);
 | 
			
		||||
          
 | 
			
		||||
          // Ensure matchedFiles contains only strings
 | 
			
		||||
          const stringMatchedFiles = Array.isArray(matchedFiles) 
 | 
			
		||||
            ? matchedFiles.filter((item): item is string => typeof item === 'string')
 | 
			
		||||
            : [];
 | 
			
		||||
            
 | 
			
		||||
          if (stringMatchedFiles.length === 0) {
 | 
			
		||||
            console.warn(`⚠️  Warning: No files matched the pattern '${pattern}'`);
 | 
			
		||||
          } else {
 | 
			
		||||
            console.log(`📂 Found ${stringMatchedFiles.length} files matching pattern '${pattern}'`);
 | 
			
		||||
            
 | 
			
		||||
            // Transform to absolute paths
 | 
			
		||||
            const absoluteMatchedFiles = plugins.smartpath.transform.toAbsolute(
 | 
			
		||||
              stringMatchedFiles,
 | 
			
		||||
              cwd
 | 
			
		||||
            ) as string[];
 | 
			
		||||
            
 | 
			
		||||
            // Add to the list of all files to check
 | 
			
		||||
            allFiles = allFiles.concat(absoluteMatchedFiles);
 | 
			
		||||
          }
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
          console.error(`❌ Error processing glob pattern '${pattern}': ${err}`);
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        // Handle as direct file path
 | 
			
		||||
        const filePath = plugins.path.isAbsolute(pattern) 
 | 
			
		||||
          ? pattern 
 | 
			
		||||
          : plugins.path.join(cwd, pattern);
 | 
			
		||||
          
 | 
			
		||||
        try {
 | 
			
		||||
          await plugins.smartfile.fs.fileExists(filePath);
 | 
			
		||||
          allFiles.push(filePath);
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
          console.error(`❌ Error: File not found: ${filePath}`);
 | 
			
		||||
          process.exit(1);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Filter to only TypeScript files
 | 
			
		||||
    allFiles = allFiles.filter(file => file.endsWith('.ts') || file.endsWith('.tsx'));
 | 
			
		||||
    
 | 
			
		||||
    if (allFiles.length === 0) {
 | 
			
		||||
      console.error('\n❌ Error: No TypeScript files found to check');
 | 
			
		||||
      console.error('   Please verify your file paths or glob patterns.\n');
 | 
			
		||||
      process.exit(1);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    console.log(`\n🔎 Found ${allFiles.length} TypeScript file${allFiles.length !== 1 ? 's' : ''} to check`);
 | 
			
		||||
 | 
			
		||||
    // Process compiler options
 | 
			
		||||
    const compilerOptions = tsbuild.mergeCompilerOptions({}, argvArg);
 | 
			
		||||
    
 | 
			
		||||
    // Run type check without emitting
 | 
			
		||||
    const success = await tsbuild.checkTypes(allFiles, compilerOptions, argvArg);
 | 
			
		||||
    
 | 
			
		||||
    // Exit with appropriate code
 | 
			
		||||
    process.exit(success ? 0 : 1);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  tsbuildCli.startParse();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,35 @@
 | 
			
		||||
import * as plugins from './plugins.js';
 | 
			
		||||
import type { CompilerOptions, ScriptTarget, ModuleKind } from 'typescript';
 | 
			
		||||
import { compiler, mergeCompilerOptions } from './tsbuild.classes.compiler.js';
 | 
			
		||||
import { compiler, mergeCompilerOptions, emitCheck, checkTypes } from './tsbuild.classes.tsbuild.js';
 | 
			
		||||
 | 
			
		||||
export type { CompilerOptions, ScriptTarget, ModuleKind };
 | 
			
		||||
 | 
			
		||||
export * from './tsbuild.classes.compiler.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
 | 
			
		||||
 */
 | 
			
		||||
export let compileFileArrayWithErrorTracking = async (
 | 
			
		||||
  fileStringArrayArg: string[],
 | 
			
		||||
  compilerOptionsArg: CompilerOptions = {},
 | 
			
		||||
  argvArg?: any,
 | 
			
		||||
  taskInfo?: ITaskInfo
 | 
			
		||||
): Promise<{ emittedFiles: any[], errorSummary: import('./tsbuild.classes.tsbuild.js').IErrorSummary }> => {
 | 
			
		||||
  const { TsBuild } = await import('./tsbuild.classes.tsbuild.js');
 | 
			
		||||
  const tsBuild = new TsBuild(fileStringArrayArg, compilerOptionsArg, argvArg, taskInfo);
 | 
			
		||||
  return tsBuild.compileWithErrorTracking();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * compile am array of absolute file paths
 | 
			
		||||
@@ -17,6 +42,75 @@ export let compileFileArray = (
 | 
			
		||||
  return compiler(fileStringArrayArg, mergeCompilerOptions(compilerOptionsArg, argvArg), argvArg);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper function to merge error summaries
 | 
			
		||||
 */
 | 
			
		||||
function mergeErrorSummaries(summaries: import('./tsbuild.classes.tsbuild.js').IErrorSummary[]): import('./tsbuild.classes.tsbuild.js').IErrorSummary {
 | 
			
		||||
  const mergedErrorsByFile: Record<string, plugins.typescript.Diagnostic[]> = {};
 | 
			
		||||
  const mergedGeneralErrors: plugins.typescript.Diagnostic[] = [];
 | 
			
		||||
  let totalErrors = 0;
 | 
			
		||||
  
 | 
			
		||||
  summaries.forEach(summary => {
 | 
			
		||||
    // Merge errors by file
 | 
			
		||||
    Object.entries(summary.errorsByFile).forEach(([fileName, errors]) => {
 | 
			
		||||
      if (!mergedErrorsByFile[fileName]) {
 | 
			
		||||
        mergedErrorsByFile[fileName] = [];
 | 
			
		||||
      }
 | 
			
		||||
      mergedErrorsByFile[fileName] = mergedErrorsByFile[fileName].concat(errors);
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    // Merge general errors
 | 
			
		||||
    mergedGeneralErrors.push(...summary.generalErrors);
 | 
			
		||||
    totalErrors += summary.totalErrors;
 | 
			
		||||
  });
 | 
			
		||||
  
 | 
			
		||||
  return {
 | 
			
		||||
    errorsByFile: mergedErrorsByFile,
 | 
			
		||||
    generalErrors: mergedGeneralErrors,
 | 
			
		||||
    totalErrors,
 | 
			
		||||
    totalFiles: Object.keys(mergedErrorsByFile).length
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper function to display final compilation summary
 | 
			
		||||
 */
 | 
			
		||||
function displayFinalErrorSummary(errorSummary: import('./tsbuild.classes.tsbuild.js').IErrorSummary): void {
 | 
			
		||||
  if (errorSummary.totalErrors === 0) {
 | 
			
		||||
    console.log('\n📊 \x1b[32mCompilation Summary: All tasks completed successfully! ✅\x1b[0m\n');
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  const colors = {
 | 
			
		||||
    reset: '\x1b[0m',
 | 
			
		||||
    red: '\x1b[31m',
 | 
			
		||||
    yellow: '\x1b[33m',
 | 
			
		||||
    cyan: '\x1b[36m',
 | 
			
		||||
    brightRed: '\x1b[91m',
 | 
			
		||||
    brightYellow: '\x1b[93m'
 | 
			
		||||
  };
 | 
			
		||||
  
 | 
			
		||||
  console.log('\n' + '='.repeat(80));
 | 
			
		||||
  console.log(`📊 ${colors.brightYellow}Final Compilation Summary${colors.reset}`);
 | 
			
		||||
  console.log('='.repeat(80));
 | 
			
		||||
  
 | 
			
		||||
  if (errorSummary.totalFiles > 0) {
 | 
			
		||||
    console.log(`${colors.brightRed}❌ Files with errors (${errorSummary.totalFiles}):${colors.reset}`);
 | 
			
		||||
    
 | 
			
		||||
    Object.entries(errorSummary.errorsByFile).forEach(([fileName, errors]) => {
 | 
			
		||||
      const displayPath = fileName.replace(process.cwd(), '').replace(/^\//, '');
 | 
			
		||||
      console.log(`  ${colors.red}•${colors.reset} ${colors.cyan}${displayPath}${colors.reset} ${colors.yellow}(${errors.length} error${errors.length !== 1 ? 's' : ''})${colors.reset}`);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  if (errorSummary.generalErrors.length > 0) {
 | 
			
		||||
    console.log(`${colors.brightRed}❌ General errors: ${errorSummary.generalErrors.length}${colors.reset}`);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  console.log(`\n${colors.brightRed}Total: ${errorSummary.totalErrors} error${errorSummary.totalErrors !== 1 ? 's' : ''} across ${errorSummary.totalFiles} file${errorSummary.totalFiles !== 1 ? 's' : ''}${colors.reset}`);
 | 
			
		||||
  console.log('='.repeat(80) + '\n');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * compile advanced glob configurations
 | 
			
		||||
 * @param globStringArrayArg a array of glob strings
 | 
			
		||||
@@ -31,13 +125,25 @@ export let compileGlobStringObject = async (
 | 
			
		||||
  argvArg?: any
 | 
			
		||||
) => {
 | 
			
		||||
  let compiledFiles: any[] = [];
 | 
			
		||||
  const errorSummaries: import('./tsbuild.classes.tsbuild.js').IErrorSummary[] = [];
 | 
			
		||||
  
 | 
			
		||||
  const totalTasks = Object.keys(globStringObjectArg).length;
 | 
			
		||||
  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]) => {
 | 
			
		||||
      console.log(`  📂 ${source} → ${dest}`);
 | 
			
		||||
    });
 | 
			
		||||
    console.log('');
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  for (const keyArg in globStringObjectArg) {
 | 
			
		||||
    // Type safety check for key
 | 
			
		||||
    if (keyArg && typeof keyArg === 'string' && globStringObjectArg[keyArg]) {
 | 
			
		||||
      console.log(
 | 
			
		||||
        `TypeScript assignment: transpile from ${keyArg} to ${globStringObjectArg[keyArg]}`
 | 
			
		||||
      );
 | 
			
		||||
      
 | 
			
		||||
      // Get files matching the glob pattern
 | 
			
		||||
      const fileTreeArray = await plugins.smartfile.fs.listFileTree(cwdArg, keyArg);
 | 
			
		||||
@@ -65,12 +171,53 @@ export let compileGlobStringObject = async (
 | 
			
		||||
        outDir: destDir,
 | 
			
		||||
      };
 | 
			
		||||
      
 | 
			
		||||
      // Compile the files and correctly concat the results
 | 
			
		||||
      // Fixed: removed duplicating compiledFiles in the concat operation
 | 
			
		||||
      const newlyCompiledFiles = await compileFileArray(absoluteFilePathArray, updatedTsOptions, argvArg);
 | 
			
		||||
      compiledFiles = compiledFiles.concat(newlyCompiledFiles);
 | 
			
		||||
      // Compile with error tracking
 | 
			
		||||
      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);
 | 
			
		||||
      errorSummaries.push(result.errorSummary);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  // Display final error summary after all compilation tasks
 | 
			
		||||
  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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Attach summary to argvArg so CLI can decide exit behavior
 | 
			
		||||
  if (argvArg && typeof argvArg === 'object') {
 | 
			
		||||
    (argvArg as any).__tsbuildFinalErrorSummary = finalErrorSummary;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return compiledFiles;
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user