From fb6bd614d3b26f22993ff6b5a9c0302b13476ba9 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Sun, 14 Dec 2025 00:19:09 +0000 Subject: [PATCH] fix(TsCompiler): Clear output directories before compilation to ensure clean builds and avoid stale files --- changelog.md | 9 + readme.md | 799 +++++++++----------------- test/assets/output/tocompile.d.ts | 1 - test/assets/output/tocompile.js | 17 - test/assets/output/tocompile2.d.ts | 1 - test/assets/output/tocompile2.js | 3 - ts/00_commitinfo_data.ts | 2 +- ts/mod_compiler/classes.tscompiler.ts | 8 + 8 files changed, 285 insertions(+), 555 deletions(-) delete mode 100644 test/assets/output/tocompile.d.ts delete mode 100644 test/assets/output/tocompile.js delete mode 100644 test/assets/output/tocompile2.d.ts delete mode 100644 test/assets/output/tocompile2.js diff --git a/changelog.md b/changelog.md index b8fe983..c49cc0e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,14 @@ # Changelog +## 2025-12-14 - 4.0.2 - fix(TsCompiler) +Clear output directories before compilation to ensure clean builds and avoid stale files + +- TsCompiler.compileGlob now clears the destination directory (if it exists) before compiling each glob pattern. +- Clearing is logged unless --quiet or --json flags are set (e.g. "๐Ÿงน Clearing output directory: "). +- Uses FsHelpers.removeDirectory to remove previous output, preventing stale or duplicate emitted files. +- Documentation (readme.md) updated to advertise automatic output directory management / clean builds. +- Removed stale compiled test artifacts from test/assets/output to avoid interference with tests. + ## 2025-12-13 - 3.1.3 - fix(npmextra) Align npmextra.json package name with package.json (@git.zone/tsbuild) diff --git a/readme.md b/readme.md index a09b537..00a0136 100644 --- a/readme.md +++ b/readme.md @@ -1,36 +1,29 @@ # @git.zone/tsbuild -> ๐Ÿš€ **A powerful, modern TypeScript build tool with smart defaults and full tsconfig.json support** - -A production-ready TypeScript compiler that combines flexibility with safety. Built for modern JavaScript development with ESNext, NodeNext modules, and automatic decorator support. - -## Why tsbuild? - -- โœ… **Smart tsconfig.json Integration** - Respects all your compiler options with intelligent merging -- โœ… **Protected Defaults** - Critical build settings are safeguarded while staying flexible -- โœ… **Zero Config** - Works perfectly without tsconfig.json -- โœ… **Glob Pattern Support** - Compile multiple directories with a single command -- โœ… **Dependency-Aware** - Automatically orders compilation based on module dependencies -- โœ… **Type Checking** - Validate code without emitting files -- โœ… **CI/CD Ready** - JSON output mode and proper exit codes -- โœ… **Library Safe** - Never calls `process.exit()` in library code -- โœ… **Modern Defaults** - ESNext, NodeNext modules, decorators out of the box - -## Issue Reporting and Security - -For reporting issues or vulnerabilities, please visit our repository at [GitLab](https://code.foss.global/git.zone/tsbuild/issues). +A powerful, modern TypeScript build tool with smart defaults, full tsconfig.json support, and automatic output directory management. ## Install ```bash +# Using pnpm (recommended) +pnpm install @git.zone/tsbuild --save-dev + +# Using npm npm install @git.zone/tsbuild --save-dev ``` -or with pnpm: +## Why tsbuild? -```bash -pnpm install @git.zone/tsbuild --save-dev -``` +- **Smart tsconfig.json Integration** - Respects all your compiler options with intelligent merging +- **Protected Defaults** - Critical build settings are safeguarded while staying flexible +- **Zero Config** - Works perfectly without tsconfig.json +- **Glob Pattern Support** - Compile multiple directories with a single command +- **Dependency-Aware** - Automatically orders compilation based on module dependencies +- **Type Checking** - Validate code without emitting files +- **Clean Builds** - Automatically clears output directories before compilation +- **Auto-Unpack** - Flattens nested output directories automatically +- **CI/CD Ready** - JSON output mode and proper exit codes +- **Modern Defaults** - ESNext, NodeNext modules, decorators out of the box ## Quick Start @@ -40,15 +33,15 @@ pnpm install @git.zone/tsbuild --save-dev ```bash npx tsbuild ``` -Compiles `./ts/**/*.ts` โ†’ `./dist_ts/` +Compiles `./ts/**/*.ts` to `./dist_ts/` **Custom directories:** ```bash npx tsbuild custom src utils ``` Compiles: -- `./src/**/*.ts` โ†’ `./dist_src/` -- `./utils/**/*.ts` โ†’ `./dist_utils/` +- `./src/**/*.ts` to `./dist_src/` +- `./utils/**/*.ts` to `./dist_utils/` **Auto-discover and compile in dependency order:** ```bash @@ -60,44 +53,41 @@ Finds all `ts_*` folders and compiles them respecting dependencies. **Basic compilation:** ```typescript -import { compileFileArray } from '@git.zone/tsbuild'; +import { TsCompiler } from '@git.zone/tsbuild'; -await compileFileArray([ +const compiler = new TsCompiler(); +await compiler.compileFilesOrThrow([ './src/index.ts', './src/utils.ts' -]); +], { outDir: './dist' }); ``` **Production-ready with error tracking (recommended):** ```typescript -import { compileFileArrayWithErrorTracking } from '@git.zone/tsbuild'; +import { TsCompiler } from '@git.zone/tsbuild'; -const result = await compileFileArrayWithErrorTracking([ - './src/**/*.ts' -], { - target: 'ES2022', - module: 'NodeNext' -}); +const compiler = new TsCompiler(); +const result = await compiler.compileFiles([ + './src/index.ts', + './src/utils.ts' +], { outDir: './dist' }); -if (result.hasErrors) { - console.error('Compilation failed!'); - console.error('Files with errors:', result.fileCount); +if (result.errorSummary.totalErrors > 0) { + console.error(`Compilation failed with ${result.errorSummary.totalErrors} errors`); process.exit(1); } -console.log('โœ… Compilation successful!'); +console.log(`Compiled ${result.emittedFiles.length} files successfully!`); ``` -**Advanced glob compilation:** +**Glob pattern compilation:** ```typescript -import { compileGlobStringObject } from '@git.zone/tsbuild'; +import { TsCompiler } from '@git.zone/tsbuild'; -await compileGlobStringObject({ +const compiler = new TsCompiler(); +await compiler.compileGlob({ './ts/**/*.ts': './dist_ts', './ts_web/**/*.ts': './dist_web' -}, { - target: 'ES2022', - module: 'ESNext' }); ``` @@ -112,9 +102,8 @@ npx tsbuild [options] Compiles all TypeScript files from `./ts/` to `./dist_ts/` **Options:** -- `--web` - Include web-specific compilation -- `--skiplibcheck` - Skip type checking of declaration files (shows 5-second warning) -- `--confirmskiplibcheck` - Skip lib check without warning +- `--skiplibcheck` - Skip type checking of declaration files +- `--confirmskiplibcheck` - Skip lib check with extended warning (5s pause) - `--disallowimplicitany` - Disallow implicit `any` types - `--commonjs` - Use CommonJS instead of ESNext modules - `--json` - Output results as JSON (for CI/CD) @@ -130,6 +119,9 @@ npx tsbuild --json --quiet # CommonJS build npx tsbuild --commonjs + +# Strict mode +npx tsbuild --disallowimplicitany ``` ### 2. Custom Directories @@ -140,7 +132,6 @@ npx tsbuild custom ... [options] Compile specific directories to their corresponding `dist_` folders. -**Examples:** ```bash # Compile src and utils npx tsbuild custom src utils @@ -157,18 +148,20 @@ npx tsbuild tsfolders [options] ``` Automatically discovers and compiles all `ts_*` folders in dependency order: -1. Prioritizes `ts_interfaces` and `ts_shared` first -2. Reads `tspublish.json` for `order` property -3. Compiles in correct sequence + +1. Prioritizes `ts_interfaces` first (if no tspublish.json) +2. Prioritizes `ts_shared` second (if no tspublish.json) +3. Reads `tspublish.json` in each folder for `order` property +4. Compiles in correct sequence **Example output:** ``` -compiling in this order: -[ 'ts_interfaces', 'ts_shared', 'ts_core', 'ts_utils', 'ts_modules' ] - -๐Ÿ”จ [1/5] Compiling ts_interfaces... -โœ… [1/5] Task completed in 1234ms -... +TypeScript Folder Compilation Plan (5 folders) + 1/5 ts_interfaces + 2/5 ts_shared + 3/5 ts_core + 4/5 ts_utils + 5/5 ts_modules ``` ### 4. Emit Check @@ -179,16 +172,12 @@ npx tsbuild emitcheck [more...] [options] Validates TypeScript files can be compiled without actually emitting them. -**Examples:** ```bash # Check specific files npx tsbuild emitcheck src/main.ts src/utils.ts # Check with glob patterns npx tsbuild emitcheck "src/**/*.ts" "test/**/*.ts" - -# CI/CD usage -npx tsbuild emitcheck "**/*.ts" --json ``` **Exit codes:** @@ -198,206 +187,215 @@ npx tsbuild emitcheck "**/*.ts" --json ### 5. Type Check ```bash -npx tsbuild check [more...] [options] +npx tsbuild check [pattern] [more...] [options] ``` -Performs type checking without emitting files. Faster than emitcheck. +Performs type checking without emitting files. -**Examples:** +**With arguments:** Check specified files/patterns ```bash -# Check all TypeScript files npx tsbuild check "ts/**/*.ts" - -# Check multiple patterns npx tsbuild check "src/**/*.ts" "test/**/*.ts" +``` -# Check with specific options -npx tsbuild check "**/*.ts" --disallowimplicitany +**Without arguments:** Two-phase default check +1. Phase 1: Type check `ts/**/*` (strict, includes .d.ts) +2. Phase 2: Type check `test/**/*` (relaxed, skipLibCheck: true) + +```bash +npx tsbuild check +# Running default type checking sequence... +# Checking ts/**/* files... +# Checking test/**/* files with --skiplibcheck... +# All default type checks passed! ``` ## API Reference -### Core Functions +### TsCompiler Class -#### `compileFileArray(files, options?, argv?)` +The main class for TypeScript compilation. -Basic compilation of file array. - -**Parameters:** -- `files: string[]` - File paths to compile -- `options?: CompilerOptions` - TypeScript compiler options -- `argv?: any` - CLI arguments object - -**Returns:** `Promise` - Compiled file results - -**Example:** ```typescript -import { compileFileArray } from '@git.zone/tsbuild'; +import { TsCompiler } from '@git.zone/tsbuild'; -await compileFileArray( - ['./src/index.ts', './src/utils.ts'], - { target: 'ES2022' } -); +const compiler = new TsCompiler(cwd?: string, argvArg?: any); ``` -#### `compileFileArrayWithErrorTracking(files, options?, argv?, taskInfo?)` +**Constructor Parameters:** +- `cwd` - Working directory (defaults to `process.cwd()`) +- `argvArg` - CLI arguments object for flags like `--skiplibcheck`, `--quiet`, etc. -**โญ RECOMMENDED for production** - Provides detailed error tracking and metrics. +#### compileFiles(fileNames, customOptions?, taskInfo?) -**Parameters:** -- `files: string[]` - File paths to compile -- `options?: CompilerOptions` - TypeScript compiler options -- `argv?: any` - CLI arguments object -- `taskInfo?: ITaskInfo` - Task metadata for progress reporting +Compile files with error tracking. Returns result instead of throwing. -**Returns:** `Promise` - Detailed error summary - -**IErrorSummary Interface:** ```typescript +const result = await compiler.compileFiles( + ['./src/index.ts', './src/utils.ts'], + { outDir: './dist' } +); + +console.log(`Emitted: ${result.emittedFiles.length} files`); +console.log(`Errors: ${result.errorSummary.totalErrors}`); +``` + +**Returns:** `Promise` + +```typescript +interface ICompileResult { + emittedFiles: string[]; + errorSummary: IErrorSummary; +} + interface IErrorSummary { - hasErrors: boolean; - errorCount: number; - fileCount: number; errorsByFile: Record; generalErrors: Diagnostic[]; + totalErrors: number; + totalFiles: number; } ``` -**Example:** +#### compileFilesOrThrow(fileNames, customOptions?) + +Compile files and throw on error. For simple scripts. + ```typescript -import { compileFileArrayWithErrorTracking } from '@git.zone/tsbuild'; - -const result = await compileFileArrayWithErrorTracking( - ['./src/**/*.ts'], - { target: 'ES2022', strict: true } -); - -if (result.hasErrors) { - console.error(`โŒ ${result.errorCount} errors in ${result.fileCount} files`); - - // Show errors by file - for (const [file, errors] of Object.entries(result.errorsByFile)) { - console.error(`\n${file}:`); - errors.forEach(err => console.error(` - ${err.messageText}`)); - } - +try { + const emittedFiles = await compiler.compileFilesOrThrow( + ['./src/index.ts'], + { outDir: './dist' } + ); + console.log('Compiled:', emittedFiles); +} catch (error) { + console.error('Compilation failed!'); process.exit(1); } - -console.log('โœ… Compilation successful!'); ``` -#### `compileGlobStringObject(globObject, options?, cwd?, argv?)` +**Returns:** `Promise` - Array of emitted file paths -**Most powerful API** - Compile multiple glob patterns to different destinations. +#### compileGlob(globPatterns, customOptions?) -**Parameters:** -- `globObject: Record` - Maps glob patterns to output directories -- `options?: CompilerOptions` - TypeScript compiler options -- `cwd?: string` - Working directory (defaults to `process.cwd()`) -- `argv?: any` - CLI arguments object +Compile multiple glob patterns to different destinations. Automatically clears output directories before compilation and unpacks nested output. -**Returns:** `Promise` - Array of compilation results - -**Example:** ```typescript -import { compileGlobStringObject } from '@git.zone/tsbuild'; - -await compileGlobStringObject( - { - './ts/**/*.ts': './dist_ts', - './ts_web/**/*.ts': './dist_web', - './ts_node/**/*.ts': './dist_node' - }, - { - target: 'ES2022', - module: 'NodeNext' - } -); +const result = await compiler.compileGlob({ + './ts/**/*.ts': './dist_ts', + './ts_web/**/*.ts': './dist_web', + './ts_node/**/*.ts': './dist_node' +}); ``` -#### `checkTypes(files, options?, argv?)` +**Returns:** `Promise` + +#### checkTypes(fileNames, customOptions?) Type check files without emitting. Fast validation. -**Parameters:** -- `files: string[]` - Files to check -- `options?: CompilerOptions` - Compiler options -- `argv?: any` - CLI arguments - -**Returns:** `Promise` - Error summary - -**Example:** ```typescript -import { checkTypes } from '@git.zone/tsbuild'; +const success = await compiler.checkTypes(['./src/**/*.ts']); -const result = await checkTypes(['./src/**/*.ts']); - -if (result.hasErrors) { +if (!success) { console.error('Type errors found!'); process.exit(1); } ``` -#### `emitCheck(files, options?, argv?)` +**Returns:** `Promise` - `true` if no errors + +#### checkEmit(fileNames, customOptions?) Validate files can be emitted without actually emitting. -**Example:** ```typescript -import { emitCheck } from '@git.zone/tsbuild'; +const canEmit = await compiler.checkEmit(['./src/index.ts']); -const result = await emitCheck(['./src/index.ts']); - -if (result.hasErrors) { +if (!canEmit) { console.error('Cannot emit these files!'); } ``` -### TsBuild Class +**Returns:** `Promise` - `true` if can emit -Object-oriented API with full control. +#### createOptions(customOptions?) + +Get merged compiler options (useful for debugging). -**Constructor:** ```typescript -new TsBuild( - fileNames?: string[], - customOptions?: CompilerOptions, - argvArg?: any, - taskInfo?: ITaskInfo -) +const options = compiler.createOptions({ strict: true }); +console.log(options); // Shows merged options ``` -**Methods:** -- `compile()` - Compile and emit files -- `compileWithErrorTracking()` - Compile with detailed error summary -- `checkTypes()` - Type check without emitting -- `emitCheck()` - Validate emit capability -- `mergeCompilerOptions()` - Merge options (public utility) +### Supporting Classes + +#### TsConfig + +TypeScript configuration management. -**Example:** ```typescript -import { TsBuild } from '@git.zone/tsbuild'; +import { TsConfig } from '@git.zone/tsbuild'; -const builder = new TsBuild( - ['./src/**/*.ts'], - { target: 'ES2022', strict: true } -); +const config = new TsConfig(process.cwd()); +const options = config.merge({ target: 'ES2022' }, argvArg); +``` -const result = await builder.compileWithErrorTracking(); +#### TsPublishConfig -if (result.hasErrors) { - console.error('Build failed!'); -} +Reads `tspublish.json` for module configuration. + +```typescript +import { TsPublishConfig } from '@git.zone/tsbuild'; + +const pubConfig = new TsPublishConfig('./ts_core'); +console.log(pubConfig.shouldUnpack); // true/false +console.log(pubConfig.order); // number or undefined +``` + +#### TsUnpacker + +Flattens nested TypeScript output directories. + +```typescript +import { TsUnpacker } from '@git.zone/tsbuild'; + +const unpacker = new TsUnpacker('./dist_ts', './ts'); +await unpacker.unpack(); +``` + +#### FsHelpers + +Static filesystem utilities. + +```typescript +import { FsHelpers } from '@git.zone/tsbuild'; + +const files = await FsHelpers.listFilesWithGlob('./', 'ts/**/*.ts'); +const exists = await FsHelpers.fileExists('./tsconfig.json'); +const dirExists = await FsHelpers.directoryExists('./ts'); +``` + +#### TsBuildCli + +CLI command handler. Used internally by the CLI. + +```typescript +import { TsBuildCli, runCli } from '@git.zone/tsbuild'; + +// Run the CLI +runCli(); + +// Or with custom working directory +const cli = new TsBuildCli('/path/to/project'); +cli.run(); ``` ## Configuration ### tsconfig.json Support -tsbuild **fully supports** all compiler options from `tsconfig.json`. Your project configuration is respected and intelligently merged. +tsbuild fully supports all compiler options from `tsconfig.json`. Your project configuration is respected and intelligently merged. -**Example tsconfig.json:** ```json { "compilerOptions": { @@ -413,7 +411,7 @@ tsbuild **fully supports** all compiler options from `tsconfig.json`. Your proje } ``` -### Configuration Priority (Merge Order) +### Configuration Priority (5 Levels) When multiple configuration sources exist, they merge in this order (later overrides earlier): @@ -423,39 +421,18 @@ When multiple configuration sources exist, they merge in this order (later overr 4. **Programmatic Options** - Options passed to API functions 5. **CLI Flags** - Command-line arguments (highest priority) -**Example:** -```typescript -// tsconfig.json has: { "target": "ES2020" } -// You call: -await compileFileArray(files, { target: 'ES2022' }); - -// Result: Uses ES2022 (programmatic overrides tsconfig.json) -``` - ### Protected Options -To ensure build integrity, these options are protected from tsconfig.json override (but can be overridden programmatically or via CLI): +These options cannot be overridden by tsconfig.json alone (but can be overridden programmatically or via CLI): - **`outDir: 'dist_ts/'`** - Required for automatic path transformations - **`noEmitOnError: true`** - Prevents broken builds from being emitted - **`declaration: true`** - Ensures `.d.ts` files for library consumers -- **`emitDecoratorMetadata: true`** - Required for DI frameworks - **`inlineSourceMap: true`** - Consistent debugging experience -**Why?** These settings ensure tsbuild works correctly and produces consumable output. - -**Override if needed:** -```typescript -// Override via programmatic API -await compileFileArray(files, { - outDir: './custom_dist', - noEmitOnError: false // โš ๏ธ Not recommended -}); -``` - ### Default Compiler Options -When no tsconfig.json exists, tsbuild uses these modern defaults: +When no tsconfig.json exists: ```typescript { @@ -465,53 +442,25 @@ When no tsconfig.json exists, tsbuild uses these modern defaults: inlineSourceMap: true, // Debug-friendly noEmitOnError: true, // Fail-fast on errors outDir: 'dist_ts/', // Output directory - module: ModuleKind.NodeNext, // Modern Node.js modules - target: ScriptTarget.ESNext, // Latest JavaScript - moduleResolution: ModuleResolutionKind.NodeNext, - lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'], + module: 'NodeNext', // Modern Node.js modules + target: 'ESNext', // Latest JavaScript + moduleResolution: 'NodeNext', noImplicitAny: false, // Flexible for quick development esModuleInterop: true, // CJS/ESM interop - useDefineForClassFields: false, // Classic decorator behavior - verbatimModuleSyntax: true, // Explicit imports/exports - baseUrl: './' + verbatimModuleSyntax: true // Explicit imports/exports } ``` -### CLI Flags +### Path Transformation -Override any option via command-line: - -- `--skiplibcheck` - Skip declaration file checking (shows 5-second warning) -- `--confirmskiplibcheck` - Skip without warning -- `--disallowimplicitany` - Enable strict `any` checking -- `--commonjs` - Use CommonJS modules -- `--json` - Output JSON (for CI/CD) -- `--quiet` - Suppress console output - -**Examples:** -```bash -# Strict mode -npx tsbuild --disallowimplicitany - -# CommonJS output -npx tsbuild --commonjs - -# CI/CD pipeline -npx tsbuild --json --quiet > build-results.json -``` - -### Path Resolution - -tsbuild automatically transforms path mappings from your tsconfig.json: +tsbuild automatically transforms path mappings: **tsconfig.json:** ```json { "compilerOptions": { - "baseUrl": "./", "paths": { - "@models/*": ["./ts_models/*"], - "@utils/*": ["./ts_utils/*"] + "@models/*": ["./ts_models/*"] } } } @@ -519,150 +468,53 @@ tsbuild automatically transforms path mappings from your tsconfig.json: **Automatic transformation:** ``` -./ts_models/* โ†’ ./dist_ts_models/* -./ts_utils/* โ†’ ./dist_ts_utils/* +./ts_models/* -> ./dist_ts_models/* ``` -This ensures imports work correctly in compiled output. +## Features -## Advanced Usage +### Clean Builds -### Error Handling Patterns +Output directories are automatically cleared before compilation: -**Pattern 1: Simple (throw on error)** -```typescript -import { compileFileArray } from '@git.zone/tsbuild'; +``` +Clearing output directory: ./dist_ts +Compiling 14 files from ./ts/**/*.ts +``` -try { - await compileFileArray(['./src/**/*.ts']); - console.log('โœ… Build successful'); -} catch (error) { - console.error('โŒ Build failed:', error); - process.exit(1); +This ensures no stale files remain from previous builds. + +### Auto-Unpack + +When TypeScript compiles files that import from sibling directories, it creates nested output: + +``` +dist_ts_core/ + ts_core/ <- nested output + ts_shared/ <- pulled-in dependency +``` + +tsbuild automatically flattens this to: + +``` +dist_ts_core/ + index.js <- flat +``` + +Configure via `tspublish.json` in source folder: +```json +{ + "unpack": true } ``` -**Pattern 2: Detailed tracking (recommended)** -```typescript -import { compileFileArrayWithErrorTracking } from '@git.zone/tsbuild'; +Set `"unpack": false` to disable. -const result = await compileFileArrayWithErrorTracking(['./src/**/*.ts']); +### Decorator Support -if (result.hasErrors) { - console.error(`\nโŒ Compilation failed with ${result.errorCount} errors in ${result.fileCount} files\n`); - - // Group errors by file - for (const [file, errors] of Object.entries(result.errorsByFile)) { - console.error(`๐Ÿ“„ ${file}:`); - errors.forEach(err => { - const line = err.file?.getLineAndCharacterOfPosition(err.start!); - console.error(` Line ${line?.line}: ${err.messageText}`); - }); - } - - process.exit(1); -} - -console.log('โœ… All files compiled successfully!'); -``` - -**Pattern 3: CI/CD Integration** -```typescript -import { compileFileArrayWithErrorTracking } from '@git.zone/tsbuild'; - -const result = await compileFileArrayWithErrorTracking(['./src/**/*.ts']); - -// Output machine-readable JSON -console.log(JSON.stringify({ - success: !result.hasErrors, - errorCount: result.errorCount, - fileCount: result.fileCount, - timestamp: new Date().toISOString() -}, null, 2)); - -process.exit(result.hasErrors ? 1 : 0); -``` - -### Multi-Stage Builds - -Compile different parts of your project with different configurations: +First-class decorator support out of the box: ```typescript -import { compileGlobStringObject } from '@git.zone/tsbuild'; - -// Stage 1: Compile shared interfaces -await compileGlobStringObject( - { './ts_interfaces/**/*.ts': './dist_interfaces' }, - { declaration: true, emitDecoratorMetadata: false } -); - -// Stage 2: Compile Node.js code -await compileGlobStringObject( - { './ts_node/**/*.ts': './dist_node' }, - { target: 'ES2022', module: 'NodeNext' } -); - -// Stage 3: Compile browser code -await compileGlobStringObject( - { './ts_web/**/*.ts': './dist_web' }, - { target: 'ES2020', module: 'ESNext', lib: ['lib.dom.d.ts', 'lib.es2020.d.ts'] } -); -``` - -### Watch Mode Integration - -Integrate with file watchers for development: - -```typescript -import { compileFileArray } from '@git.zone/tsbuild'; -import chokidar from 'chokidar'; - -const watcher = chokidar.watch('./ts/**/*.ts'); - -watcher.on('change', async (path) => { - console.log(`๐Ÿ“ ${path} changed, recompiling...`); - - try { - await compileFileArray([path]); - console.log('โœ… Recompiled successfully'); - } catch (error) { - console.error('โŒ Compilation error:', error); - } -}); - -console.log('๐Ÿ‘€ Watching for changes...'); -``` - -### Custom Task Progress - -Track compilation progress in your UI: - -```typescript -import { compileFileArrayWithErrorTracking } from '@git.zone/tsbuild'; - -const taskInfo = { - taskIndex: 1, - totalTasks: 5, - taskName: 'Compiling Core Modules' -}; - -const result = await compileFileArrayWithErrorTracking( - ['./ts_core/**/*.ts'], - { target: 'ES2022' }, - undefined, - taskInfo -); - -// Output: ๐Ÿ”จ [1/5] Compiling Core Modules... -// โœ… [1/5] Task completed in 2345ms -``` - -## TypeScript Decorator Support - -tsbuild has **first-class decorator support** out of the box: - -```typescript -// Works automatically with no configuration @Injectable() class UserService { constructor( @@ -672,11 +524,7 @@ class UserService { } ``` -The following options are enabled by default: -- `experimentalDecorators: true` -- `emitDecoratorMetadata: true` - -This means frameworks like **NestJS**, **TypeORM**, **Inversify**, and **Angular** work without extra setup. +Works with NestJS, TypeORM, Inversify, Angular, and other DI frameworks. ## CI/CD Integration @@ -690,34 +538,31 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version: '20' - run: npm install - - run: npx tsbuild --json --quiet > build-results.json - - - name: Check build results - run: | - if ! cat build-results.json | jq -e '.success' > /dev/null; then - echo "Build failed!" - cat build-results.json | jq '.errors' - exit 1 - fi + - run: npx tsbuild ``` -### GitLab CI +### JSON Output -```yaml -build: - stage: build - script: - - npm install - - npx tsbuild - artifacts: - paths: - - dist_ts/ +```bash +npx tsbuild --json --quiet +``` + +```json +{ + "success": true, + "totals": { + "errors": 0, + "filesWithErrors": 0, + "tasks": 1 + }, + "errorsByFile": {} +} ``` ### Package.json Scripts @@ -726,9 +571,8 @@ build: { "scripts": { "build": "tsbuild", - "build:watch": "tsbuild && chokidar 'ts/**/*.ts' -c 'tsbuild'", "build:prod": "tsbuild --disallowimplicitany", - "typecheck": "tsbuild check 'ts/**/*.ts'", + "typecheck": "tsbuild check", "pretest": "tsbuild emitcheck 'test/**/*.ts'" } } @@ -740,143 +584,34 @@ build: **"Cannot find module" errors in compiled output** -This happens when path mappings aren't configured correctly. Make sure your tsconfig.json includes: - -```json -{ - "compilerOptions": { - "baseUrl": "./", - "paths": { - "@myapp/*": ["./ts/*"] - } - } -} -``` - -tsbuild automatically transforms these to work in the output directory. +Make sure path mappings are configured in tsconfig.json. tsbuild automatically transforms them. **Decorator errors** -If you see decorator-related errors, ensure: -1. `experimentalDecorators: true` in tsconfig.json -2. `emitDecoratorMetadata: true` for DI frameworks -3. You're using a compatible TypeScript version (4.0+) - -**Build succeeds but types are wrong** - -Run with strict checking: -```bash -npx tsbuild --disallowimplicitany +Ensure your tsconfig.json has: +```json +{ + "compilerOptions": { + "experimentalDecorators": true, + "emitDecoratorMetadata": true + } +} ``` -This catches implicit `any` types that can hide bugs. - **Slow compilation** Use `--skiplibcheck` to skip declaration file checking: ```bash -npx tsbuild --confirmskiplibcheck +npx tsbuild --skiplibcheck ``` -โš ๏ธ Only use this if you trust your dependencies' type definitions. +Only use this if you trust your dependencies' type definitions. -### Debug Mode +## Issue Reporting -For troubleshooting, combine flags: +For reporting issues or vulnerabilities, please visit our community at [community.foss.global](https://community.foss.global). We're looking forward to your contribution! -```bash -# See exactly what's happening -npx tsbuild --json | jq '.' - -# Check types without emitting -npx tsbuild check "**/*.ts" - -# Verify emit capability -npx tsbuild emitcheck "**/*.ts" -``` - -## Best Practices - -### โœ… DO - -- **Use `compileFileArrayWithErrorTracking()`** for production builds -- **Enable strict mode** in tsconfig.json for better type safety -- **Organize code in `ts_*` folders** for automatic dependency ordering -- **Use protected defaults** - they exist for good reasons -- **Type check in CI/CD** with `npx tsbuild check` -- **Version lock** tsbuild in package.json - -### โŒ DON'T - -- **Don't override `noEmitOnError`** - broken builds cause runtime errors -- **Don't skip lib check** in production builds -- **Don't ignore type errors** - they indicate real problems -- **Don't mix module formats** - stick to NodeNext for Node.js projects -- **Don't use `--quiet` without `--json`** - you'll lose error information - -## Performance Tips - -1. **Use glob patterns** instead of explicit file lists -2. **Enable `--skiplibcheck`** for faster development (not production!) -3. **Compile in stages** for large multi-package projects -4. **Use tsfolders** for automatic dependency ordering -5. **Cache `dist_*` folders** in CI/CD pipelines - -## Migration Guide - -### From tsc - -**Before (package.json):** -```json -{ - "scripts": { - "build": "tsc" - } -} -``` - -**After:** -```json -{ - "scripts": { - "build": "tsbuild" - } -} -``` - -Your tsconfig.json continues to work! tsbuild respects all your settings. - -### From other build tools - -tsbuild is a drop-in replacement focused on TypeScript compilation. If you need bundling, combine with your bundler: - -```json -{ - "scripts": { - "build": "tsbuild && esbuild dist_ts/index.js --bundle --outfile=bundle.js" - } -} -``` - -## FAQ - -**Q: Does tsbuild bundle code?** -A: No, tsbuild compiles TypeScript to JavaScript. For bundling, use esbuild, webpack, or rollup after compilation. - -**Q: Can I use tsbuild with monorepos?** -A: Yes! Use `tsbuild tsfolders` to automatically compile all packages in dependency order. - -**Q: Does it work with decorators?** -A: Yes, decorator support is enabled by default (both `experimentalDecorators` and `emitDecoratorMetadata`). - -**Q: Can I disable the protected defaults?** -A: Yes, via programmatic API or CLI flags. But consider why they're protected first! - -**Q: Does tsbuild support incremental compilation?** -A: tsbuild respects TypeScript's incremental flag if you set it in tsconfig.json. - -**Q: Is tsbuild compatible with TypeScript 5.x?** -A: Yes, tsbuild works with all modern TypeScript versions. +For repository access: [code.foss.global/git.zone/tsbuild](https://code.foss.global/git.zone/tsbuild) ## License and Legal Information @@ -891,7 +626,7 @@ This project is owned and maintained by Task Venture Capital GmbH. The names and ### Company Information Task Venture Capital GmbH -Registered at District court Bremen HRB 35230 HB, Germany +Registered at District Court Bremen HRB 35230 HB, Germany For any legal inquiries or if you require further information, please contact us via email at hello@task.vc. diff --git a/test/assets/output/tocompile.d.ts b/test/assets/output/tocompile.d.ts deleted file mode 100644 index cb0ff5c..0000000 --- a/test/assets/output/tocompile.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/test/assets/output/tocompile.js b/test/assets/output/tocompile.js deleted file mode 100644 index 45bebbb..0000000 --- a/test/assets/output/tocompile.js +++ /dev/null @@ -1,17 +0,0 @@ -console.log('test'); -console.log('test2'); -import * as early from '@push.rocks/early'; -early.start(); -early.stop(); -import { anExportedString } from './tocompile2.js'; -console.log(anExportedString); -class test2 { - test = []; - constructor() { - console.log('hi'); - } -} -const run = async () => { - return 'hi'; -}; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9jb21waWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdG9jb21waWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDcEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUVyQixPQUFPLEtBQUssS0FBSyxNQUFNLG1CQUFtQixDQUFDO0FBRTNDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUNkLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUViLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUU5QixNQUFNLEtBQUs7SUFDVCxJQUFJLEdBQWEsRUFBRSxDQUFDO0lBQ3BCO1FBQ0UsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQixDQUFDO0NBQ0Y7QUFFRCxNQUFNLEdBQUcsR0FBRyxLQUFLLElBQXFCLEVBQUU7SUFDdEMsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDLENBQUMifQ== \ No newline at end of file diff --git a/test/assets/output/tocompile2.d.ts b/test/assets/output/tocompile2.d.ts deleted file mode 100644 index b01ef63..0000000 --- a/test/assets/output/tocompile2.d.ts +++ /dev/null @@ -1 +0,0 @@ -export declare const anExportedString = "exported string"; diff --git a/test/assets/output/tocompile2.js b/test/assets/output/tocompile2.js deleted file mode 100644 index 40f9b92..0000000 --- a/test/assets/output/tocompile2.js +++ /dev/null @@ -1,3 +0,0 @@ -console.log('hello'); -export const anExportedString = 'exported string'; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9jb21waWxlMi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RvY29tcGlsZTIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUNyQixNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxpQkFBaUIsQ0FBQyJ9 \ No newline at end of file diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 02c67fb..00477c6 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@git.zone/tsbuild', - version: '3.1.3', + version: '4.0.2', description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.' } diff --git a/ts/mod_compiler/classes.tscompiler.ts b/ts/mod_compiler/classes.tscompiler.ts index 6f8fe5c..ae00f4e 100644 --- a/ts/mod_compiler/classes.tscompiler.ts +++ b/ts/mod_compiler/classes.tscompiler.ts @@ -335,6 +335,14 @@ export class TsCompiler { // Get destination directory as absolute path const destDir = smartpath.transform.toAbsolute(destPath, this.cwd) as string; + // Clear the destination directory before compilation if it exists + if (await FsHelpers.directoryExists(destDir)) { + if (!isQuiet && !isJson) { + console.log(`๐Ÿงน Clearing output directory: ${destPath}`); + } + await FsHelpers.removeDirectory(destDir); + } + // Update compiler options with the output directory const options: CompilerOptions = { ...customOptions,