Compare commits

..

34 Commits

Author SHA1 Message Date
4ebc37fa5a 3.1.4 2025-12-13 11:44:20 +00:00
5bfe60927e fix(npmextra.json): update to new format 2025-12-13 11:44:03 +00:00
9e6b91b891 v3.1.3 2025-12-13 09:44:15 +00:00
e40e8f6a77 fix(npmextra): Align npmextra.json package name with package.json (@git.zone/tsbuild) 2025-12-13 09:44:15 +00:00
ebe7afce82 v3.1.2 2025-11-28 08:44:42 +00:00
27aa318054 fix(TsBuild): Set default TypeScript target to ESNext 2025-11-28 08:44:42 +00:00
9a071ce82f v3.1.1 2025-11-27 23:04:13 +00:00
ad227ded73 fix(compiler): Update default TypeScript target to ES2024 2025-11-27 23:04:13 +00:00
c66a941aaf v3.1.0 2025-11-17 12:25:31 +00:00
a3b58dda39 feat(tsbuild.classes): Update default TypeScript lib to lib.esnext.d.ts 2025-11-17 12:25:31 +00:00
4b29107130 v3.0.0 2025-11-17 11:57:32 +00:00
09adbc1965 BREAKING CHANGE(TsBuild): Stop forcing emitDecoratorMetadata in protected compiler defaults 2025-11-17 11:57:32 +00:00
7fb571d4f6 v2.7.3 2025-11-17 11:51:56 +00:00
6b32dced5a fix(tsbuild.classes): Remove duplicate emitDecoratorMetadata from default compiler options and centralize it in protected defaults 2025-11-17 11:51:56 +00:00
df39aa48d0 v2.7.2 2025-11-17 08:08:21 +00:00
a4863bc761 fix(compilerOptions): Remove experimentalDecorators and useDefineForClassFields from default TypeScript compiler options 2025-11-17 08:08:21 +00:00
b38ef6cf82 2.7.1 2025-11-02 06:13:34 +00:00
8b50cd3090 fix(readme): Update documentation: expand README with usage, CLI and API examples; add readme.hints.md project memory 2025-11-02 06:13:34 +00:00
c6ab493efc 2.7.0 2025-11-02 05:31:55 +00:00
82ae8a0e4a feat(tsbuild): Add tsconfig.json support and safer compiler option merging; protect critical options; apply path and enum transforms; bump dependencies. 2025-11-02 05:31:55 +00:00
787becc4d3 2.6.8 2025-08-29 17:14:58 +00:00
746ca8767a fix(tsbuild): Avoid process.exit in library, add confirmskiplibcheck flag, improve CLI exit handling and JSON/quiet modes, update test script 2025-08-29 17:14:58 +00:00
55c1a2953a 2.6.7 2025-08-18 02:19:15 +00:00
8e9fcb8135 fix(tspublish): Bump @git.zone/tspublish dependency to ^1.10.3 2025-08-18 02:19:15 +00:00
18573c777d 2.6.6 2025-08-18 00:32:26 +00:00
fa654b83e3 fix(dependencies): Update dependency @git.zone/tspublish to ^1.10.2 2025-08-18 00:32:26 +00:00
aa3c83cd95 2.6.5 2025-08-18 00:29:51 +00:00
20ed41df42 fix(dependencies): Bump dependencies and add pnpm-workspace configuration 2025-08-18 00:29:51 +00:00
7162476f7f 2.6.4 2025-05-24 00:30:16 +00:00
1b012628eb fix(dependencies): Add .npmrc and update dependency versions for smartfile and tstest 2025-05-24 00:30:16 +00:00
4081086621 2.6.3 2025-05-21 18:06:46 +00:00
b9cf09ccba fix(tsbuild): minor maintenance updates and documentation improvements 2025-05-21 18:06:46 +00:00
8463fbc78a 2.6.2 2025-05-21 17:59:28 +00:00
0164eb51a1 fix(npm configuration): Remove .npmrc file to default npm registry behavior 2025-05-21 17:59:28 +00:00
14 changed files with 4144 additions and 4757 deletions

1
.npmrc
View File

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

View File

@@ -1,5 +1,122 @@
# Changelog # 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) ## 2025-05-21 - 2.6.1 - fix(tsbuild.classes)
Improve error diagnostics handling by removing legacy helper and integrating more robust error summaries in the compilation process Improve error diagnostics handling by removing legacy helper and integrating more robust error summaries in the compilation process

