Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ebc37fa5a | |||
| 5bfe60927e | |||
| 9e6b91b891 | |||
| e40e8f6a77 | |||
| ebe7afce82 | |||
| 27aa318054 | |||
| 9a071ce82f | |||
| ad227ded73 | |||
| c66a941aaf | |||
| a3b58dda39 | |||
| 4b29107130 | |||
| 09adbc1965 | |||
| 7fb571d4f6 | |||
| 6b32dced5a | |||
| df39aa48d0 | |||
| a4863bc761 | |||
| b38ef6cf82 | |||
| 8b50cd3090 | |||
| 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 |
155
changelog.md
155
changelog.md
@@ -1,5 +1,160 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-12-13 - 3.1.3 - fix(npmextra)
|
||||
Align npmextra.json package name with package.json (@git.zone/tsbuild)
|
||||
|
||||
- Corrected npmPackagename in npmextra.json from "@gitzone/tsbuild" to "@git.zone/tsbuild" to match package.json and README
|
||||
- Metadata-only change: no code or API behavior affected
|
||||
|
||||
## 2025-11-28 - 3.1.2 - fix(TsBuild)
|
||||
Set default TypeScript target to ESNext
|
||||
|
||||
- Default compiler target changed from ScriptTarget.ES2024 to ScriptTarget.ESNext in ts/tsbuild.classes.tsbuild.ts
|
||||
- Aligns the default compiler options with documentation and ensures use of the latest language features
|
||||
|
||||
## 2025-11-27 - 3.1.1 - fix(compiler)
|
||||
Update default TypeScript target to ES2024
|
||||
|
||||
- Default compiler option 'target' changed from ScriptTarget.ESNext to ScriptTarget.ES2024 in ts/tsbuild.classes.tsbuild.ts
|
||||
- Aligns emitted code to ES2024 language features by default
|
||||
|
||||
## 2025-11-17 - 3.1.0 - feat(tsbuild.classes)
|
||||
Update default TypeScript lib to lib.esnext.d.ts
|
||||
|
||||
- Changed default compilerOptions.lib from ['lib.dom.d.ts', 'lib.es2022.d.ts'] to ['lib.dom.d.ts', 'lib.esnext.d.ts'] in compilerOptionsDefault.
|
||||
- Allows newer ECMAScript/DOM features by default when compiling with tsbuild (affects emitted types and available globals).
|
||||
- Behavioral default change only — no public API changes; callers can still override lib via tsconfig, programmatic options, or CLI.
|
||||
|
||||
## 2025-11-17 - 3.0.0 - BREAKING CHANGE(TsBuild)
|
||||
Stop forcing emitDecoratorMetadata in protected compiler defaults
|
||||
|
||||
- Removed emitDecoratorMetadata from the set of protected/critical default compiler options.
|
||||
- Projects that relied on tsbuild automatically enabling emitDecoratorMetadata (for DI frameworks like NestJS, TypeORM, Inversify) must now enable it explicitly in their tsconfig.json or via programmatic/CLI options.
|
||||
- No other protected defaults were changed; outDir, noEmitOnError, declaration and inlineSourceMap remain enforced.
|
||||
- Behavior is now more permissive: decorator metadata generation is controlled by user configuration rather than being forced by tsbuild.
|
||||
|
||||
## 2025-11-17 - 2.7.3 - fix(tsbuild.classes)
|
||||
Remove duplicate emitDecoratorMetadata from default compiler options and centralize it in protected defaults
|
||||
|
||||
- Removed emitDecoratorMetadata from compilerOptionsDefault in ts/tsbuild.classes.tsbuild.ts to avoid duplicate configuration.
|
||||
- emitDecoratorMetadata remains enforced via getCriticalDefaults(), ensuring decorator metadata support is protected from tsconfig.json overrides.
|
||||
- Prevents inconsistencies during compiler option merging by centralizing the decorator-related setting.
|
||||
|
||||
## 2025-11-17 - 2.7.2 - fix(compilerOptions)
|
||||
Remove experimentalDecorators and useDefineForClassFields from default TypeScript compiler options
|
||||
|
||||
- Removed experimentalDecorators from compilerOptionsDefault in ts/tsbuild.classes.tsbuild.ts
|
||||
- Removed useDefineForClassFields from compilerOptionsDefault in ts/tsbuild.classes.tsbuild.ts
|
||||
- Default compiler options now rely on TypeScript's upstream defaults for decorator and class field behavior
|
||||
- If your project relies on these settings, re-enable them in your tsconfig.json or pass them via the programmatic API / CLI
|
||||
|
||||
## 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)
|
||||
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
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"gitscope": "gitzone",
|
||||
"gitrepo": "tsbuild",
|
||||
"description": "A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.",
|
||||
"npmPackagename": "@gitzone/tsbuild",
|
||||
"npmPackagename": "@git.zone/tsbuild",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"TypeScript",
|
||||
|
||||
27
package.json
27
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@git.zone/tsbuild",
|
||||
"version": "2.4.1",
|
||||
"version": "3.1.4",
|
||||
"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,7 +10,7 @@
|
||||
"tsbuild": "./cli.js"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tsrun test/test.ts",
|
||||
"test": "tstest test/test.ts --verbose",
|
||||
"build": "node cli.ts.js --web",
|
||||
"buildDocs": "tsdoc"
|
||||
},
|
||||
@@ -29,27 +29,28 @@
|
||||
"development",
|
||||
"API"
|
||||
],
|
||||
"author": "Lossless GmbH",
|
||||
"author": "Task Venture Capital GmbH",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://code.foss.global/git.zone/tsbuild/issues"
|
||||
},
|
||||
"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": "^13.1.2",
|
||||
"@push.rocks/smartfs": "^1.2.0",
|
||||
"@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": "^2.0.1",
|
||||
"@git.zone/tstest": "^3.1.3",
|
||||
"@types/node": "^25.0.1"
|
||||
},
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
|
||||
8604
pnpm-lock.yaml
generated
8604
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
187
readme.hints.md
187
readme.hints.md
@@ -0,0 +1,187 @@
|
||||
# @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@^4.0.19 - CLI framework
|
||||
- @push.rocks/smartfile@^13.1.2 - File content handling (SmartFile, StreamFile, VirtualDirectory)
|
||||
- @push.rocks/smartfs@^1.2.0 - Filesystem operations (file listing, directory listing, etc.)
|
||||
- @push.rocks/smartpath@^6.0.0 - Path transformation utilities
|
||||
- @push.rocks/smartpromise@^4.2.3 - Promise utilities
|
||||
- @push.rocks/smartdelay@^3.0.5 - Delay utilities
|
||||
- typescript@5.9.3 - TypeScript compiler
|
||||
|
||||
### smartfs Migration Notes
|
||||
- smartfile v13+ split filesystem operations to a separate @push.rocks/smartfs package
|
||||
- File listing uses smartfs fluent API: `smartfs.directory(path).recursive().filter(pattern).list()`
|
||||
- File existence checks use: `smartfs.file(path).exists()`
|
||||
- The `listFilesWithGlob()` helper in plugins.ts handles glob pattern parsing for smartfs
|
||||
|
||||
## 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)
|
||||
- 3.1.3 - Current version
|
||||
- Migrated filesystem operations from smartfile to smartfs
|
||||
- Updated @git.zone/tsrun to ^2.0.1
|
||||
- Updated @git.zone/tstest to ^3.1.3
|
||||
- Updated @push.rocks/smartfile to ^13.1.2
|
||||
- Added @push.rocks/smartfs@^1.2.0 for filesystem operations
|
||||
- Updated @types/node to ^25.0.1
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -6,12 +6,12 @@ early.stop();
|
||||
import { anExportedString } from './tocompile2.js';
|
||||
console.log(anExportedString);
|
||||
class test2 {
|
||||
test = [];
|
||||
constructor() {
|
||||
this.test = [];
|
||||
console.log('hi');
|
||||
}
|
||||
}
|
||||
const run = async () => {
|
||||
return 'hi';
|
||||
};
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9jb21waWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdG9jb21waWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDcEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUVyQixPQUFPLEtBQUssS0FBSyxNQUFNLG1CQUFtQixDQUFDO0FBRTNDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUNkLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUViLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUU5QixNQUFNLEtBQUs7SUFFVDtRQURBLFNBQUksR0FBYSxFQUFFLENBQUM7UUFFbEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQixDQUFDO0NBQ0Y7QUFFRCxNQUFNLEdBQUcsR0FBRyxLQUFLLElBQXFCLEVBQUU7SUFDdEMsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDLENBQUMifQ==
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9jb21waWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdG9jb21waWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDcEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUVyQixPQUFPLEtBQUssS0FBSyxNQUFNLG1CQUFtQixDQUFDO0FBRTNDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUNkLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUViLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUU5QixNQUFNLEtBQUs7SUFDVCxJQUFJLEdBQWEsRUFBRSxDQUFDO0lBQ3BCO1FBQ0UsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQixDQUFDO0NBQ0Y7QUFFRCxNQUFNLEdBQUcsR0FBRyxLQUFLLElBQXFCLEVBQUU7SUFDdEMsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDLENBQUMifQ==
|
||||
@@ -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.4.1',
|
||||
version: '3.1.3',
|
||||
description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.'
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// node native
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
export {
|
||||
fs,
|
||||
path
|
||||
}
|
||||
|
||||
@@ -16,9 +18,66 @@ export {
|
||||
import * as smartcli from '@push.rocks/smartcli';
|
||||
import * as smartdelay from '@push.rocks/smartdelay';
|
||||
import * as smartfile from '@push.rocks/smartfile';
|
||||
import * as smartfsModule from '@push.rocks/smartfs';
|
||||
import * as smartpath from '@push.rocks/smartpath';
|
||||
import * as smartpromise from '@push.rocks/smartpromise';
|
||||
|
||||
// Create a smartfs instance with Node.js provider
|
||||
export const smartfs = new smartfsModule.SmartFs(new smartfsModule.SmartFsProviderNode());
|
||||
|
||||
/**
|
||||
* Helper to list files matching a glob pattern like './ts/**\/*.ts'
|
||||
* Parses the pattern to extract base directory and filter pattern
|
||||
*/
|
||||
export async function listFilesWithGlob(basePath: string, globPattern: string): Promise<string[]> {
|
||||
// Remove leading ./ if present
|
||||
let pattern = globPattern.replace(/^\.\//, '');
|
||||
|
||||
// Find the first directory part before any glob characters
|
||||
const globChars = ['*', '?', '{', '['];
|
||||
let baseDir = basePath;
|
||||
|
||||
// Find where the glob pattern starts
|
||||
const parts = pattern.split('/');
|
||||
const staticParts: string[] = [];
|
||||
let filterParts: string[] = [];
|
||||
let foundGlob = false;
|
||||
|
||||
for (const part of parts) {
|
||||
if (!foundGlob && !globChars.some(c => part.includes(c))) {
|
||||
staticParts.push(part);
|
||||
} else {
|
||||
foundGlob = true;
|
||||
filterParts.push(part);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the base directory
|
||||
if (staticParts.length > 0) {
|
||||
baseDir = path.join(basePath, ...staticParts);
|
||||
}
|
||||
|
||||
// Build the filter pattern (just the filename part, ignoring ** for directories)
|
||||
// The recursive() handles the ** part
|
||||
const fileFilter = filterParts[filterParts.length - 1] || '*';
|
||||
|
||||
// Check if we need recursive search
|
||||
const needsRecursive = filterParts.some(p => p === '**' || p.includes('**'));
|
||||
|
||||
let dirBuilder = smartfs.directory(baseDir);
|
||||
if (needsRecursive) {
|
||||
dirBuilder = dirBuilder.recursive();
|
||||
}
|
||||
|
||||
try {
|
||||
const entries = await dirBuilder.filter(fileFilter).list();
|
||||
return entries.filter(e => e.isFile).map(e => e.path);
|
||||
} catch {
|
||||
// Directory doesn't exist or other error
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export { smartcli, smartdelay, smartfile, smartpath, smartpromise };
|
||||
|
||||
// third party scope
|
||||
|
||||
@@ -3,23 +3,30 @@ 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'],
|
||||
lib: ['lib.dom.d.ts', 'lib.esnext.d.ts'],
|
||||
noImplicitAny: false, // Allow implicit any by default
|
||||
esModuleInterop: true,
|
||||
useDefineForClassFields: false,
|
||||
verbatimModuleSyntax: true,
|
||||
baseUrl: './',
|
||||
};
|
||||
@@ -31,6 +38,7 @@ export class TsBuild {
|
||||
private fileNames: string[] = [];
|
||||
private options: plugins.typescript.CompilerOptions;
|
||||
private argvArg?: any;
|
||||
private taskInfo?: any;
|
||||
|
||||
/**
|
||||
* Create a new TsBuild instance
|
||||
@@ -38,10 +46,12 @@ export class TsBuild {
|
||||
constructor(
|
||||
fileNames: string[] = [],
|
||||
customOptions: CompilerOptions = {},
|
||||
argvArg?: any
|
||||
argvArg?: any,
|
||||
taskInfo?: any
|
||||
) {
|
||||
this.fileNames = fileNames;
|
||||
this.argvArg = argvArg;
|
||||
this.taskInfo = taskInfo;
|
||||
this.options = this.mergeCompilerOptions(customOptions, argvArg);
|
||||
}
|
||||
|
||||
@@ -49,41 +59,37 @@ export class TsBuild {
|
||||
* Helper function to read and process tsconfig.json
|
||||
*/
|
||||
private getTsConfigOptions(): CompilerOptions {
|
||||
const tsconfig = plugins.smartfile.fs.toObjectSync(plugins.path.join(paths.cwd, 'tsconfig.json'));
|
||||
const returnObject: CompilerOptions = {};
|
||||
let tsconfig: any;
|
||||
|
||||
// Try to read tsconfig.json, but don't fail if it doesn't exist
|
||||
try {
|
||||
const tsconfigPath = plugins.path.join(paths.cwd, 'tsconfig.json');
|
||||
const tsconfigContent = plugins.fs.readFileSync(tsconfigPath, 'utf8');
|
||||
tsconfig = JSON.parse(tsconfigContent);
|
||||
} catch (error) {
|
||||
// tsconfig.json doesn't exist or is invalid - use defaults
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!tsconfig || !tsconfig.compilerOptions) {
|
||||
return returnObject;
|
||||
return {};
|
||||
}
|
||||
|
||||
// Process baseUrl
|
||||
if (tsconfig.compilerOptions.baseUrl) {
|
||||
returnObject.baseUrl = tsconfig.compilerOptions.baseUrl;
|
||||
}
|
||||
// Start by copying ALL compiler options from tsconfig.json
|
||||
const returnObject: CompilerOptions = { ...tsconfig.compilerOptions };
|
||||
|
||||
// Process paths
|
||||
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_');
|
||||
}
|
||||
}
|
||||
}
|
||||
// Apply special transformations for string-to-enum conversions
|
||||
|
||||
// Process target
|
||||
if (tsconfig.compilerOptions.target) {
|
||||
if (typeof tsconfig.compilerOptions.target === 'string') {
|
||||
// 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
|
||||
if (tsconfig.compilerOptions.module) {
|
||||
if (typeof tsconfig.compilerOptions.module === 'string') {
|
||||
// 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];
|
||||
@@ -91,11 +97,9 @@ export class TsBuild {
|
||||
returnObject.module = plugins.typescript.ModuleKind.NodeNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process moduleResolution
|
||||
if (tsconfig.compilerOptions.moduleResolution) {
|
||||
if (typeof tsconfig.compilerOptions.moduleResolution === 'string') {
|
||||
// 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[
|
||||
@@ -105,23 +109,33 @@ export class TsBuild {
|
||||
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeNext;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply path transformations (ts_ → dist_ts_)
|
||||
if (tsconfig.compilerOptions.paths) {
|
||||
returnObject.paths = { ...tsconfig.compilerOptions.paths };
|
||||
for (const path of Object.keys(returnObject.paths)) {
|
||||
if (Array.isArray(returnObject.paths[path]) && returnObject.paths[path].length > 0) {
|
||||
returnObject.paths[path][0] = returnObject.paths[path][0].replace('./ts_', './dist_ts_');
|
||||
}
|
||||
|
||||
// Copy boolean options directly
|
||||
const booleanOptions = [
|
||||
'experimentalDecorators', 'useDefineForClassFields',
|
||||
'esModuleInterop', 'verbatimModuleSyntax'
|
||||
];
|
||||
|
||||
for (const option of booleanOptions) {
|
||||
if (option in tsconfig.compilerOptions) {
|
||||
(returnObject as any)[option] = (tsconfig.compilerOptions as any)[option];
|
||||
}
|
||||
}
|
||||
|
||||
return returnObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
inlineSourceMap: true, // Consistent debugging experience
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Process command line arguments and return applicable compiler options
|
||||
*/
|
||||
@@ -149,6 +163,13 @@ export class TsBuild {
|
||||
|
||||
/**
|
||||
* Merges compilerOptions with the default compiler options
|
||||
*
|
||||
* Merge order (later overwrites earlier):
|
||||
* 1. compilerOptionsDefault - Base defaults for all options
|
||||
* 2. getTsConfigOptions() - User's tsconfig.json (all options)
|
||||
* 3. getCriticalDefaults() - Protected options that shouldn't be overridden by tsconfig.json
|
||||
* 4. customTsOptions - Programmatic options (can override critical defaults)
|
||||
* 5. getCommandLineOptions() - CLI flags (highest priority)
|
||||
*/
|
||||
public mergeCompilerOptions(
|
||||
customTsOptions: CompilerOptions = {},
|
||||
@@ -156,24 +177,20 @@ export class TsBuild {
|
||||
): CompilerOptions {
|
||||
// create merged options
|
||||
const mergedOptions: CompilerOptions = {
|
||||
...compilerOptionsDefault,
|
||||
...customTsOptions,
|
||||
...this.getCommandLineOptions(argvArg),
|
||||
...this.getTsConfigOptions(),
|
||||
...compilerOptionsDefault, // 1. All defaults
|
||||
...this.getTsConfigOptions(), // 2. User's tsconfig.json (all options)
|
||||
...this.getCriticalDefaults(), // 3. Protected overrides
|
||||
...customTsOptions, // 4. Programmatic options
|
||||
...this.getCommandLineOptions(argvArg), // 5. CLI flags (highest priority)
|
||||
};
|
||||
|
||||
return mergedOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to handle and log TypeScript diagnostics
|
||||
* Helper function to process TypeScript diagnostics and return error summary
|
||||
*/
|
||||
private handleDiagnostics(diagnostics: readonly plugins.typescript.Diagnostic[]): boolean {
|
||||
if (diagnostics.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Group errors by file for better readability
|
||||
private processDiagnostics(diagnostics: readonly plugins.typescript.Diagnostic[]): IErrorSummary {
|
||||
const errorsByFile: Record<string, plugins.typescript.Diagnostic[]> = {};
|
||||
const generalErrors: plugins.typescript.Diagnostic[] = [];
|
||||
|
||||
@@ -190,12 +207,27 @@ export class TsBuild {
|
||||
}
|
||||
});
|
||||
|
||||
// Print error summary header
|
||||
const totalErrorCount = diagnostics.length;
|
||||
const fileCount = Object.keys(errorsByFile).length;
|
||||
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 ${totalErrorCount} error${totalErrorCount !== 1 ? 's' : ''} in ${fileCount} file${fileCount !== 1 ? 's' : ''}:`);
|
||||
console.log(`❌ Found ${totalErrors} error${totalErrors !== 1 ? 's' : ''} in ${totalFiles} file${totalFiles !== 1 ? 's' : ''}:`);
|
||||
console.log('='.repeat(80));
|
||||
|
||||
// Color codes for error formatting
|
||||
@@ -255,10 +287,9 @@ export class TsBuild {
|
||||
}
|
||||
|
||||
console.log('\n' + '='.repeat(80) + '\n');
|
||||
|
||||
return diagnostics.length > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a TypeScript program from file names and options
|
||||
*/
|
||||
@@ -283,14 +314,113 @@ export class TsBuild {
|
||||
}
|
||||
|
||||
/**
|
||||
* The main compiler function that compiles the files
|
||||
* The main compiler function that compiles the files and returns error summary
|
||||
*/
|
||||
public async compile(): Promise<any[]> {
|
||||
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...`);
|
||||
@@ -299,18 +429,20 @@ export class TsBuild {
|
||||
|
||||
// Check for pre-emit diagnostics first
|
||||
const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
|
||||
const hasPreEmitErrors = this.handleDiagnostics(preEmitDiagnostics);
|
||||
const preEmitErrorSummary = this.processDiagnostics(preEmitDiagnostics);
|
||||
|
||||
// Only continue to emit phase if no pre-emit errors
|
||||
if (hasPreEmitErrors) {
|
||||
if (preEmitErrorSummary.totalErrors > 0) {
|
||||
this.displayErrorSummary(preEmitErrorSummary);
|
||||
console.error('\n❌ TypeScript pre-emit checks failed. Please fix the issues listed above before proceeding.');
|
||||
console.error(' 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
|
||||
const emitResult = program.emit();
|
||||
const hasEmitErrors = this.handleDiagnostics(emitResult.diagnostics);
|
||||
const emitErrorSummary = this.processDiagnostics(emitResult.diagnostics);
|
||||
|
||||
const exitCode = emitResult.emitSkipped ? 1 : 0;
|
||||
if (exitCode === 0) {
|
||||
@@ -328,9 +460,11 @@ export class TsBuild {
|
||||
|
||||
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');
|
||||
process.exit(exitCode);
|
||||
// Throw instead of exiting to keep library pure
|
||||
throw new Error('TypeScript emit failed.');
|
||||
}
|
||||
|
||||
return done.promise;
|
||||
@@ -351,18 +485,27 @@ export class TsBuild {
|
||||
|
||||
// Check for pre-emit diagnostics
|
||||
const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
|
||||
const hasPreEmitErrors = this.handleDiagnostics(preEmitDiagnostics);
|
||||
const preEmitErrorSummary = this.processDiagnostics(preEmitDiagnostics);
|
||||
|
||||
// Run the emit phase but with noEmit: true to check for emit errors without producing files
|
||||
const emitResult = program.emit(undefined, undefined, undefined, true);
|
||||
const hasEmitErrors = this.handleDiagnostics(emitResult.diagnostics);
|
||||
const emitErrorSummary = this.processDiagnostics(emitResult.diagnostics);
|
||||
|
||||
const success = !hasPreEmitErrors && !hasEmitErrors && !emitResult.emitSkipped;
|
||||
// Combine error summaries
|
||||
const combinedErrorSummary: IErrorSummary = {
|
||||
errorsByFile: { ...preEmitErrorSummary.errorsByFile, ...emitErrorSummary.errorsByFile },
|
||||
generalErrors: [...preEmitErrorSummary.generalErrors, ...emitErrorSummary.generalErrors],
|
||||
totalErrors: preEmitErrorSummary.totalErrors + emitErrorSummary.totalErrors,
|
||||
totalFiles: Object.keys({ ...preEmitErrorSummary.errorsByFile, ...emitErrorSummary.errorsByFile }).length
|
||||
};
|
||||
|
||||
const success = combinedErrorSummary.totalErrors === 0 && !emitResult.emitSkipped;
|
||||
|
||||
if (success) {
|
||||
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');
|
||||
}
|
||||
@@ -385,15 +528,16 @@ export class TsBuild {
|
||||
|
||||
// Check for type errors
|
||||
const diagnostics = plugins.typescript.getPreEmitDiagnostics(program);
|
||||
const hasErrors = this.handleDiagnostics(diagnostics);
|
||||
const errorSummary = this.processDiagnostics(diagnostics);
|
||||
|
||||
// Set success flag
|
||||
const success = !hasErrors;
|
||||
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');
|
||||
}
|
||||
|
||||
@@ -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,10 @@ 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);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -55,12 +63,7 @@ export const runCli = async () => {
|
||||
// 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')
|
||||
: [];
|
||||
const stringMatchedFiles = await plugins.listFilesWithGlob(cwd, pattern);
|
||||
|
||||
if (stringMatchedFiles.length === 0) {
|
||||
console.warn(`⚠️ Warning: No files matched the pattern '${pattern}'`);
|
||||
@@ -85,10 +88,10 @@ export const runCli = async () => {
|
||||
? pattern
|
||||
: plugins.path.join(cwd, pattern);
|
||||
|
||||
try {
|
||||
await plugins.smartfile.fs.fileExists(filePath);
|
||||
const fileExists = await plugins.smartfs.file(filePath).exists();
|
||||
if (fileExists) {
|
||||
allFiles.push(filePath);
|
||||
} catch (err) {
|
||||
} else {
|
||||
console.error(`❌ Error: File not found: ${filePath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -120,7 +123,11 @@ export const runCli = async () => {
|
||||
* the custom command compiles any customDir to dist_customDir
|
||||
*/
|
||||
tsbuildCli.addCommand('tsfolders').subscribe(async (argvArg) => {
|
||||
const tsFolders = await plugins.smartfile.fs.listFolders(paths.cwd, /^ts/);
|
||||
// List folders matching /^ts/ regex
|
||||
const allEntries = await plugins.smartfs.directory(paths.cwd).list();
|
||||
const tsFolders = allEntries
|
||||
.filter(e => e.isDirectory && /^ts/.test(e.name))
|
||||
.map(e => e.name);
|
||||
|
||||
// Now tsFolders contains all other folders except 'ts_shared' and 'ts_interfaces'
|
||||
|
||||
@@ -182,6 +189,10 @@ export const runCli = async () => {
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -190,12 +201,61 @@ export const runCli = async () => {
|
||||
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.error('\n❌ Error: Please provide at least one TypeScript file path or glob pattern');
|
||||
console.error(' Usage: tsbuild check <file_or_glob_pattern> [additional_patterns ...]\n');
|
||||
console.error(' Example: tsbuild check "src/**/*.ts" "test/**/*.ts"\n');
|
||||
console.log('\n🔬 Running default type checking sequence...\n');
|
||||
|
||||
// First check ts/**/* without skiplibcheck
|
||||
console.log('📂 Checking ts/**/* files...');
|
||||
const tsTsFiles = await plugins.listFilesWithGlob(process.cwd(), 'ts/**/*.ts');
|
||||
|
||||
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 testTsFiles = await plugins.listFilesWithGlob(process.cwd(), 'test/**/*.ts');
|
||||
|
||||
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[] = [];
|
||||
@@ -207,12 +267,7 @@ export const runCli = async () => {
|
||||
// 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')
|
||||
: [];
|
||||
const stringMatchedFiles = await plugins.listFilesWithGlob(cwd, pattern);
|
||||
|
||||
if (stringMatchedFiles.length === 0) {
|
||||
console.warn(`⚠️ Warning: No files matched the pattern '${pattern}'`);
|
||||
@@ -237,10 +292,10 @@ export const runCli = async () => {
|
||||
? pattern
|
||||
: plugins.path.join(cwd, pattern);
|
||||
|
||||
try {
|
||||
await plugins.smartfile.fs.fileExists(filePath);
|
||||
const fileExists = await plugins.smartfs.file(filePath).exists();
|
||||
if (fileExists) {
|
||||
allFiles.push(filePath);
|
||||
} catch (err) {
|
||||
} else {
|
||||
console.error(`❌ Error: File not found: ${filePath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,31 @@ export type { CompilerOptions, ScriptTarget, ModuleKind };
|
||||
|
||||
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,25 +125,28 @@ export let compileGlobStringObject = async (
|
||||
argvArg?: any
|
||||
) => {
|
||||
let compiledFiles: any[] = [];
|
||||
const errorSummaries: import('./tsbuild.classes.tsbuild.js').IErrorSummary[] = [];
|
||||
|
||||
// Log the compilation tasks in a nice format
|
||||
console.log('\n👷 TypeScript Compilation Tasks:');
|
||||
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]) {
|
||||
|
||||
// Get files matching the glob pattern
|
||||
const fileTreeArray = await plugins.smartfile.fs.listFileTree(cwdArg, keyArg);
|
||||
|
||||
// Ensure fileTreeArray contains only strings before transforming
|
||||
const stringFileTreeArray = Array.isArray(fileTreeArray)
|
||||
? fileTreeArray.filter((item): item is string => typeof item === 'string')
|
||||
: [];
|
||||
// Get files matching the glob pattern using helper function
|
||||
const stringFileTreeArray = await plugins.listFilesWithGlob(cwdArg, keyArg);
|
||||
|
||||
// Transform to absolute paths
|
||||
const absoluteFilePathArray = plugins.smartpath.transform.toAbsolute(
|
||||
@@ -69,12 +166,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;
|
||||
};
|
||||
@@ -1,7 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"useDefineForClassFields": false,
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
|
||||
Reference in New Issue
Block a user