Compare commits

..

20 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
14 changed files with 3493 additions and 3649 deletions

View File

@@ -1,5 +1,73 @@
# 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

View File

@@ -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",

View File

@@ -1,6 +1,6 @@
{
"name": "@git.zone/tsbuild",
"version": "2.6.8",
"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",
@@ -29,7 +29,7 @@
"development",
"API"
],
"author": "Lossless GmbH",
"author": "Task Venture Capital GmbH",
"license": "MIT",
"bugs": {
"url": "https://code.foss.global/git.zone/tsbuild/issues"
@@ -38,18 +38,19 @@
"dependencies": {
"@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.2.7",
"@push.rocks/smartlog": "^3.1.8",
"@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.2"
"typescript": "5.9.3"
},
"devDependencies": {
"@git.zone/tsrun": "^1.2.47",
"@git.zone/tstest": "^2.3.4",
"@types/node": "^22.15.21"
"@git.zone/tsrun": "^2.0.1",
"@git.zone/tstest": "^3.1.3",
"@types/node": "^25.0.1"
},
"files": [
"ts/**/*",

5524
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

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

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';
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==

View File

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

View File

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

View File

@@ -18,18 +18,15 @@ export interface IErrorSummary {
*/
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: './',
};
@@ -62,19 +59,58 @@ 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 };
// Apply special transformations for string-to-enum conversions
// Process target (convert string to enum)
if (tsconfig.compilerOptions.target && typeof tsconfig.compilerOptions.target === 'string') {
const targetKey = tsconfig.compilerOptions.target.toUpperCase();
if (targetKey in plugins.typescript.ScriptTarget) {
returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget];
}
}
// Process paths
// Process module (convert string to enum)
if (tsconfig.compilerOptions.module && typeof tsconfig.compilerOptions.module === 'string') {
const moduleKey = tsconfig.compilerOptions.module.toUpperCase();
if (moduleKey in plugins.typescript.ModuleKind) {
returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind];
} else if (moduleKey === 'NODENEXT') {
returnObject.module = plugins.typescript.ModuleKind.NodeNext;
}
}
// Process moduleResolution (convert string to enum)
if (tsconfig.compilerOptions.moduleResolution && typeof tsconfig.compilerOptions.moduleResolution === 'string') {
const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase();
if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) {
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[
moduleResolutionKey as keyof typeof plugins.typescript.ModuleResolutionKind
];
} else if (moduleResolutionKey === 'NODENEXT') {
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeNext;
}
}
// Apply path transformations (ts_ → dist_ts_)
if (tsconfig.compilerOptions.paths) {
returnObject.paths = { ...tsconfig.compilerOptions.paths };
for (const path of Object.keys(returnObject.paths)) {
@@ -84,57 +120,22 @@ export class TsBuild {
}
}
// Process target
if (tsconfig.compilerOptions.target) {
if (typeof tsconfig.compilerOptions.target === 'string') {
const targetKey = tsconfig.compilerOptions.target.toUpperCase();
if (targetKey in plugins.typescript.ScriptTarget) {
returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget];
}
}
}
// Process module
if (tsconfig.compilerOptions.module) {
if (typeof tsconfig.compilerOptions.module === 'string') {
const moduleKey = tsconfig.compilerOptions.module.toUpperCase();
if (moduleKey in plugins.typescript.ModuleKind) {
returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind];
} else if (moduleKey === 'NODENEXT') {
returnObject.module = plugins.typescript.ModuleKind.NodeNext;
}
}
}
// Process moduleResolution
if (tsconfig.compilerOptions.moduleResolution) {
if (typeof tsconfig.compilerOptions.moduleResolution === 'string') {
const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase();
if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) {
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[
moduleResolutionKey as keyof typeof plugins.typescript.ModuleResolutionKind
];
} else if (moduleResolutionKey === 'NODENEXT') {
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeNext;
}
}
}
// Copy boolean options directly
const booleanOptions = [
'experimentalDecorators', 'useDefineForClassFields',
'esModuleInterop', 'verbatimModuleSyntax'
];
for (const option of booleanOptions) {
if (option in tsconfig.compilerOptions) {
(returnObject as any)[option] = (tsconfig.compilerOptions as any)[option];
}
}
return returnObject;
}
/**
* 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
*/
@@ -162,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 = {},
@@ -169,10 +177,11 @@ 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;

View File

@@ -63,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}'`);
@@ -93,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);
}
@@ -128,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'
@@ -208,10 +207,7 @@ export const runCli = async () => {
// First check ts/**/* without skiplibcheck
console.log('📂 Checking ts/**/* files...');
const tsFiles = await plugins.smartfile.fs.listFileTree(process.cwd(), 'ts/**/*.ts');
const tsTsFiles = Array.isArray(tsFiles)
? tsFiles.filter((item): item is string => typeof item === 'string')
: [];
const tsTsFiles = await plugins.listFilesWithGlob(process.cwd(), 'ts/**/*.ts');
if (tsTsFiles.length > 0) {
console.log(` Found ${tsTsFiles.length} TypeScript files in ts/`);
@@ -234,10 +230,7 @@ export const runCli = async () => {
// Then check test/**/* with skiplibcheck
console.log('📂 Checking test/**/* files with --skiplibcheck...');
const testFiles = await plugins.smartfile.fs.listFileTree(process.cwd(), 'test/**/*.ts');
const testTsFiles = Array.isArray(testFiles)
? testFiles.filter((item): item is string => typeof item === 'string')
: [];
const testTsFiles = await plugins.listFilesWithGlob(process.cwd(), 'test/**/*.ts');
if (testTsFiles.length > 0) {
console.log(` Found ${testTsFiles.length} TypeScript files in test/`);
@@ -274,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}'`);
@@ -304,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);
}

View File

@@ -145,13 +145,8 @@ export let compileGlobStringObject = async (
// 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(

View File

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