View File

@@ -10,7 +10,7 @@
"gitscope": "gitzone", "gitscope": "gitzone",
"gitrepo": "tsbuild", "gitrepo": "tsbuild",
"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.",
"npmPackagename": "@gitzone/tsbuild", "npmPackagename": "@git.zone/tsbuild",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [
"TypeScript", "TypeScript",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@git.zone/tsbuild", "name": "@git.zone/tsbuild",
"version": "2.6.1", "version": "3.1.4",
"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"
}, },
@@ -29,27 +29,28 @@
"development", "development",
"API" "API"
], ],
"author": "Lossless GmbH", "author": "Task Venture Capital GmbH",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://code.foss.global/git.zone/tsbuild/issues" "url": "https://code.foss.global/git.zone/tsbuild/issues"
}, },
"homepage": "https://code.foss.global/git.zone/tsbuild#README", "homepage": "https://code.foss.global/git.zone/tsbuild#README",
"dependencies": { "dependencies": {
"@git.zone/tspublish": "^1.9.1", "@git.zone/tspublish": "^1.10.3",
"@push.rocks/early": "^4.0.4", "@push.rocks/early": "^4.0.4",
"@push.rocks/smartcli": "^4.0.11", "@push.rocks/smartcli": "^4.0.19",
"@push.rocks/smartdelay": "^3.0.5", "@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartfile": "^11.2.3", "@push.rocks/smartfile": "^13.1.2",
"@push.rocks/smartlog": "^3.1.8", "@push.rocks/smartfs": "^1.2.0",
"@push.rocks/smartpath": "^5.0.18", "@push.rocks/smartlog": "^3.1.10",
"@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.2.3", "@push.rocks/smartpromise": "^4.2.3",
"typescript": "5.8.3" "typescript": "5.9.3"
}, },
"devDependencies": { "devDependencies": {
"@git.zone/tsrun": "^1.2.47", "@git.zone/tsrun": "^2.0.1",
"@git.zone/tstest": "^1.9.0", "@git.zone/tstest": "^3.1.3",
"@types/node": "^22.15.21" "@types/node": "^25.0.1"
}, },
"files": [ "files": [
"ts/**/*", "ts/**/*",

7126
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -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.

1017
readme.md

File diff suppressed because it is too large Load Diff

View File

@@ -6,12 +6,12 @@ early.stop();
import { anExportedString } from './tocompile2.js'; import { anExportedString } from './tocompile2.js';
console.log(anExportedString); console.log(anExportedString);
class test2 { class test2 {
test = [];
constructor() { constructor() {
this.test = [];
console.log('hi'); console.log('hi');
} }
} }
const run = async () => { const run = async () => {
return 'hi'; return 'hi';
}; };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9jb21waWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdG9jb21waWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDcEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUVyQixPQUFPLEtBQUssS0FBSyxNQUFNLG1CQUFtQixDQUFDO0FBRTNDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUNkLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUViLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUU5QixNQUFNLEtBQUs7SUFFVDtRQURBLFNBQUksR0FBYSxFQUFFLENBQUM7UUFFbEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQixDQUFDO0NBQ0Y7QUFFRCxNQUFNLEdBQUcsR0FBRyxLQUFLLElBQXFCLEVBQUU7SUFDdEMsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDLENBQUMifQ== //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9jb21waWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdG9jb21waWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDcEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUVyQixPQUFPLEtBQUssS0FBSyxNQUFNLG1CQUFtQixDQUFDO0FBRTNDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUNkLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUViLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUU5QixNQUFNLEtBQUs7SUFDVCxJQUFJLEdBQWEsRUFBRSxDQUFDO0lBQ3BCO1FBQ0UsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQixDQUFDO0NBQ0Y7QUFFRCxNQUFNLEdBQUcsR0FBRyxLQUFLLElBQXFCLEVBQUU7SUFDdEMsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDLENBQUMifQ==

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@git.zone/tsbuild', name: '@git.zone/tsbuild',
version: '2.6.1', version: '3.1.3',
description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.' description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.'
} }

View File

