Compare commits

..

18 Commits

Author SHA1 Message Date
b38ef6cf82 2.7.1 2025-11-02 06:13:34 +00:00
8b50cd3090 fix(readme): Update documentation: expand README with usage, CLI and API examples; add readme.hints.md project memory 2025-11-02 06:13:34 +00:00
c6ab493efc 2.7.0 2025-11-02 05:31:55 +00:00
82ae8a0e4a feat(tsbuild): Add tsconfig.json support and safer compiler option merging; protect critical options; apply path and enum transforms; bump dependencies. 2025-11-02 05:31:55 +00:00
787becc4d3 2.6.8 2025-08-29 17:14:58 +00:00
746ca8767a fix(tsbuild): Avoid process.exit in library, add confirmskiplibcheck flag, improve CLI exit handling and JSON/quiet modes, update test script 2025-08-29 17:14:58 +00:00
55c1a2953a 2.6.7 2025-08-18 02:19:15 +00:00
8e9fcb8135 fix(tspublish): Bump @git.zone/tspublish dependency to ^1.10.3 2025-08-18 02:19:15 +00:00
18573c777d 2.6.6 2025-08-18 00:32:26 +00:00
fa654b83e3 fix(dependencies): Update dependency @git.zone/tspublish to ^1.10.2 2025-08-18 00:32:26 +00:00
aa3c83cd95 2.6.5 2025-08-18 00:29:51 +00:00
20ed41df42 fix(dependencies): Bump dependencies and add pnpm-workspace configuration 2025-08-18 00:29:51 +00:00
7162476f7f 2.6.4 2025-05-24 00:30:16 +00:00
1b012628eb fix(dependencies): Add .npmrc and update dependency versions for smartfile and tstest 2025-05-24 00:30:16 +00:00
4081086621 2.6.3 2025-05-21 18:06:46 +00:00
b9cf09ccba fix(tsbuild): minor maintenance updates and documentation improvements 2025-05-21 18:06:46 +00:00
8463fbc78a 2.6.2 2025-05-21 17:59:28 +00:00
0164eb51a1 fix(npm configuration): Remove .npmrc file to default npm registry behavior 2025-05-21 17:59:28 +00:00
11 changed files with 4829 additions and 3572 deletions

1
.npmrc
View File

@@ -1 +0,0 @@
registry=https://registry.npmjs.org/

View File

@@ -1,5 +1,74 @@
# Changelog # Changelog
## 2025-11-02 - 2.7.1 - fix(readme)
Update documentation: expand README with usage, CLI and API examples; add readme.hints.md project memory
- Add readme.hints.md: new project memory / quick reference with public API and CLI summaries
- Expand and restructure readme.md: more comprehensive Quick Start, CLI Commands, API Reference, configuration, examples and troubleshooting
- Clarify protected compiler options, default compiler options, path transformation behavior and error-handling patterns
- Docs-only change — no source code or behavioral changes
## 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) ## 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 Improve error diagnostics handling by removing legacy helper and integrating more robust error summaries in the compilation process

View File

