Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b38ef6cf82 | |||
| 8b50cd3090 | |||
| c6ab493efc | |||
| 82ae8a0e4a | |||
| 787becc4d3 | |||
| 746ca8767a | |||
| 55c1a2953a | |||
| 8e9fcb8135 |
34
changelog.md
34
changelog.md
@@ -1,5 +1,39 @@
|
|||||||
# 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)
|
## 2025-08-18 - 2.6.6 - fix(dependencies)
|
||||||
Update dependency @git.zone/tspublish to ^1.10.2
|
Update dependency @git.zone/tspublish to ^1.10.2
|
||||||
|
|
||||||
|
|||||||
16
package.json
16
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@git.zone/tsbuild",
|
"name": "@git.zone/tsbuild",
|
||||||
"version": "2.6.6",
|
"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.10.2",
|
"@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.7",
|
"@push.rocks/smartfile": "^11.2.7",
|
||||||
"@push.rocks/smartlog": "^3.1.8",
|
"@push.rocks/smartlog": "^3.1.10",
|
||||||
"@push.rocks/smartpath": "^6.0.0",
|
"@push.rocks/smartpath": "^6.0.0",
|
||||||
"@push.rocks/smartpromise": "^4.2.3",
|
"@push.rocks/smartpromise": "^4.2.3",
|
||||||
"typescript": "5.9.2"
|
"typescript": "5.9.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@git.zone/tsrun": "^1.2.47",
|
"@git.zone/tsrun": "^1.6.2",
|
||||||
"@git.zone/tstest": "^2.3.4",
|
"@git.zone/tstest": "^2.7.0",
|
||||||
"@types/node": "^22.15.21"
|
"@types/node": "^22.15.21"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
4183
pnpm-lock.yaml
generated
4183
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
175
readme.hints.md
175
readme.hints.md
@@ -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.
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@git.zone/tsbuild',
|
name: '@git.zone/tsbuild',
|
||||||
version: '2.6.6',
|
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.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)) {
|
||||||
@@ -83,58 +120,24 @@ export class TsBuild {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process target
|
|
||||||
if (tsconfig.compilerOptions.target) {
|
|
||||||
if (typeof tsconfig.compilerOptions.target === 'string') {
|
|
||||||
const targetKey = tsconfig.compilerOptions.target.toUpperCase();
|
|
||||||
if (targetKey in plugins.typescript.ScriptTarget) {
|
|
||||||
returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process module
|
|
||||||
if (tsconfig.compilerOptions.module) {
|
|
||||||
if (typeof tsconfig.compilerOptions.module === 'string') {
|
|
||||||
const moduleKey = tsconfig.compilerOptions.module.toUpperCase();
|
|
||||||
if (moduleKey in plugins.typescript.ModuleKind) {
|
|
||||||
returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind];
|
|
||||||
} else if (moduleKey === 'NODENEXT') {
|
|
||||||
returnObject.module = plugins.typescript.ModuleKind.NodeNext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process moduleResolution
|
|
||||||
if (tsconfig.compilerOptions.moduleResolution) {
|
|
||||||
if (typeof tsconfig.compilerOptions.moduleResolution === 'string') {
|
|
||||||
const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase();
|
|
||||||
if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) {
|
|
||||||
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[
|
|
||||||
moduleResolutionKey as keyof typeof plugins.typescript.ModuleResolutionKind
|
|
||||||
];
|
|
||||||
} else if (moduleResolutionKey === 'NODENEXT') {
|
|
||||||
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeNext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy boolean options directly
|
|
||||||
const booleanOptions = [
|
|
||||||
'experimentalDecorators', 'useDefineForClassFields',
|
|
||||||
'esModuleInterop', 'verbatimModuleSyntax'
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const option of booleanOptions) {
|
|
||||||
if (option in tsconfig.compilerOptions) {
|
|
||||||
(returnObject as any)[option] = (tsconfig.compilerOptions as any)[option];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnObject;
|
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;
|
||||||
@@ -565,4 +593,4 @@ export const checkTypes = async (
|
|||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
const tsBuild = new TsBuild(fileNames, options, argvArg);
|
const tsBuild = new TsBuild(fileNames, options, argvArg);
|
||||||
return tsBuild.checkTypes();
|
return tsBuild.checkTypes();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user