@@ -1,7 +1,9 @@
// node native // node native
import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
export { export {
fs,
path path
} }
@@ -16,9 +18,66 @@ export {
import * as smartcli from '@push.rocks/smartcli'; import * as smartcli from '@push.rocks/smartcli';
import * as smartdelay from '@push.rocks/smartdelay'; import * as smartdelay from '@push.rocks/smartdelay';
import * as smartfile from '@push.rocks/smartfile'; import * as smartfile from '@push.rocks/smartfile';
import * as smartfsModule from '@push.rocks/smartfs';
import * as smartpath from '@push.rocks/smartpath'; import * as smartpath from '@push.rocks/smartpath';
import * as smartpromise from '@push.rocks/smartpromise'; 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 }; export { smartcli, smartdelay, smartfile, smartpath, smartpromise };
// third party scope // third party scope

View File

@@ -18,18 +18,15 @@ export interface IErrorSummary {
*/ */
export const compilerOptionsDefault: CompilerOptions = { export const compilerOptionsDefault: CompilerOptions = {
declaration: true, declaration: true,
emitDecoratorMetadata: true,
experimentalDecorators: true,
inlineSourceMap: true, inlineSourceMap: true,
noEmitOnError: true, noEmitOnError: true,
outDir: 'dist_ts/', outDir: 'dist_ts/',
module: plugins.typescript.ModuleKind.NodeNext, module: plugins.typescript.ModuleKind.NodeNext,
target: plugins.typescript.ScriptTarget.ESNext, target: plugins.typescript.ScriptTarget.ESNext,
moduleResolution: plugins.typescript.ModuleResolutionKind.NodeNext, 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 noImplicitAny: false, // Allow implicit any by default
esModuleInterop: true, esModuleInterop: true,
useDefineForClassFields: false,
verbatimModuleSyntax: true, verbatimModuleSyntax: true,
baseUrl: './', baseUrl: './',
}; };
@@ -62,41 +59,37 @@ 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 {
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) { if (!tsconfig || !tsconfig.compilerOptions) {
return returnObject; return {};
} }
// Process baseUrl // Start by copying ALL compiler options from tsconfig.json
if (tsconfig.compilerOptions.baseUrl) { const returnObject: CompilerOptions = { ...tsconfig.compilerOptions };
returnObject.baseUrl = tsconfig.compilerOptions.baseUrl;
}
// Process paths // Apply special transformations for string-to-enum conversions
if (tsconfig.compilerOptions.paths) {
returnObject.paths = { ...tsconfig.compilerOptions.paths };
for (const path of Object.keys(returnObject.paths)) {
if (Array.isArray(returnObject.paths[path]) && returnObject.paths[path].length > 0) {
returnObject.paths[path][0] = returnObject.paths[path][0].replace('./ts_', './dist_ts_');
}
}
}
// Process target // Process target (convert string to enum)
if (tsconfig.compilerOptions.target) { if (tsconfig.compilerOptions.target && typeof tsconfig.compilerOptions.target === 'string') {
if (typeof tsconfig.compilerOptions.target === 'string') {
const targetKey = tsconfig.compilerOptions.target.toUpperCase(); const targetKey = tsconfig.compilerOptions.target.toUpperCase();
if (targetKey in plugins.typescript.ScriptTarget) { if (targetKey in plugins.typescript.ScriptTarget) {
returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget]; returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget];
} }
} }
}
// Process module // Process module (convert string to enum)
if (tsconfig.compilerOptions.module) { if (tsconfig.compilerOptions.module && typeof tsconfig.compilerOptions.module === 'string') {
if (typeof tsconfig.compilerOptions.module === 'string') {
const moduleKey = tsconfig.compilerOptions.module.toUpperCase(); const moduleKey = tsconfig.compilerOptions.module.toUpperCase();
if (moduleKey in plugins.typescript.ModuleKind) { if (moduleKey in plugins.typescript.ModuleKind) {
returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind]; returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind];
@@ -104,11 +97,9 @@ export class TsBuild {
returnObject.module = plugins.typescript.ModuleKind.NodeNext; returnObject.module = plugins.typescript.ModuleKind.NodeNext;
} }
} }
}
// Process moduleResolution // Process moduleResolution (convert string to enum)
if (tsconfig.compilerOptions.moduleResolution) { if (tsconfig.compilerOptions.moduleResolution && typeof tsconfig.compilerOptions.moduleResolution === 'string') {
if (typeof tsconfig.compilerOptions.moduleResolution === 'string') {
const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase(); const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase();
if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) { if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) {
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[ returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[
@@ -118,23 +109,33 @@ export class TsBuild {
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeNext; returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeNext;
} }
} }
// Apply path transformations (ts_ → dist_ts_)
if (tsconfig.compilerOptions.paths) {
returnObject.paths = { ...tsconfig.compilerOptions.paths };
for (const path of Object.keys(returnObject.paths)) {
if (Array.isArray(returnObject.paths[path]) && returnObject.paths[path].length > 0) {
returnObject.paths[path][0] = returnObject.paths[path][0].replace('./ts_', './dist_ts_');
} }
// Copy boolean options directly
const booleanOptions = [
'experimentalDecorators', 'useDefineForClassFields',
'esModuleInterop', 'verbatimModuleSyntax'
];
for (const option of booleanOptions) {
if (option in tsconfig.compilerOptions) {
(returnObject as any)[option] = (tsconfig.compilerOptions as any)[option];
} }
} }
return returnObject; return returnObject;
} }
/**
* Returns critical default options that should not be overridden by tsconfig.json
* These options are essential for tsbuild's functionality and build integrity
*/
private getCriticalDefaults(): CompilerOptions {
return {
outDir: 'dist_ts/', // Required for path transformation logic
noEmitOnError: true, // Build integrity - prevent broken builds
declaration: true, // Library consumers depend on .d.ts files
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 +163,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 +177,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 +318,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) {
if (this.argvArg?.confirmskiplibcheck) {
console.log('\n⚠ WARNING ⚠️'); console.log('\n⚠ WARNING ⚠️');
console.log('You are skipping libcheck... Is that really wanted?'); console.log('You are skipping libcheck... Is that really wanted?');
console.log('Continuing in 5 seconds...\n'); console.log('Continuing in 5 seconds...\n');
await plugins.smartdelay.delayFor(5000); await plugins.smartdelay.delayFor(5000);
} else {
// No delay by default; keep a short note unless in quiet/json modes
if (!this.argvArg?.quiet && !this.argvArg?.json) {
console.log('⚠️ skipLibCheck enabled; use --confirmskiplibcheck to pause with warning.');
}
}
} }
// Enhanced logging with task info // Enhanced logging with task info
@@ -382,7 +398,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 +411,16 @@ export class TsBuild {
*/ */
public async compile(): Promise<any[]> { public async compile(): Promise<any[]> {
if (this.options.skipLibCheck) { if (this.options.skipLibCheck) {
if (this.argvArg?.confirmskiplibcheck) {
console.log('\n⚠ WARNING ⚠️'); console.log('\n⚠ WARNING ⚠️');
console.log('You are skipping libcheck... Is that really wanted?'); console.log('You are skipping libcheck... Is that really wanted?');
console.log('Continuing in 5 seconds...\n'); console.log('Continuing in 5 seconds...\n');
await plugins.smartdelay.delayFor(5000); await plugins.smartdelay.delayFor(5000);
} else {
if (!this.argvArg?.quiet && !this.argvArg?.json) {
console.log('⚠️ skipLibCheck enabled; use --confirmskiplibcheck to pause with warning.');
}
}
} }
console.log(`🔨 Compiling ${this.fileNames.length} files...`); console.log(`🔨 Compiling ${this.fileNames.length} files...`);
@@ -412,7 +436,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 +463,8 @@ export class TsBuild {
this.displayErrorSummary(emitErrorSummary); this.displayErrorSummary(emitErrorSummary);
console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!'); console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!');
console.error(' No output files have been generated.\n'); console.error(' No output files have been generated.\n');
process.exit(exitCode); // Throw instead of exiting to keep library pure
throw new Error('TypeScript emit failed.');
} }
return done.promise; return done.promise;

View File

@@ -9,7 +9,7 @@ export const runCli = async () => {
* the standard task compiles anything in ts/ directory to dist directory * the standard task compiles anything in ts/ directory to dist directory
*/ */
tsbuildCli.standardCommand().subscribe(async (argvArg) => { tsbuildCli.standardCommand().subscribe(async (argvArg) => {
tsbuild.compileGlobStringObject( await tsbuild.compileGlobStringObject(
{ {
'./ts/**/*.ts': './dist_ts', './ts/**/*.ts': './dist_ts',
}, },
@@ -17,6 +17,10 @@ export const runCli = async () => {
process.cwd(), process.cwd(),
argvArg argvArg
); );
const summary = (argvArg as any)?.__tsbuildFinalErrorSummary;
if (summary && summary.totalErrors > 0) {
process.exit(1);
}
}); });
/** /**
@@ -30,6 +34,10 @@ export const runCli = async () => {
compilationCommandObject[`./${directory}/**/*.ts`] = `./dist_${directory}`; compilationCommandObject[`./${directory}/**/*.ts`] = `./dist_${directory}`;
} }
await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg); await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
const summary = (argvArg as any)?.__tsbuildFinalErrorSummary;
if (summary && summary.totalErrors > 0) {
process.exit(1);
}
}); });
/** /**
@@ -55,12 +63,7 @@ export const runCli = async () => {
// Handle as glob pattern // Handle as glob pattern
console.log(`Processing glob pattern: ${pattern}`); console.log(`Processing glob pattern: ${pattern}`);
try { try {
const matchedFiles = await plugins.smartfile.fs.listFileTree(cwd, pattern); const stringMatchedFiles = await plugins.listFilesWithGlob(cwd, pattern);
// Ensure matchedFiles contains only strings
const stringMatchedFiles = Array.isArray(matchedFiles)
? matchedFiles.filter((item): item is string => typeof item === 'string')
: [];
if (stringMatchedFiles.length === 0) { if (stringMatchedFiles.length === 0) {
console.warn(`⚠️ Warning: No files matched the pattern '${pattern}'`); console.warn(`⚠️ Warning: No files matched the pattern '${pattern}'`);
@@ -85,10 +88,10 @@ export const runCli = async () => {
? pattern ? pattern
: plugins.path.join(cwd, pattern); : plugins.path.join(cwd, pattern);
try { const fileExists = await plugins.smartfs.file(filePath).exists();
await plugins.smartfile.fs.fileExists(filePath); if (fileExists) {
allFiles.push(filePath); allFiles.push(filePath);
} catch (err) { } else {
console.error(`❌ Error: File not found: ${filePath}`); console.error(`❌ Error: File not found: ${filePath}`);
process.exit(1); process.exit(1);
} }
@@ -120,7 +123,11 @@ export const runCli = async () => {
* the custom command compiles any customDir to dist_customDir * the custom command compiles any customDir to dist_customDir
*/ */
tsbuildCli.addCommand('tsfolders').subscribe(async (argvArg) => { 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' // 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}`; 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);
}
}); });
/** /**
@@ -196,10 +207,7 @@ export const runCli = async () => {
// First check ts/**/* without skiplibcheck // First check ts/**/* without skiplibcheck
console.log('📂 Checking ts/**/* files...'); console.log('📂 Checking ts/**/* files...');
const tsFiles = await plugins.smartfile.fs.listFileTree(process.cwd(), 'ts/**/*.ts'); const tsTsFiles = await plugins.listFilesWithGlob(process.cwd(), 'ts/**/*.ts');
const tsTsFiles = Array.isArray(tsFiles)
? tsFiles.filter((item): item is string => typeof item === 'string')
: [];
if (tsTsFiles.length > 0) { if (tsTsFiles.length > 0) {
console.log(` Found ${tsTsFiles.length} TypeScript files in ts/`); console.log(` Found ${tsTsFiles.length} TypeScript files in ts/`);
@@ -222,10 +230,7 @@ export const runCli = async () => {
// Then check test/**/* with skiplibcheck // Then check test/**/* with skiplibcheck
console.log('📂 Checking test/**/* files with --skiplibcheck...'); console.log('📂 Checking test/**/* files with --skiplibcheck...');
const testFiles = await plugins.smartfile.fs.listFileTree(process.cwd(), 'test/**/*.ts'); const testTsFiles = await plugins.listFilesWithGlob(process.cwd(), 'test/**/*.ts');
const testTsFiles = Array.isArray(testFiles)
? testFiles.filter((item): item is string => typeof item === 'string')
: [];
if (testTsFiles.length > 0) { if (testTsFiles.length > 0) {
console.log(` Found ${testTsFiles.length} TypeScript files in test/`); console.log(` Found ${testTsFiles.length} TypeScript files in test/`);
@@ -262,12 +267,7 @@ export const runCli = async () => {
// Handle as glob pattern // Handle as glob pattern
console.log(`Processing glob pattern: ${pattern}`); console.log(`Processing glob pattern: ${pattern}`);
try { try {
const matchedFiles = await plugins.smartfile.fs.listFileTree(cwd, pattern); const stringMatchedFiles = await plugins.listFilesWithGlob(cwd, pattern);
// Ensure matchedFiles contains only strings
const stringMatchedFiles = Array.isArray(matchedFiles)
? matchedFiles.filter((item): item is string => typeof item === 'string')
: [];
if (stringMatchedFiles.length === 0) { if (stringMatchedFiles.length === 0) {
console.warn(`⚠️ Warning: No files matched the pattern '${pattern}'`); console.warn(`⚠️ Warning: No files matched the pattern '${pattern}'`);
@@ -292,10 +292,10 @@ export const runCli = async () => {
? pattern ? pattern
: plugins.path.join(cwd, pattern); : plugins.path.join(cwd, pattern);
try { const fileExists = await plugins.smartfs.file(filePath).exists();
await plugins.smartfile.fs.fileExists(filePath); if (fileExists) {
allFiles.push(filePath); allFiles.push(filePath);
} catch (err) { } else {
console.error(`❌ Error: File not found: ${filePath}`); console.error(`❌ Error: File not found: ${filePath}`);
process.exit(1); process.exit(1);
} }

View File

@@ -130,24 +130,23 @@ 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)
const isQuiet = argvArg?.quiet === true;
const isJson = argvArg?.json === true;
if (!isQuiet && !isJson) {
console.log(`\n👷 TypeScript Compilation Tasks (${totalTasks} task${totalTasks !== 1 ? 's' : ''}):`); console.log(`\n👷 TypeScript Compilation Tasks (${totalTasks} task${totalTasks !== 1 ? 's' : ''}):`);
Object.entries(globStringObjectArg).forEach(([source, dest]) => { Object.entries(globStringObjectArg).forEach(([source, dest]) => {
console.log(` 📂 ${source}${dest}`); console.log(` 📂 ${source}${dest}`);
}); });
console.log(''); console.log('');
}
for (const keyArg in globStringObjectArg) { for (const keyArg in globStringObjectArg) {
// Type safety check for key // Type safety check for key
if (keyArg && typeof keyArg === 'string' && globStringObjectArg[keyArg]) { if (keyArg && typeof keyArg === 'string' && globStringObjectArg[keyArg]) {
// Get files matching the glob pattern // Get files matching the glob pattern using helper function
const fileTreeArray = await plugins.smartfile.fs.listFileTree(cwdArg, keyArg); const stringFileTreeArray = await plugins.listFilesWithGlob(cwdArg, keyArg);
// Ensure fileTreeArray contains only strings before transforming
const stringFileTreeArray = Array.isArray(fileTreeArray)
? fileTreeArray.filter((item): item is string => typeof item === 'string')
: [];
// Transform to absolute paths // Transform to absolute paths
const absoluteFilePathArray = plugins.smartpath.transform.toAbsolute( const absoluteFilePathArray = plugins.smartpath.transform.toAbsolute(
@@ -185,7 +184,35 @@ export let compileGlobStringObject = async (
// Display final error summary after all compilation tasks // Display final error summary after all compilation tasks
const finalErrorSummary = mergeErrorSummaries(errorSummaries); const finalErrorSummary = mergeErrorSummaries(errorSummaries);
// Output summary based on mode
if (isJson) {
const result = {
success: finalErrorSummary.totalErrors === 0,
totals: {
errors: finalErrorSummary.totalErrors,
filesWithErrors: finalErrorSummary.totalFiles,
tasks: totalTasks,
},
errorsByFile: Object.fromEntries(
Object.entries(finalErrorSummary.errorsByFile).map(([file, diags]) => [
file,
diags.map(d => ({
code: d.code,
message: plugins.typescript.flattenDiagnosticMessageText(d.messageText as any, '\n'),
}))
])
),
};
console.log(JSON.stringify(result));
} else if (!isQuiet) {
displayFinalErrorSummary(finalErrorSummary); displayFinalErrorSummary(finalErrorSummary);
}
// Attach summary to argvArg so CLI can decide exit behavior
if (argvArg && typeof argvArg === 'object') {
(argvArg as any).__tsbuildFinalErrorSummary = finalErrorSummary;
}
return compiledFiles; return compiledFiles;
}; };

View File

@@ -1,7 +1,5 @@
{ {
"compilerOptions": { "compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false,
"target": "ES2022", "target": "ES2022",
"module": "NodeNext", "module": "NodeNext",
"moduleResolution": "NodeNext", "moduleResolution": "NodeNext",