@@ -1,6 +1,6 @@
{ {
"name": "@git.zone/tsbuild", "name": "@git.zone/tsbuild",
"version": "2.6.1", "version": "2.7.1",
"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 --verbose", "test": "tstest test/test.ts --verbose",
"build": "node cli.ts.js --web", "build": "node cli.ts.js --web",
"buildDocs": "tsdoc" "buildDocs": "tsdoc"
}, },
@@ -36,19 +36,19 @@
}, },
"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.2.3", "@push.rocks/smartfile": "^11.2.7",
"@push.rocks/smartlog": "^3.1.8", "@push.rocks/smartlog": "^3.1.10",
"@push.rocks/smartpath": "^5.0.18", "@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.2.3", "@push.rocks/smartpromise": "^4.2.3",
"typescript": "5.8.3" "typescript": "5.9.3"
}, },
"devDependencies": { "devDependencies": {
"@git.zone/tsrun": "^1.2.47", "@git.zone/tsrun": "^1.6.2",
"@git.zone/tstest": "^1.9.0", "@git.zone/tstest": "^2.7.0",
"@types/node": "^22.15.21" "@types/node": "^22.15.21"
}, },
"files": [ "files": [

6869
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

4
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,4 @@
onlyBuiltDependencies:
- esbuild
- mongodb-memory-server
- puppeteer

View File

@@ -0,0 +1,175 @@
# @git.zone/tsbuild - Project Memory
## Quick Reference
### Public API (8 functions + 1 class)
1. **compileFileArray()** - Basic compilation, throws on error
2. **compileFileArrayWithErrorTracking()** - RECOMMENDED, returns IErrorSummary
3. **compileGlobStringObject()** - Most powerful, multiple patterns
4. **TsBuild Class** - Object-oriented API with compile, checkTypes, checkEmit methods
5. **mergeCompilerOptions()** - Utility for option merging
6. **compiler()** - Legacy function
7. **emitCheck()** - Validate emit capability
8. **checkTypes()** - Type checking only
### CLI Commands (5)
1. **tsbuild** (default) - Compiles ./ts/**/*.ts → ./dist_ts/
2. **tsbuild custom <dir1> <dir2>** - Custom directory compilation
3. **tsbuild tsfolders** - Auto-discover ts_* folders, compile in order
4. **tsbuild emitcheck <pattern>** - Validate emit without output
5. **tsbuild check [pattern]** - Type check only
### CLI Flags
- `--skiplibcheck` - Skip .d.ts type checking (shows warning)
- `--confirmskiplibcheck` - Extended warning with 5s pause
- `--disallowimplicitany` - Stricter type checking
- `--commonjs` - Use CommonJS instead of ESNext
- `--quiet` - Suppress non-error output
- `--json` - JSON output format
## Key Architecture Decisions
### Configuration Priority (5 levels)
1. Default options (hardcoded)
2. tsconfig.json (if exists)
3. Protected defaults (ensure integrity)
4. Programmatic options (function params)
5. CLI flags (highest priority)
### Protected Options
Cannot be overridden by tsconfig.json alone:
- `outDir: 'dist_ts/'` - Path transformation logic
- `noEmitOnError: true` - Build integrity
- `declaration: true` - Library support
- `emitDecoratorMetadata: true` - DI frameworks
- `inlineSourceMap: true` - Debugging
### Path Transformation
- Automatic: `./ts_interfaces``./dist_ts_interfaces`
- In tsconfig paths: `./ts_*``./dist_ts_*` (first array element only)
## Default Compiler Options
- Module: NodeNext (ESM with CommonJS fallback)
- Target: ESNext (latest JavaScript)
- Decorators: ENABLED (experimentalDecorators + emitDecoratorMetadata)
- Source Maps: Inline (no separate .map files)
- Declaration Files: ALWAYS generated (protected)
- Output: dist_ts/
- Implicit any: ALLOWED by default
- esModuleInterop: true
## Error Handling
### Error Summary Structure
```typescript
interface IErrorSummary {
errorsByFile: Record<string, Diagnostic[]>
generalErrors: Diagnostic[]
totalErrors: number
totalFiles: number
}
```
### Three Error Patterns
1. **Throw Pattern** - compileFileArray: throws on error
2. **Tracking Pattern** - compileFileArrayWithErrorTracking: returns IErrorSummary, NO throw
3. **Boolean Pattern** - checkTypes/emitCheck: returns boolean
RECOMMENDATION: Use compileFileArrayWithErrorTracking for production code
## JSON Output Format
```json
{
"success": boolean,
"totals": {
"errors": number,
"filesWithErrors": number,
"tasks": number
},
"errorsByFile": {
"fileName": [
{ "code": number, "message": string }
]
}
}
```
## Special Behaviors
### tsfolders Command Ordering
1. Always: ts_interfaces first
2. Always: ts_shared second
3. Then: Other folders by `order` property in their tspublish.json
4. Finally: Folders without order property (Infinity)
### check Command Default (No Arguments)
Two-phase check:
1. Phase 1: Type check ts/**/* (strict, include .d.ts)
2. Phase 2: Type check test/**/* (relaxed, skipLibCheck: true)
### Glob Pattern Support
- `*` single level
- `**` recursive
- `?` single char
- `{a,b}` alternation
- Duplicates: Files matching multiple patterns compile multiple times
### Task Information Display
When compiling multiple files with taskInfo param:
Shows: `[1/3] Compiling 45 files from ./src/**/*.ts`
Plus: File counts, duration, and file type breakdown
## File Structure
- **index.ts** - Main entry, re-exports all
- **tsbuild.exports.ts** - Core API functions
- **tsbuild.classes.tsbuild.ts** - TsBuild class + utility functions
- **tsbuild.cli.ts** - CLI command definitions
- **plugins.ts** - Dependency imports (smartfile, smartpath, smartcli, etc.)
- **paths.ts** - Path utilities (cwd, packageDir)
## Dependencies Used
- @git.zone/tspublish@^1.10.3 - Module ordering
- @push.rocks/* - smartcli, smartfile, smartpath, smartpromise, smartdelay
- typescript@5.9.3 - TypeScript compiler
## Edge Cases
1. **Empty file list** - Returns [], no error
2. **Glob duplicates** - Files compile multiple times, possible duplicate errors
3. **Non-existent files** - Handled by TypeScript "file not found" errors
4. **skipLibCheck warning** - 1-line default, 5-second pause with --confirmskiplibcheck
5. **Missing tsconfig.json** - Graceful fallback, no error
6. **Module resolution** - --commonjs switches to NodeJs (not NodeNext)
7. **Source maps** - Inline only (not separate .map files)
8. **File filtering** - Only .ts and .tsx; .d.ts and .js ignored
## Build Safety Features
- `noEmitOnError: true` - Prevents broken builds
- Error aggregation before final output
- Protected options ensure integrity
- Pre-emit checks before emit phase
- CLI exit code handling (0=success, 1=error)
## Recent Changes (from git log)
- 2.6.8 - Current version
- 2.6.7 - Previous version
- Added confirmskiplibcheck flag
- Improved CLI exit handling
- JSON/quiet modes enhanced
- Test script updates
## Configuration Example (tsconfig.json)
Paths get automatically transformed:
```json
{
"compilerOptions": {
"paths": {
"@utils/*": ["./ts_utils/*"] // → ["./dist_ts_utils/*"]
}
}
}
```
## No ts_* folders found in project root
The project itself doesn't have ts_interfaces, ts_shared, etc. directories.
The tsfolders command is designed for OTHER projects using tsbuild.

1013
readme.md

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@git.zone/tsbuild', name: '@git.zone/tsbuild',
version: '2.6.1', version: '2.7.1',
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.'
} }

View File

@@ -62,19 +62,56 @@ 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;
// Apply special transformations for string-to-enum conversions
// Process target (convert string to enum)
if (tsconfig.compilerOptions.target && typeof tsconfig.compilerOptions.target === 'string') {
const targetKey = tsconfig.compilerOptions.target.toUpperCase();
if (targetKey in plugins.typescript.ScriptTarget) {
returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget];
}
} }
// Process paths // Process module (convert string to enum)
if (tsconfig.compilerOptions.module && typeof tsconfig.compilerOptions.module === 'string') {
const moduleKey = tsconfig.compilerOptions.module.toUpperCase();
if (moduleKey in plugins.typescript.ModuleKind) {
returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind];
} else if (moduleKey === 'NODENEXT') {
returnObject.module = plugins.typescript.ModuleKind.NodeNext;
}
}
// Process moduleResolution (convert string to enum)
if (tsconfig.compilerOptions.moduleResolution && typeof tsconfig.compilerOptions.moduleResolution === 'string') {
const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase();
if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) {
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[
moduleResolutionKey as keyof typeof plugins.typescript.ModuleResolutionKind
];
} else if (moduleResolutionKey === 'NODENEXT') {
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeNext;
}
}
// Apply path transformations (ts_ → dist_ts_)
if (tsconfig.compilerOptions.paths) { if (tsconfig.compilerOptions.paths) {
returnObject.paths = { ...tsconfig.compilerOptions.paths }; returnObject.paths = { ...tsconfig.compilerOptions.paths };
for (const path of Object.keys(returnObject.paths)) { for (const path of Object.keys(returnObject.paths)) {
@@ -84,57 +121,23 @@ export class TsBuild {
} }
} }
// Process target
if (tsconfig.compilerOptions.target) {
if (typeof tsconfig.compilerOptions.target === 'string') {
const targetKey = tsconfig.compilerOptions.target.toUpperCase();
if (targetKey in plugins.typescript.ScriptTarget) {
returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget];
}
}
}
// Process module
if (tsconfig.compilerOptions.module) {
if (typeof tsconfig.compilerOptions.module === 'string') {
const moduleKey = tsconfig.compilerOptions.module.toUpperCase();
if (moduleKey in plugins.typescript.ModuleKind) {
returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind];
} else if (moduleKey === 'NODENEXT') {
returnObject.module = plugins.typescript.ModuleKind.NodeNext;
}
}
}
// Process moduleResolution
if (tsconfig.compilerOptions.moduleResolution) {
if (typeof tsconfig.compilerOptions.moduleResolution === 'string') {
const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase();
if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) {
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[
moduleResolutionKey as keyof typeof plugins.typescript.ModuleResolutionKind
];
} else if (moduleResolutionKey === 'NODENEXT') {
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeNext;
}
}
}
// Copy boolean options directly
const booleanOptions = [
'experimentalDecorators', 'useDefineForClassFields',
'esModuleInterop', 'verbatimModuleSyntax'
];
for (const option of booleanOptions) {
if (option in tsconfig.compilerOptions) {
(returnObject as any)[option] = (tsconfig.compilerOptions as any)[option];
}
}
return returnObject; 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
*/ */
@@ -162,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 = {},
@@ -169,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;
@@ -309,10 +320,17 @@ 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) {
console.log('\n⚠ WARNING ⚠️'); if (this.argvArg?.confirmskiplibcheck) {
console.log('You are skipping libcheck... Is that really wanted?'); console.log('\n⚠ WARNING ⚠️');
console.log('Continuing in 5 seconds...\n'); console.log('You are skipping libcheck... Is that really wanted?');
await plugins.smartdelay.delayFor(5000); 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 // Enhanced logging with task info
@@ -382,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;
@@ -393,10 +413,16 @@ export class TsBuild {
*/ */
public async compile(): Promise<any[]> { public async compile(): Promise<any[]> {
if (this.options.skipLibCheck) { if (this.options.skipLibCheck) {
console.log('\n⚠ WARNING ⚠️'); if (this.argvArg?.confirmskiplibcheck) {
console.log('You are skipping libcheck... Is that really wanted?'); console.log('\n⚠ WARNING ⚠️');
console.log('Continuing in 5 seconds...\n'); console.log('You are skipping libcheck... Is that really wanted?');
await plugins.smartdelay.delayFor(5000); 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...`); console.log(`🔨 Compiling ${this.fileNames.length} files...`);
@@ -412,7 +438,8 @@ export class TsBuild {
this.displayErrorSummary(preEmitErrorSummary); 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
@@ -438,7 +465,8 @@ export class TsBuild {
this.displayErrorSummary(emitErrorSummary); 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;

View File

@@ -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);
}
}); });
/** /**

View File

@@ -130,12 +130,16 @@ export let compileGlobStringObject = async (
const totalTasks = Object.keys(globStringObjectArg).length; const totalTasks = Object.keys(globStringObjectArg).length;
let currentTask = 0; let currentTask = 0;
// Log the compilation tasks in a nice format // Log the compilation tasks in a nice format (skip for --quiet or --json)
console.log(`\n👷 TypeScript Compilation Tasks (${totalTasks} task${totalTasks !== 1 ? 's' : ''}):`); const isQuiet = argvArg?.quiet === true;
Object.entries(globStringObjectArg).forEach(([source, dest]) => { const isJson = argvArg?.json === true;
console.log(` 📂 ${source}${dest}`); if (!isQuiet && !isJson) {
}); console.log(`\n👷 TypeScript Compilation Tasks (${totalTasks} task${totalTasks !== 1 ? 's' : ''}):`);
console.log(''); Object.entries(globStringObjectArg).forEach(([source, dest]) => {
console.log(` 📂 ${source}${dest}`);
});
console.log('');
}
for (const keyArg in globStringObjectArg) { for (const keyArg in globStringObjectArg) {
// Type safety check for key // Type safety check for key
@@ -185,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);
displayFinalErrorSummary(finalErrorSummary);
// 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; return compiledFiles;
}; };