Compare commits
152 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b38ef6cf82 | |||
| 8b50cd3090 | |||
| c6ab493efc | |||
| 82ae8a0e4a | |||
| 787becc4d3 | |||
| 746ca8767a | |||
| 55c1a2953a | |||
| 8e9fcb8135 | |||
| 18573c777d | |||
| fa654b83e3 | |||
| aa3c83cd95 | |||
| 20ed41df42 | |||
| 7162476f7f | |||
| 1b012628eb | |||
| 4081086621 | |||
| b9cf09ccba | |||
| 8463fbc78a | |||
| 0164eb51a1 | |||
| a305dd89dd | |||
| fa6b053ee0 | |||
| adfba21c67 | |||
| 050e41cdf9 | |||
| f220a11caa | |||
| 0909fa306a | |||
| 88c0601c03 | |||
| 9645f27942 | |||
| b73aa4f21f | |||
| d9d6878a9f | |||
| 30506da84c | |||
| 52b4d8f944 | |||
| 57d2726f6b | |||
| 960fc5f213 | |||
| 6d68f35a9a | |||
| 0378b9feca | |||
| 5ecf4b7125 | |||
| 2aa6348cdd | |||
| 9f42670865 | |||
| 6cc9f41bd2 | |||
| 5d32ac85e0 | |||
| 4f2ac6922a | |||
| 31834e0b3e | |||
| c6c94866bb | |||
| 09a648b435 | |||
| 065e0baaf7 | |||
| 89d32617ce | |||
| 094702b917 | |||
| c2aec98da3 | |||
| 289421206c | |||
| 1f9870ffbb | |||
| 8f7f34d61e | |||
| 2e23919503 | |||
| f601cf8eb8 | |||
| 15af2e4e2d | |||
| 59c6e72187 | |||
| 5369e8d931 | |||
| 88444e835f | |||
| 4892c8f7ae | |||
| 687f01d1a3 | |||
| 071b3e222f | |||
| fa41dbf332 | |||
| c45a216379 | |||
| 00046837a7 | |||
| ed22b539f2 | |||
| 43c7021aea | |||
| b21009f815 | |||
| deba95dfa6 | |||
| 50e6fec9b0 | |||
| f7c2a67d81 | |||
| 91e3502965 | |||
| 0afddbefce | |||
| 94e879d9fe | |||
| 43e2a1d777 | |||
| 9a1f57b92d | |||
| 0064f63ddb | |||
| 6e90bdda36 | |||
| 82cce58d69 | |||
| a316cc6725 | |||
| 05738a5c94 | |||
| 651a06ff7b | |||
| 2f04474dab | |||
| d88af368a4 | |||
| e60816be4c | |||
| a9e383ba2d | |||
| a3e1cf9e3d | |||
| 8790886815 | |||
| 611bd0d542 | |||
| b182fa5c0a | |||
| 03d4996284 | |||
| 6b2d2c9cc3 | |||
| e9dc5ae444 | |||
| 24574bdb4d | |||
| 2fe98bec22 | |||
| 87b6a4efb2 | |||
| dc81d99ac3 | |||
| 5d0c9b0326 | |||
| f27c27bd31 | |||
| 67e42cc0bd | |||
| 4a71b92868 | |||
| c251bce006 | |||
| f83b872f31 | |||
| 4e93832683 | |||
| 4d37e880a3 | |||
| b7e6412b7a | |||
| 113717886c | |||
| 98b4d4bc5b | |||
| 83f496f0ca | |||
| 662b7d4e6c | |||
| ab43ea0a10 | |||
| 0561f655cb | |||
| b0b1be70ab | |||
| dda03bad45 | |||
| a0b9f8d8f3 | |||
| da823e51d5 | |||
| b68aa06941 | |||
| f5ee2c2c70 | |||
| 0c018e6448 | |||
| 565c66e4e6 | |||
| 72ad77446c | |||
| 59ce28395f | |||
| cddd7ffd25 | |||
| 48ef556e6b | |||
| 0645beb199 | |||
| 97f52d1016 | |||
| 8d725e2e11 | |||
| 42b83b888e | |||
| 832664b667 | |||
| 4925809030 | |||
| 622a080b3c | |||
| 18747dbc83 | |||
| 210a7a07f7 | |||
| 211d42c36b | |||
| cfbe4bbcb9 | |||
| 72350a49ec | |||
| d4a0d03301 | |||
| 75f506ba0e | |||
| 035207f4f9 | |||
| 6d2d48af9d | |||
| 9adbce12e1 | |||
| 318189c7b2 | |||
| 167483b909 | |||
| 67db62e7d5 | |||
| ddf76c31b9 | |||
| 6a0a53adda | |||
| eb1a70ea70 | |||
| c10ddd3c1e | |||
| 9c9f7ae1dc | |||
| 70245584d7 | |||
| f11d7c6cb0 | |||
| dc7980e619 | |||
| 686a428624 | |||
| 6772bb439c | |||
| 3acab250db |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -18,3 +18,4 @@ dist/
|
||||
dist_*/
|
||||
|
||||
# custom
|
||||
.claude
|
||||
127
.gitlab-ci.yml
127
.gitlab-ci.yml
@@ -1,127 +0,0 @@
|
||||
# gitzone ci_default
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- .npmci_cache/
|
||||
key: '$CI_BUILD_STAGE'
|
||||
|
||||
stages:
|
||||
- security
|
||||
- test
|
||||
- release
|
||||
- metadata
|
||||
|
||||
# ====================
|
||||
# security stage
|
||||
# ====================
|
||||
mirror:
|
||||
stage: security
|
||||
script:
|
||||
- npmci git mirror
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
audit:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci command npm install --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
# ====================
|
||||
# test stage
|
||||
# ====================
|
||||
|
||||
testStable:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- priv
|
||||
|
||||
testBuild:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci command npm run build
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
release:
|
||||
stage: release
|
||||
script:
|
||||
- npmci node install stable
|
||||
- npmci npm publish
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
# ====================
|
||||
# metadata stage
|
||||
# ====================
|
||||
codequality:
|
||||
stage: metadata
|
||||
allow_failure: true
|
||||
script:
|
||||
- npmci command npm install -g tslint typescript
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- priv
|
||||
|
||||
trigger:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci trigger
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
pages:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci node install lts
|
||||
- npmci command npm install -g @gitzone/tsdoc
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command tsdoc
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
only:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
paths:
|
||||
- public
|
||||
allow_failure: true
|
||||
24
.vscode/launch.json
vendored
24
.vscode/launch.json
vendored
@@ -2,28 +2,10 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "current file",
|
||||
"type": "node",
|
||||
"command": "npm test",
|
||||
"name": "Run npm test",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"${relativeFile}"
|
||||
],
|
||||
"runtimeArgs": ["-r", "@gitzone/tsrun"],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"protocol": "inspector",
|
||||
"internalConsoleOptions": "openOnSessionStart"
|
||||
},
|
||||
{
|
||||
"name": "test.ts",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"test/test.ts"
|
||||
],
|
||||
"runtimeArgs": ["-r", "@gitzone/tsrun"],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"protocol": "inspector",
|
||||
"internalConsoleOptions": "openOnSessionStart"
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -15,7 +15,7 @@
|
||||
"properties": {
|
||||
"projectType": {
|
||||
"type": "string",
|
||||
"enum": ["website", "element", "service", "npm"]
|
||||
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
381
changelog.md
Normal file
381
changelog.md
Normal file
@@ -0,0 +1,381 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-11-02 - 2.7.1 - fix(readme)
|
||||
Update documentation: expand README with usage, CLI and API examples; add readme.hints.md project memory
|
||||
|
||||
- Add readme.hints.md: new project memory / quick reference with public API and CLI summaries
|
||||
- Expand and restructure readme.md: more comprehensive Quick Start, CLI Commands, API Reference, configuration, examples and troubleshooting
|
||||
- Clarify protected compiler options, default compiler options, path transformation behavior and error-handling patterns
|
||||
- Docs-only change — no source code or behavioral changes
|
||||
|
||||
## 2025-11-02 - 2.7.0 - feat(tsbuild)
|
||||
Add tsconfig.json support and safer compiler option merging; protect critical options; apply path and enum transforms; bump dependencies.
|
||||
|
||||
- Add robust tsconfig.json reading with graceful fallback when no tsconfig is present or it is invalid
|
||||
- Merge compiler options in a clear priority order (defaults -> tsconfig -> protected defaults -> programmatic -> CLI flags)
|
||||
- Introduce protected (critical) compiler options that cannot be overridden by tsconfig.json: outDir, noEmitOnError, declaration, emitDecoratorMetadata, inlineSourceMap
|
||||
- Convert string values from tsconfig (target, module, moduleResolution) to TypeScript enum values where applicable; special-case NodeNext
|
||||
- Transform tsconfig path mappings by replacing './ts_' with './dist_ts_' to keep runtime path resolution consistent with compiled output
|
||||
- Expose getCriticalDefaults helper and adjust mergeCompilerOptions to apply protected defaults before programmatic and CLI overrides
|
||||
- Update README with documentation for tsconfig support, merge order, protected compiler options, and example tsconfig
|
||||
- Bump dependencies/devDependencies: @push.rocks/smartcli ^4.0.19, @push.rocks/smartlog ^3.1.10, typescript 5.9.3, @git.zone/tsrun ^1.6.2, @git.zone/tstest ^2.7.0
|
||||
|
||||
## 2025-08-29 - 2.6.8 - fix(tsbuild)
|
||||
Avoid process.exit in library, add confirmskiplibcheck flag, improve CLI exit handling and JSON/quiet modes, update test script
|
||||
|
||||
- Changed package.json test script from "tsrun test/test.ts --verbose" to "tstest test/test.ts --verbose".
|
||||
- Library no longer calls process.exit from compile and compileWithErrorTracking; errors are returned or thrown so callers can decide process termination.
|
||||
- skipLibCheck behavior updated: delay/warning only happens when --confirmskiplibcheck is present; otherwise a short informational note is printed (suppressed in --quiet/--json).
|
||||
- CLI now awaits compileGlobStringObject calls and inspects a final error summary attached to argv to decide process.exit(1) when errors occurred.
|
||||
- compileGlobStringObject/exports now respect --quiet and --json modes, emit a JSON summary when --json is used, and attach the final error summary to argv so the CLI can determine exit behavior.
|
||||
|
||||
## 2025-08-18 - 2.6.7 - fix(tspublish)
|
||||
Bump @git.zone/tspublish dependency to ^1.10.3
|
||||
|
||||
- Updated dependency @git.zone/tspublish from ^1.10.2 to ^1.10.3 in package.json
|
||||
|
||||
## 2025-08-18 - 2.6.6 - fix(dependencies)
|
||||
Update dependency @git.zone/tspublish to ^1.10.2
|
||||
|
||||
- Bumped @git.zone/tspublish in package.json from ^1.10.1 to ^1.10.2
|
||||
|
||||
## 2025-08-18 - 2.6.5 - fix(dependencies)
|
||||
Bump dependencies and add pnpm-workspace configuration
|
||||
|
||||
- Updated @git.zone/tspublish from ^1.9.1 to ^1.10.1
|
||||
- Updated @push.rocks/smartfile from ^11.2.4 to ^11.2.7
|
||||
- Updated @push.rocks/smartpath from ^5.0.18 to ^6.0.0
|
||||
- Updated typescript from 5.8.3 to 5.9.2
|
||||
- Updated devDependency @git.zone/tstest from ^1.10.1 to ^2.3.4
|
||||
- Added pnpm-workspace.yaml with onlyBuiltDependencies list (esbuild, mongodb-memory-server, puppeteer)
|
||||
|
||||
## 2025-05-24 - 2.6.4 - fix(dependencies)
|
||||
Add .npmrc and update dependency versions for smartfile and tstest
|
||||
|
||||
- Add .npmrc with registry configuration for npm
|
||||
- Bump @push.rocks/smartfile version from ^11.2.3 to ^11.2.4
|
||||
- Bump @git.zone/tstest version from ^1.9.0 to ^1.10.1
|
||||
|
||||
## 2025-05-21 - 2.6.3 - fix(tsbuild)
|
||||
minor maintenance updates and documentation improvements
|
||||
|
||||
- Updated commit metadata to align with project version
|
||||
- Refined CLI command parsing and diagnostics logging for better clarity
|
||||
- Improved code readability in compiler options merging
|
||||
|
||||
## 2025-05-21 - 2.6.2 - fix(npm configuration)
|
||||
Remove .npmrc file to default npm registry behavior
|
||||
|
||||
- Deleted .npmrc file that hard-coded the npm registry URL to https://registry.npmjs.org/
|
||||
- This change leverages npm's default registry settings and reduces configuration clutter
|
||||
|
||||
## 2025-05-21 - 2.6.1 - fix(tsbuild.classes)
|
||||
Improve error diagnostics handling by removing legacy helper and integrating more robust error summaries in the compilation process
|
||||
|
||||
- Removed the handleDiagnostics method and its legacy usage
|
||||
- Replaced legacy calls with inline processDiagnostics checks for pre-emit and emit phases
|
||||
- Combined error summaries for clearer reporting during emit checks and type validation
|
||||
- Enhanced error output to guide users on resolving TypeScript errors before emission
|
||||
|
||||
## 2025-05-21 - 2.6.0 - feat(tsbuild)
|
||||
Improve task logging and update dependencies
|
||||
|
||||
- Add .npmrc file with npm registry configuration
|
||||
- Update test script to use '--verbose' flag
|
||||
- Bump dependency versions for @push.rocks packages and TypeScript
|
||||
- Enhance TsBuild logging by incorporating task info (e.g. task number, total tasks, output folder, and compile durations)
|
||||
- Propagate task info in compileFileArrayWithErrorTracking for better task tracking
|
||||
|
||||
## 2025-05-21 - 2.5.2 - fix(tsbuild)
|
||||
Improve diagnostic error handling and summary reporting for TypeScript compilation by refactoring diagnostic processing and adding pre-emit error checks.
|
||||
|
||||
- Introduce a dedicated processDiagnostics function that categorizes errors by file and computes error totals.
|
||||
- Refactor displayErrorSummary to provide clearer, color-coded output of error details.
|
||||
- Add pre-emit error checking in compileWithErrorTracking to prevent emission when errors exist.
|
||||
- Consolidate error summary merging in compileFileArrayWithErrorTracking for improved reporting.
|
||||
|
||||
## 2025-05-15 - 2.5.1 - fix(commitinfo)
|
||||
Update commit information and metadata to synchronize release data
|
||||
|
||||
- Regenerated the commitinfo file with current version details
|
||||
- Maintained existing functionality with no functional code changes
|
||||
|
||||
## 2025-05-15 - 2.5.0 - feat(cli)
|
||||
Enhance type checking in CLI by adding default file pattern handling
|
||||
|
||||
- When no TypeScript file or glob pattern is provided, the CLI now performs a default type checking sequence.
|
||||
- First checks 'ts/**/*' files with standard options, then checks 'test/**/*' files with skiplibcheck enabled.
|
||||
- Improved logging to indicate file discovery and check results, ensuring clear feedback for users.
|
||||
|
||||
## 2025-05-15 - 2.4.1 - fix(cli)
|
||||
Improve TS folder compilation order display in CLI
|
||||
|
||||
- Refactor folder compilation output to use a bordered, tabular format with order numbering
|
||||
- Enhance readability of TS folder compilation plan in the CLI output
|
||||
|
||||
## 2025-05-15 - 2.4.0 - feat(cli)
|
||||
Add new 'check' command for type checking and update compiler options handling
|
||||
|
||||
- Introduced a new 'check' command to verify TypeScript files without emitting output
|
||||
- Updated CLI error messages and logging for better clarity
|
||||
- Replaced '--allowimplicitany' flag with '--disallowimplicitany' to reflect new default behavior
|
||||
- Modified compiler options default settings (noImplicitAny now set to false) for more flexible type handling
|
||||
- Refined diagnostic output in tsbuild class for improved error reporting
|
||||
- Updated .gitignore to exclude the .claude file
|
||||
- Enhanced documentation in readme and implementation plan files
|
||||
|
||||
## 2025-03-20 - 2.3.2 - fix(compileGlobStringObject)
|
||||
Fix duplicate file outputs in glob pattern processing
|
||||
|
||||
- Removed duplicate concatenation of compiled files in compileGlobStringObject
|
||||
- Ensured unique file paths are used during TypeScript compilation
|
||||
|
||||
## 2025-03-20 - 2.3.1 - fix(compiler)
|
||||
Refactor compiler implementation with consolidated TsBuild class and improved diagnostics handling
|
||||
|
||||
- Removed legacy tsbuild.classes.compiler.ts and introduced tsbuild.classes.tsbuild.ts
|
||||
- Unified compiler options merging, reading tsconfig.json, and diagnostics reporting within the TsBuild class
|
||||
- Updated exports to reference the new compiler class implementation for backward compatibility
|
||||
|
||||
## 2025-03-20 - 2.3.0 - feat(cli)
|
||||
Add emitcheck command to validate TS file emission without generating output
|
||||
|
||||
- Implemented the emitcheck CLI command to allow checking if TypeScript files can be emitted without producing files
|
||||
- Updated tsbuild.classes.compiler.ts to include the emitCheck function
|
||||
- Enhanced documentation in readme.md to describe the new emitcheck usage with examples
|
||||
|
||||
## 2025-03-17 - 2.2.7 - fix(compiler)
|
||||
Improve diagnostic checking and error handling in the TypeScript compiler integration
|
||||
|
||||
- Added pre-emit diagnostics check to log errors before emitting
|
||||
- Process exits on encountering pre-emit errors to ensure build correctness
|
||||
- Enhanced logging for emit diagnostics to aid debugging
|
||||
|
||||
## 2025-03-04 - 2.2.6 - fix(package)
|
||||
Fix repository URL in package.json
|
||||
|
||||
- Updated repository URL in package.json to point to the correct Git repository.
|
||||
|
||||
## 2025-03-04 - 2.2.5 - fix(package.json)
|
||||
Update repository URLs in package metadata.
|
||||
|
||||
- Corrected the 'bugs.url' and 'homepage' fields with the accurate URLs.
|
||||
|
||||
## 2025-03-04 - 2.2.4 - fix(core)
|
||||
Fix compiler logic to remove duplicate compiled files and improve glob pattern handling.
|
||||
|
||||
- Resolved an issue causing duplicate file compilations when using compileGlobStringObject.
|
||||
- Improved handling of glob patterns to ensure accurate compilation paths.
|
||||
|
||||
## 2025-03-04 - 2.2.3 - fix(exports)
|
||||
Fixed duplicate file compilation in compileGlobStringObject
|
||||
|
||||
- Enhanced type safety checks for glob pattern compilation keys.
|
||||
- Ensured file list transformations include type checks.
|
||||
- Fixed issue with duplicate compilation results in compileGlobStringObject.
|
||||
|
||||
## 2025-01-28 - 2.2.2 - fix(ci)
|
||||
Remove GitLab CI configuration
|
||||
|
||||
|
||||
## 2025-01-28 - 2.2.1 - fix(core)
|
||||
Update dependencies to improve stability and performance.
|
||||
|
||||
- Updated @git.zone/tspublish from version ^1.7.5 to ^1.9.1.
|
||||
- Updated @push.rocks/smartfile from version ^11.0.21 to ^11.1.5.
|
||||
- Updated @push.rocks/smartpromise from version ^4.0.4 to ^4.2.2.
|
||||
- Updated typescript from version 5.6.3 to 5.7.3.
|
||||
- Updated @push.rocks/tapbundle from version ^5.0.23 to ^5.5.6.
|
||||
- Updated @types/node from version ^22.8.7 to ^22.12.0.
|
||||
|
||||
## 2024-11-05 - 2.2.0 - feat(cli)
|
||||
Enhance CLI for TypeScript folder compilation ordering based on rank and predefined rules.
|
||||
|
||||
- CLI now supports automatic ordering of TypeScript folders for compilation using tspublish.json based ranking.
|
||||
- Ensures 'ts_interfaces' and 'ts_shared' are always transpiled first if certain conditions are met.
|
||||
- Updated TypeScript compilerOptions to support additional path transformations.
|
||||
- Updated dependencies versions and added '@git.zone/tspublish' in ts/plugins.ts.
|
||||
|
||||
## 2024-10-27 - 2.1.85 - fix(compiler)
|
||||
Improve path handling in compiler options
|
||||
|
||||
- Refactored path import in tsbuild.classes.compiler.ts.
|
||||
- Enhanced mergeCompilerOptions to read paths and baseUrl from tsconfig.json if present.
|
||||
|
||||
## 2024-07-22 - 2.1.84 - fix(cli)
|
||||
Fixed transpilation order issue in tsfolders command
|
||||
|
||||
- Corrected the transpilation order so 'ts_shared' is processed before other folders in the 'tsfolders' CLI command.
|
||||
|
||||
## 2024-07-21 - 2.1.83 - fix(cli)
|
||||
Ensure 'ts_shared' folder is compiled first if present
|
||||
|
||||
- Added logic to make sure the 'ts_shared' folder is compiled first when running 'tsfolders' command.
|
||||
|
||||
## 2024-06-24 - 2.1.82 - fix(core)
|
||||
Minor improvements and optimizations in core TypeScript compiler integration.
|
||||
|
||||
- Updated TypeScript dependency to latest version 5.5.2.
|
||||
- Enhanced logging in compiler process.
|
||||
- Improved handling of CLI commands for better flexibility.
|
||||
- Compiled output directories are now more structured.
|
||||
- Refactored internal compiler options merge function.
|
||||
|
||||
## 2024-06-24 - 2.1.81 - fix(dependencies)
|
||||
Update dependencies to latest versions
|
||||
|
||||
- Upgraded @push.rocks/smartcli from ^4.0.10 to ^4.0.11
|
||||
- Upgraded @push.rocks/smartfile from ^11.0.14 to ^11.0.21
|
||||
- Upgraded @push.rocks/smartlog from ^3.0.3 to ^3.0.7
|
||||
- Upgraded @push.rocks/smartpromise from ^4.0.3 to ^4.0.4
|
||||
- Upgraded typescript from 5.4.5 to 5.5.2
|
||||
- Upgraded @git.zone/tsrun from ^1.2.46 to ^1.2.47
|
||||
- Upgraded @types/node from ^20.12.11 to ^20.14.8
|
||||
|
||||
## 2024-05-17 - 2.1.80 - core
|
||||
Fix multiple core issues.
|
||||
|
||||
- Various small fixes and updates to the core functionality.
|
||||
|
||||
## 2024-05-17 - 2.1.76 to 2.1.79 - core
|
||||
Routine core updates and fixes.
|
||||
|
||||
- Several minor enhancements and bug fixes.
|
||||
|
||||
## 2024-05-14 - 2.1.74 to 2.1.75 - core
|
||||
General core maintenance updates.
|
||||
|
||||
- Core updated to fix minor bugs.
|
||||
|
||||
## 2024-05-10 - 2.1.72 to 2.1.73 - core
|
||||
Minor core updates.
|
||||
|
||||
- Improvements and fixes to core components.
|
||||
|
||||
## 2024-01-08 - 2.1.70 to 2.1.71 - core
|
||||
Core functionality enhancements.
|
||||
|
||||
- Small fixes and updates in the core.
|
||||
|
||||
## 2023-08-26 - 2.1.66 to 2.1.69 - core
|
||||
Regular core updates and fixes.
|
||||
|
||||
- Various updates to improve core functionality.
|
||||
|
||||
## 2023-06-03 - 2.1.65 - core
|
||||
Core maintenance update.
|
||||
|
||||
- Fixed issues in core functionality.
|
||||
|
||||
## 2022-08-03 - 2.1.63 to 2.1.64 - core
|
||||
Minor core updates and fixes.
|
||||
|
||||
- Updated core functionality with minor fixes.
|
||||
|
||||
## 2022-05-25 - 2.1.61 to 2.1.62 - core
|
||||
Routine core updates.
|
||||
|
||||
- Fixed minor bugs in the core.
|
||||
|
||||
## 2022-03-24 - 2.1.60 - core
|
||||
Core functionality update.
|
||||
|
||||
- Fixed various minor issues in core.
|
||||
|
||||
## 2022-03-18 - 2.1.57 to 2.1.59 - core
|
||||
Minor core updates and enhancements.
|
||||
|
||||
- Updated core components with small fixes.
|
||||
|
||||
## 2022-03-15 - 2.1.50 to 2.1.56 - core
|
||||
Several core bug fixes.
|
||||
|
||||
- Fixed various minor issues in the core functionality.
|
||||
|
||||
## 2022-03-14 - 2.1.49 - core
|
||||
Core update.
|
||||
|
||||
- Fixed minor bugs in the core.
|
||||
|
||||
## 2022-03-12 - 2.1.43 to 2.1.48 - core
|
||||
General core maintenance updates.
|
||||
|
||||
- Core updated to fix minor bugs and improve functionality.
|
||||
|
||||
## 2022-03-11 - 2.1.33 to 2.1.42 - core
|
||||
Core functionality enhancements and fixes.
|
||||
|
||||
- Multiple updates to improve core functionality and fix bugs.
|
||||
|
||||
## 2022-03-11 - 2.1.29 to 2.1.32 - core
|
||||
Routine core updates.
|
||||
|
||||
- Minor bug fixes and improvements in core functionality.
|
||||
|
||||
## 2022-01-19 - 2.1.28 to 2.1.29 - core
|
||||
Core bug fixes.
|
||||
|
||||
- Updated core to address minor issues.
|
||||
|
||||
## 2021-10-06 - 2.1.27 - core
|
||||
Minor core update.
|
||||
|
||||
- Fixed core bugs.
|
||||
|
||||
## 2021-09-08 - 2.1.26 - core
|
||||
Core update.
|
||||
|
||||
- Fixed minor bugs in the core.
|
||||
|
||||
## 2021-08-17 - 2.1.25 - core
|
||||
Core bug fixes.
|
||||
|
||||
- Small updates to improve core functionality.
|
||||
|
||||
## 2020-08-11 - 2.1.24 - core
|
||||
Routine core update.
|
||||
|
||||
- Fixed minor bugs in the core.
|
||||
|
||||
## 2020-05-14 - 2.1.23 - core
|
||||
General core updates.
|
||||
|
||||
- Fixes to improve core stability.
|
||||
|
||||
## 2020-03-13 - 2.1.20 to 2.1.22 - core
|
||||
Minor core updates.
|
||||
|
||||
- Enhancements and fixes for core functionality.
|
||||
|
||||
## 2020-03-09 - 2.1.19 - core
|
||||
Maintenance core update.
|
||||
|
||||
- Fixes addressing minor issues in core functionality.
|
||||
|
||||
## 2019-08-26 - 2.1.16 to 2.1.17 - core
|
||||
Routine minor core updates.
|
||||
|
||||
- Improvement and fixes within the core functionality.
|
||||
|
||||
## 2019-01-27 - 2.1.6 - custom directory compilation
|
||||
Now picking up TypeScript files correctly.
|
||||
|
||||
- Resolved compilation issues with custom directories.
|
||||
|
||||
## 2018-12-05 - 2.1.0 to 2.1.1 - core
|
||||
Minor core updates.
|
||||
|
||||
- Small enhancements and fixes applied to core functionality.
|
||||
|
||||
## 2018-12-05 - 2.0.22 - cli options
|
||||
Now support --web for web compilations targeting Google Chrome.
|
||||
|
||||
- Added new CLI option for web compilation.
|
||||
|
||||
## 2018-07-25 - 2.0.15 to 2.0.19 - various
|
||||
Multiple fixes across core, dependency, and compiler modules.
|
||||
|
||||
- Packagename fix in core.
|
||||
- Dependency updates.
|
||||
- Compiler options fixed.
|
||||
- Initial core updates.
|
||||
4
cli.child.ts
Normal file
4
cli.child.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env node
|
||||
process.env.CLI_CALL = 'true';
|
||||
import * as cliTool from './ts/index.js';
|
||||
cliTool.runCli();
|
||||
2
cli.js
2
cli.js
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env node
|
||||
process.env.CLI_CALL = 'true';
|
||||
const cliTool = await import('./dist_ts/index');
|
||||
const cliTool = await import('./dist_ts/index.js');
|
||||
cliTool.runCli();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env node
|
||||
process.env.CLI_CALL = 'true';
|
||||
await import('@gitzone/tsrun');
|
||||
const cliTool = await import('./ts/index');
|
||||
cliTool.runCli();
|
||||
import * as tsrun from '@git.zone/tsrun';
|
||||
tsrun.runPath('./cli.child.js');
|
||||
@@ -9,9 +9,23 @@
|
||||
"githost": "gitlab.com",
|
||||
"gitscope": "gitzone",
|
||||
"gitrepo": "tsbuild",
|
||||
"shortDescription": "TypeScript nightly to easily make use of latest features",
|
||||
"description": "A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.",
|
||||
"npmPackagename": "@gitzone/tsbuild",
|
||||
"license": "MIT"
|
||||
}
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"TypeScript",
|
||||
"compilation",
|
||||
"nightly features",
|
||||
"CLI tool",
|
||||
"file compilation",
|
||||
"glob patterns",
|
||||
"compiler options",
|
||||
"development",
|
||||
"API"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tsdoc": {
|
||||
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
|
||||
}
|
||||
}
|
||||
3088
package-lock.json
generated
3088
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
58
package.json
58
package.json
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "@gitzone/tsbuild",
|
||||
"version": "2.1.33",
|
||||
"name": "@git.zone/tsbuild",
|
||||
"version": "2.7.1",
|
||||
"private": false,
|
||||
"description": "TypeScript nightly to easily make use of latest features",
|
||||
"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",
|
||||
"typings": "dist_ts/index.d.ts",
|
||||
"type": "module",
|
||||
@@ -10,38 +10,46 @@
|
||||
"tsbuild": "./cli.js"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tsrun test/test.ts",
|
||||
"testCustom": "node cli.ts.js custom ts_web",
|
||||
"build": "node cli.ts.js --web"
|
||||
"test": "tstest test/test.ts --verbose",
|
||||
"build": "node cli.ts.js --web",
|
||||
"buildDocs": "tsdoc"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@gitlab.com/pushrocks/tsn.git"
|
||||
"url": "https://code.foss.global/git.zone/tsbuild.git"
|
||||
},
|
||||
"keywords": [
|
||||
"TypeScript"
|
||||
"TypeScript",
|
||||
"compilation",
|
||||
"nightly features",
|
||||
"CLI tool",
|
||||
"file compilation",
|
||||
"glob patterns",
|
||||
"compiler options",
|
||||
"development",
|
||||
"API"
|
||||
],
|
||||
"author": "Lossless GmbH",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://gitlab.com/pushrocks/tsn/issues"
|
||||
"url": "https://code.foss.global/git.zone/tsbuild/issues"
|
||||
},
|
||||
"homepage": "https://gitlab.com/pushrocks/tsn#README",
|
||||
"homepage": "https://code.foss.global/git.zone/tsbuild#README",
|
||||
"dependencies": {
|
||||
"@pushrocks/early": "^3.0.6",
|
||||
"@pushrocks/smartcli": "^3.0.14",
|
||||
"@pushrocks/smartfile": "^9.0.6",
|
||||
"@pushrocks/smartlog": "^2.0.44",
|
||||
"@pushrocks/smartpath": "^4.0.3",
|
||||
"@pushrocks/smartpromise": "^3.1.7",
|
||||
"typescript": "4.7.0-dev.20220311"
|
||||
"@git.zone/tspublish": "^1.10.3",
|
||||
"@push.rocks/early": "^4.0.4",
|
||||
"@push.rocks/smartcli": "^4.0.19",
|
||||
"@push.rocks/smartdelay": "^3.0.5",
|
||||
"@push.rocks/smartfile": "^11.2.7",
|
||||
"@push.rocks/smartlog": "^3.1.10",
|
||||
"@push.rocks/smartpath": "^6.0.0",
|
||||
"@push.rocks/smartpromise": "^4.2.3",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gitzone/tsrun": "^1.2.19",
|
||||
"@pushrocks/tapbundle": "^4.0.8",
|
||||
"@types/node": "^17.0.21",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-config-prettier": "^1.18.0"
|
||||
"@git.zone/tsrun": "^1.6.2",
|
||||
"@git.zone/tstest": "^2.7.0",
|
||||
"@types/node": "^22.15.21"
|
||||
},
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
@@ -54,5 +62,9 @@
|
||||
"cli.js",
|
||||
"npmextra.json",
|
||||
"readme.md"
|
||||
]
|
||||
],
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
],
|
||||
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
|
||||
}
|
||||
|
||||
9979
pnpm-lock.yaml
generated
Normal file
9979
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
4
pnpm-workspace.yaml
Normal file
4
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
onlyBuiltDependencies:
|
||||
- esbuild
|
||||
- mongodb-memory-server
|
||||
- puppeteer
|
||||
175
readme.hints.md
Normal file
175
readme.hints.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# @git.zone/tsbuild - Project Memory
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Public API (8 functions + 1 class)
|
||||
1. **compileFileArray()** - Basic compilation, throws on error
|
||||
2. **compileFileArrayWithErrorTracking()** - RECOMMENDED, returns IErrorSummary
|
||||
3. **compileGlobStringObject()** - Most powerful, multiple patterns
|
||||
4. **TsBuild Class** - Object-oriented API with compile, checkTypes, checkEmit methods
|
||||
5. **mergeCompilerOptions()** - Utility for option merging
|
||||
6. **compiler()** - Legacy function
|
||||
7. **emitCheck()** - Validate emit capability
|
||||
8. **checkTypes()** - Type checking only
|
||||
|
||||
### CLI Commands (5)
|
||||
1. **tsbuild** (default) - Compiles ./ts/**/*.ts → ./dist_ts/
|
||||
2. **tsbuild custom <dir1> <dir2>** - Custom directory compilation
|
||||
3. **tsbuild tsfolders** - Auto-discover ts_* folders, compile in order
|
||||
4. **tsbuild emitcheck <pattern>** - Validate emit without output
|
||||
5. **tsbuild check [pattern]** - Type check only
|
||||
|
||||
### CLI Flags
|
||||
- `--skiplibcheck` - Skip .d.ts type checking (shows warning)
|
||||
- `--confirmskiplibcheck` - Extended warning with 5s pause
|
||||
- `--disallowimplicitany` - Stricter type checking
|
||||
- `--commonjs` - Use CommonJS instead of ESNext
|
||||
- `--quiet` - Suppress non-error output
|
||||
- `--json` - JSON output format
|
||||
|
||||
## Key Architecture Decisions
|
||||
|
||||
### Configuration Priority (5 levels)
|
||||
1. Default options (hardcoded)
|
||||
2. tsconfig.json (if exists)
|
||||
3. Protected defaults (ensure integrity)
|
||||
4. Programmatic options (function params)
|
||||
5. CLI flags (highest priority)
|
||||
|
||||
### Protected Options
|
||||
Cannot be overridden by tsconfig.json alone:
|
||||
- `outDir: 'dist_ts/'` - Path transformation logic
|
||||
- `noEmitOnError: true` - Build integrity
|
||||
- `declaration: true` - Library support
|
||||
- `emitDecoratorMetadata: true` - DI frameworks
|
||||
- `inlineSourceMap: true` - Debugging
|
||||
|
||||
### Path Transformation
|
||||
- Automatic: `./ts_interfaces` → `./dist_ts_interfaces`
|
||||
- In tsconfig paths: `./ts_*` → `./dist_ts_*` (first array element only)
|
||||
|
||||
## Default Compiler Options
|
||||
- Module: NodeNext (ESM with CommonJS fallback)
|
||||
- Target: ESNext (latest JavaScript)
|
||||
- Decorators: ENABLED (experimentalDecorators + emitDecoratorMetadata)
|
||||
- Source Maps: Inline (no separate .map files)
|
||||
- Declaration Files: ALWAYS generated (protected)
|
||||
- Output: dist_ts/
|
||||
- Implicit any: ALLOWED by default
|
||||
- esModuleInterop: true
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Error Summary Structure
|
||||
```typescript
|
||||
interface IErrorSummary {
|
||||
errorsByFile: Record<string, Diagnostic[]>
|
||||
generalErrors: Diagnostic[]
|
||||
totalErrors: number
|
||||
totalFiles: number
|
||||
}
|
||||
```
|
||||
|
||||
### Three Error Patterns
|
||||
1. **Throw Pattern** - compileFileArray: throws on error
|
||||
2. **Tracking Pattern** - compileFileArrayWithErrorTracking: returns IErrorSummary, NO throw
|
||||
3. **Boolean Pattern** - checkTypes/emitCheck: returns boolean
|
||||
|
||||
RECOMMENDATION: Use compileFileArrayWithErrorTracking for production code
|
||||
|
||||
## JSON Output Format
|
||||
```json
|
||||
{
|
||||
"success": boolean,
|
||||
"totals": {
|
||||
"errors": number,
|
||||
"filesWithErrors": number,
|
||||
"tasks": number
|
||||
},
|
||||
"errorsByFile": {
|
||||
"fileName": [
|
||||
{ "code": number, "message": string }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Special Behaviors
|
||||
|
||||
### tsfolders Command Ordering
|
||||
1. Always: ts_interfaces first
|
||||
2. Always: ts_shared second
|
||||
3. Then: Other folders by `order` property in their tspublish.json
|
||||
4. Finally: Folders without order property (Infinity)
|
||||
|
||||
### check Command Default (No Arguments)
|
||||
Two-phase check:
|
||||
1. Phase 1: Type check ts/**/* (strict, include .d.ts)
|
||||
2. Phase 2: Type check test/**/* (relaxed, skipLibCheck: true)
|
||||
|
||||
### Glob Pattern Support
|
||||
- `*` single level
|
||||
- `**` recursive
|
||||
- `?` single char
|
||||
- `{a,b}` alternation
|
||||
- Duplicates: Files matching multiple patterns compile multiple times
|
||||
|
||||
### Task Information Display
|
||||
When compiling multiple files with taskInfo param:
|
||||
Shows: `[1/3] Compiling 45 files from ./src/**/*.ts`
|
||||
Plus: File counts, duration, and file type breakdown
|
||||
|
||||
## File Structure
|
||||
- **index.ts** - Main entry, re-exports all
|
||||
- **tsbuild.exports.ts** - Core API functions
|
||||
- **tsbuild.classes.tsbuild.ts** - TsBuild class + utility functions
|
||||
- **tsbuild.cli.ts** - CLI command definitions
|
||||
- **plugins.ts** - Dependency imports (smartfile, smartpath, smartcli, etc.)
|
||||
- **paths.ts** - Path utilities (cwd, packageDir)
|
||||
|
||||
## Dependencies Used
|
||||
- @git.zone/tspublish@^1.10.3 - Module ordering
|
||||
- @push.rocks/* - smartcli, smartfile, smartpath, smartpromise, smartdelay
|
||||
- typescript@5.9.3 - TypeScript compiler
|
||||
|
||||
## Edge Cases
|
||||
|
||||
1. **Empty file list** - Returns [], no error
|
||||
2. **Glob duplicates** - Files compile multiple times, possible duplicate errors
|
||||
3. **Non-existent files** - Handled by TypeScript "file not found" errors
|
||||
4. **skipLibCheck warning** - 1-line default, 5-second pause with --confirmskiplibcheck
|
||||
5. **Missing tsconfig.json** - Graceful fallback, no error
|
||||
6. **Module resolution** - --commonjs switches to NodeJs (not NodeNext)
|
||||
7. **Source maps** - Inline only (not separate .map files)
|
||||
8. **File filtering** - Only .ts and .tsx; .d.ts and .js ignored
|
||||
|
||||
## Build Safety Features
|
||||
- `noEmitOnError: true` - Prevents broken builds
|
||||
- Error aggregation before final output
|
||||
- Protected options ensure integrity
|
||||
- Pre-emit checks before emit phase
|
||||
- CLI exit code handling (0=success, 1=error)
|
||||
|
||||
## Recent Changes (from git log)
|
||||
- 2.6.8 - Current version
|
||||
- 2.6.7 - Previous version
|
||||
- Added confirmskiplibcheck flag
|
||||
- Improved CLI exit handling
|
||||
- JSON/quiet modes enhanced
|
||||
- Test script updates
|
||||
|
||||
## Configuration Example (tsconfig.json)
|
||||
Paths get automatically transformed:
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@utils/*": ["./ts_utils/*"] // → ["./dist_ts_utils/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## No ts_* folders found in project root
|
||||
The project itself doesn't have ts_interfaces, ts_shared, etc. directories.
|
||||
The tsfolders command is designed for OTHER projects using tsbuild.
|
||||
931
readme.md
931
readme.md
@@ -1,79 +1,894 @@
|
||||
# @gitzone/tsbuild
|
||||
TypeScript nightly to easily make use of latest features
|
||||
# @git.zone/tsbuild
|
||||
|
||||
## Availabililty and Links
|
||||
* [npmjs.org (npm package)](https://www.npmjs.com/package/@gitzone/tsbuild)
|
||||
* [gitlab.com (source)](https://gitlab.com/gitzone/tsbuild)
|
||||
* [github.com (source mirror)](https://github.com/gitzone/tsbuild)
|
||||
* [docs (typedoc)](https://gitzone.gitlab.io/tsbuild/)
|
||||
> 🚀 **A powerful, modern TypeScript build tool with smart defaults and full tsconfig.json support**
|
||||
|
||||
## Status for master
|
||||
[](https://gitlab.com/gitzone/tsbuild/commits/master)
|
||||
[](https://gitlab.com/gitzone/tsbuild/commits/master)
|
||||
[](https://www.npmjs.com/package/@gitzone/tsbuild)
|
||||
[](https://snyk.io/test/npm/@gitzone/tsbuild)
|
||||
[](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||
[](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||
[](https://prettier.io/)
|
||||
A production-ready TypeScript compiler that combines flexibility with safety. Built for modern JavaScript development with ESNext, NodeNext modules, and automatic decorator support.
|
||||
|
||||
## Usage
|
||||
## Why tsbuild?
|
||||
|
||||
Tsn uses the **next** tagged npm version of typescript
|
||||
- ✅ **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
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @git.zone/tsbuild --save-dev
|
||||
```
|
||||
|
||||
or with pnpm:
|
||||
|
||||
```bash
|
||||
pnpm install @git.zone/tsbuild --save-dev
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### CLI Usage
|
||||
|
||||
**Compile your TypeScript project:**
|
||||
```bash
|
||||
npx tsbuild
|
||||
```
|
||||
Compiles `./ts/**/*.ts` → `./dist_ts/`
|
||||
|
||||
**Custom directories:**
|
||||
```bash
|
||||
npx tsbuild custom src utils
|
||||
```
|
||||
Compiles:
|
||||
- `./src/**/*.ts` → `./dist_src/`
|
||||
- `./utils/**/*.ts` → `./dist_utils/`
|
||||
|
||||
**Auto-discover and compile in dependency order:**
|
||||
```bash
|
||||
npx tsbuild tsfolders
|
||||
```
|
||||
Finds all `ts_*` folders and compiles them respecting dependencies.
|
||||
|
||||
### Programmatic Usage
|
||||
|
||||
**Basic compilation:**
|
||||
```typescript
|
||||
import * as tsn from 'tsn';
|
||||
import { compileFileArray } from '@git.zone/tsbuild';
|
||||
|
||||
let myGlobStringObject = {
|
||||
'./myTsFolder/**/*.ts': './myDestinationFolder/',
|
||||
'./someOtherTsFolder/**/*.ts': './myOtherDestinationFolder/'
|
||||
};
|
||||
await compileFileArray([
|
||||
'./src/index.ts',
|
||||
'./src/utils.ts'
|
||||
]);
|
||||
```
|
||||
|
||||
let tsOptions = {
|
||||
target: tsn.ScriptTarget.ES2015,
|
||||
module: tsn.ModuleKind.CommonJS
|
||||
};
|
||||
**Production-ready with error tracking (recommended):**
|
||||
```typescript
|
||||
import { compileFileArrayWithErrorTracking } from '@git.zone/tsbuild';
|
||||
|
||||
/*
|
||||
note: since this only works in code, here are the target numbers
|
||||
enum ScriptTarget {
|
||||
ES3 = 0,
|
||||
ES5 = 1,
|
||||
ES2015 = 2,
|
||||
ES2016 = 3,
|
||||
ES2017 = 4,
|
||||
ESNext = 5,
|
||||
Latest = 5,
|
||||
const result = await compileFileArrayWithErrorTracking([
|
||||
'./src/**/*.ts'
|
||||
], {
|
||||
target: 'ES2022',
|
||||
module: 'NodeNext'
|
||||
});
|
||||
|
||||
if (result.hasErrors) {
|
||||
console.error('Compilation failed!');
|
||||
console.error('Files with errors:', result.fileCount);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
and here are the module kinds
|
||||
enum ModuleKind {
|
||||
None = 0,
|
||||
CommonJS = 1,
|
||||
AMD = 2,
|
||||
UMD = 3,
|
||||
System = 4,
|
||||
ES2015 = 5,
|
||||
}
|
||||
*/
|
||||
console.log('✅ Compilation successful!');
|
||||
```
|
||||
|
||||
let myCwd = process.cwd();
|
||||
**Advanced glob compilation:**
|
||||
```typescript
|
||||
import { compileGlobStringObject } from '@git.zone/tsbuild';
|
||||
|
||||
tsn.compileGlobStringObject(
|
||||
myGlobStringObject, // the glob string object describing from where to compile what to where
|
||||
tsOptions, // the options for TypeScript
|
||||
myCwd // a custom cwd, optional, defaults to process.cwd()
|
||||
await compileGlobStringObject({
|
||||
'./ts/**/*.ts': './dist_ts',
|
||||
'./ts_web/**/*.ts': './dist_web'
|
||||
}, {
|
||||
target: 'ES2022',
|
||||
module: 'ESNext'
|
||||
});
|
||||
```
|
||||
|
||||
## CLI Commands
|
||||
|
||||
### 1. Default Build
|
||||
|
||||
```bash
|
||||
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
|
||||
- `--disallowimplicitany` - Disallow implicit `any` types
|
||||
- `--commonjs` - Use CommonJS instead of ESNext modules
|
||||
- `--json` - Output results as JSON (for CI/CD)
|
||||
- `--quiet` - Suppress console output
|
||||
|
||||
**Examples:**
|
||||
```bash
|
||||
# Standard build
|
||||
npx tsbuild
|
||||
|
||||
# Build with JSON output for CI
|
||||
npx tsbuild --json --quiet
|
||||
|
||||
# CommonJS build
|
||||
npx tsbuild --commonjs
|
||||
```
|
||||
|
||||
### 2. Custom Directories
|
||||
|
||||
```bash
|
||||
npx tsbuild custom <dir1> <dir2> ... [options]
|
||||
```
|
||||
|
||||
Compile specific directories to their corresponding `dist_` folders.
|
||||
|
||||
**Examples:**
|
||||
```bash
|
||||
# Compile src and utils
|
||||
npx tsbuild custom src utils
|
||||
# Creates: ./dist_src/ and ./dist_utils/
|
||||
|
||||
# Multiple directories with options
|
||||
npx tsbuild custom api models services --commonjs
|
||||
```
|
||||
|
||||
### 3. TSFolders (Dependency-Aware)
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
**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
|
||||
...
|
||||
```
|
||||
|
||||
### 4. Emit Check
|
||||
|
||||
```bash
|
||||
npx tsbuild emitcheck <file_or_pattern> [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:**
|
||||
- `0` - All files can be emitted
|
||||
- `1` - One or more files have errors
|
||||
|
||||
### 5. Type Check
|
||||
|
||||
```bash
|
||||
npx tsbuild check <pattern> [more...] [options]
|
||||
```
|
||||
|
||||
Performs type checking without emitting files. Faster than emitcheck.
|
||||
|
||||
**Examples:**
|
||||
```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
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Core Functions
|
||||
|
||||
#### `compileFileArray(files, options?, argv?)`
|
||||
|
||||
Basic compilation of file array.
|
||||
|
||||
**Parameters:**
|
||||
- `files: string[]` - File paths to compile
|
||||
- `options?: CompilerOptions` - TypeScript compiler options
|
||||
- `argv?: any` - CLI arguments object
|
||||
|
||||
**Returns:** `Promise<any[]>` - Compiled file results
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
import { compileFileArray } from '@git.zone/tsbuild';
|
||||
|
||||
await compileFileArray(
|
||||
['./src/index.ts', './src/utils.ts'],
|
||||
{ target: 'ES2022' }
|
||||
);
|
||||
```
|
||||
|
||||
[](https://push.rocks)
|
||||
#### `compileFileArrayWithErrorTracking(files, options?, argv?, taskInfo?)`
|
||||
|
||||
## Contribution
|
||||
**⭐ RECOMMENDED for production** - Provides detailed error tracking and metrics.
|
||||
|
||||
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
|
||||
**Parameters:**
|
||||
- `files: string[]` - File paths to compile
|
||||
- `options?: CompilerOptions` - TypeScript compiler options
|
||||
- `argv?: any` - CLI arguments object
|
||||
- `taskInfo?: ITaskInfo` - Task metadata for progress reporting
|
||||
|
||||
For further information read the linked docs at the top of this readme.
|
||||
**Returns:** `Promise<IErrorSummary>` - Detailed error summary
|
||||
|
||||
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
|
||||
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
|
||||
**IErrorSummary Interface:**
|
||||
```typescript
|
||||
interface IErrorSummary {
|
||||
hasErrors: boolean;
|
||||
errorCount: number;
|
||||
fileCount: number;
|
||||
errorsByFile: Record<string, Diagnostic[]>;
|
||||
generalErrors: Diagnostic[];
|
||||
}
|
||||
```
|
||||
|
||||
[](https://maintainedby.lossless.com)
|
||||
**Example:**
|
||||
```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}`));
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('✅ Compilation successful!');
|
||||
```
|
||||
|
||||
#### `compileGlobStringObject(globObject, options?, cwd?, argv?)`
|
||||
|
||||
**Most powerful API** - Compile multiple glob patterns to different destinations.
|
||||
|
||||
**Parameters:**
|
||||
- `globObject: Record<string, string>` - Maps glob patterns to output directories
|
||||
- `options?: CompilerOptions` - TypeScript compiler options
|
||||
- `cwd?: string` - Working directory (defaults to `process.cwd()`)
|
||||
- `argv?: any` - CLI arguments object
|
||||
|
||||
**Returns:** `Promise<any[]>` - 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'
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
#### `checkTypes(files, options?, argv?)`
|
||||
|
||||
Type check files without emitting. Fast validation.
|
||||
|
||||
**Parameters:**
|
||||
- `files: string[]` - Files to check
|
||||
- `options?: CompilerOptions` - Compiler options
|
||||
- `argv?: any` - CLI arguments
|
||||
|
||||
**Returns:** `Promise<IErrorSummary>` - Error summary
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
import { checkTypes } from '@git.zone/tsbuild';
|
||||
|
||||
const result = await checkTypes(['./src/**/*.ts']);
|
||||
|
||||
if (result.hasErrors) {
|
||||
console.error('Type errors found!');
|
||||
process.exit(1);
|
||||
}
|
||||
```
|
||||
|
||||
#### `emitCheck(files, options?, argv?)`
|
||||
|
||||
Validate files can be emitted without actually emitting.
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
import { emitCheck } from '@git.zone/tsbuild';
|
||||
|
||||
const result = await emitCheck(['./src/index.ts']);
|
||||
|
||||
if (result.hasErrors) {
|
||||
console.error('Cannot emit these files!');
|
||||
}
|
||||
```
|
||||
|
||||
### TsBuild Class
|
||||
|
||||
Object-oriented API with full control.
|
||||
|
||||
**Constructor:**
|
||||
```typescript
|
||||
new TsBuild(
|
||||
fileNames?: string[],
|
||||
customOptions?: CompilerOptions,
|
||||
argvArg?: any,
|
||||
taskInfo?: ITaskInfo
|
||||
)
|
||||
```
|
||||
|
||||
**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)
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
import { TsBuild } from '@git.zone/tsbuild';
|
||||
|
||||
const builder = new TsBuild(
|
||||
['./src/**/*.ts'],
|
||||
{ target: 'ES2022', strict: true }
|
||||
);
|
||||
|
||||
const result = await builder.compileWithErrorTracking();
|
||||
|
||||
if (result.hasErrors) {
|
||||
console.error('Build failed!');
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### tsconfig.json Support
|
||||
|
||||
tsbuild **fully supports** all compiler options from `tsconfig.json`. Your project configuration is respected and intelligently merged.
|
||||
|
||||
**Example tsconfig.json:**
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"verbatimModuleSyntax": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Priority (Merge Order)
|
||||
|
||||
When multiple configuration sources exist, they merge in this order (later overrides earlier):
|
||||
|
||||
1. **Default Options** - tsbuild's sensible defaults
|
||||
2. **tsconfig.json** - All options from your tsconfig.json (if present)
|
||||
3. **Protected Defaults** - Critical options for build integrity
|
||||
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):
|
||||
|
||||
- **`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:
|
||||
|
||||
```typescript
|
||||
{
|
||||
declaration: true, // Generate .d.ts files
|
||||
emitDecoratorMetadata: true, // Support DI frameworks
|
||||
experimentalDecorators: true, // Enable decorators
|
||||
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'],
|
||||
noImplicitAny: false, // Flexible for quick development
|
||||
esModuleInterop: true, // CJS/ESM interop
|
||||
useDefineForClassFields: false, // Classic decorator behavior
|
||||
verbatimModuleSyntax: true, // Explicit imports/exports
|
||||
baseUrl: './'
|
||||
}
|
||||
```
|
||||
|
||||
### CLI Flags
|
||||
|
||||
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:
|
||||
|
||||
**tsconfig.json:**
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@models/*": ["./ts_models/*"],
|
||||
"@utils/*": ["./ts_utils/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Automatic transformation:**
|
||||
```
|
||||
./ts_models/* → ./dist_ts_models/*
|
||||
./ts_utils/* → ./dist_ts_utils/*
|
||||
```
|
||||
|
||||
This ensures imports work correctly in compiled output.
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Error Handling Patterns
|
||||
|
||||
**Pattern 1: Simple (throw on error)**
|
||||
```typescript
|
||||
import { compileFileArray } from '@git.zone/tsbuild';
|
||||
|
||||
try {
|
||||
await compileFileArray(['./src/**/*.ts']);
|
||||
console.log('✅ Build successful');
|
||||
} catch (error) {
|
||||
console.error('❌ Build failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
```
|
||||
|
||||
**Pattern 2: Detailed tracking (recommended)**
|
||||
```typescript
|
||||
import { compileFileArrayWithErrorTracking } from '@git.zone/tsbuild';
|
||||
|
||||
const result = await compileFileArrayWithErrorTracking(['./src/**/*.ts']);
|
||||
|
||||
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:
|
||||
|
||||
```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(
|
||||
@Inject('CONFIG') private config: Config,
|
||||
private logger: Logger
|
||||
) {}
|
||||
}
|
||||
```
|
||||
|
||||
The following options are enabled by default:
|
||||
- `experimentalDecorators: true`
|
||||
- `emitDecoratorMetadata: true`
|
||||
|
||||
This means frameworks like **NestJS**, **TypeORM**, **Inversify**, and **Angular** work without extra setup.
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
```yaml
|
||||
name: Build
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- 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
|
||||
```
|
||||
|
||||
### GitLab CI
|
||||
|
||||
```yaml
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- npm install
|
||||
- npx tsbuild
|
||||
artifacts:
|
||||
paths:
|
||||
- dist_ts/
|
||||
```
|
||||
|
||||
### Package.json Scripts
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"build": "tsbuild",
|
||||
"build:watch": "tsbuild && chokidar 'ts/**/*.ts' -c 'tsbuild'",
|
||||
"build:prod": "tsbuild --disallowimplicitany",
|
||||
"typecheck": "tsbuild check 'ts/**/*.ts'",
|
||||
"pretest": "tsbuild emitcheck 'test/**/*.ts'"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**"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.
|
||||
|
||||
**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
|
||||
```
|
||||
|
||||
This catches implicit `any` types that can hide bugs.
|
||||
|
||||
**Slow compilation**
|
||||
|
||||
Use `--skiplibcheck` to skip declaration file checking:
|
||||
```bash
|
||||
npx tsbuild --confirmskiplibcheck
|
||||
```
|
||||
|
||||
⚠️ Only use this if you trust your dependencies' type definitions.
|
||||
|
||||
### Debug Mode
|
||||
|
||||
For troubleshooting, combine flags:
|
||||
|
||||
```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.
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
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.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
|
||||
45
readme.plan.md
Normal file
45
readme.plan.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Implementation Plan for tsbuild `check` Command
|
||||
|
||||
## Overview
|
||||
Add a new `check` command to tsbuild that allows checking TypeScript files against a glob pattern without emitting them, similar to running the TypeScript compiler with the `--noEmit` flag.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. **Reread CLAUDE.md** to ensure we follow project guidelines
|
||||
|
||||
2. **Extend TsBuild Class**
|
||||
- The existing `TsBuild` class already has a `checkEmit()` method
|
||||
- We can leverage this method for our implementation
|
||||
|
||||
3. **Implement Check Command in CLI**
|
||||
- Add a new `check` command to `tsbuild.cli.ts`
|
||||
- Command should accept glob patterns as arguments
|
||||
- Process glob patterns to find matching TypeScript files
|
||||
- Use the `TsBuild` class to check the files without emitting
|
||||
|
||||
4. **Update Exports**
|
||||
- Ensure any new functionality is properly exported
|
||||
|
||||
5. **Testing**
|
||||
- Test the command with various glob patterns
|
||||
- Verify error reporting works correctly
|
||||
|
||||
## Differences from Existing `emitcheck` Command
|
||||
The `emitcheck` command already exists and checks specific files without emitting. Our new `check` command will:
|
||||
- Be designed specifically for checking files against glob patterns
|
||||
- Use a simpler, more intuitive command name
|
||||
- Potentially add additional benefits (like summary statistics of checked files)
|
||||
|
||||
## Example Usage
|
||||
Once implemented, the command would work like this:
|
||||
|
||||
```bash
|
||||
npx tsbuild check ts/**/*
|
||||
npx tsbuild check "src/**/*.ts" "test/**/*.ts"
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
The command should:
|
||||
- Report any TypeScript errors in the matched files
|
||||
- Provide a count of files checked and any errors found
|
||||
- Exit with code 0 if successful, or 1 if errors are found
|
||||
@@ -1,9 +1,9 @@
|
||||
console.log('test');
|
||||
console.log('test2');
|
||||
import * as early from '@pushrocks/early';
|
||||
import * as early from '@push.rocks/early';
|
||||
early.start();
|
||||
early.stop();
|
||||
import { anExportedString } from './tocompile2';
|
||||
import { anExportedString } from './tocompile2.js';
|
||||
console.log(anExportedString);
|
||||
class test2 {
|
||||
constructor() {
|
||||
@@ -14,4 +14,4 @@ class test2 {
|
||||
const run = async () => {
|
||||
return 'hi';
|
||||
};
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9jb21waWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdG9jb21waWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDcEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUVyQixPQUFPLEtBQUssS0FBSyxNQUFNLGtCQUFrQixDQUFDO0FBRTFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUNkLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUViLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLGNBQWMsQ0FBQztBQUM5QyxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUFnQixDQUFDLENBQUM7QUFFOUIsTUFBTSxLQUFLO0lBRVQ7UUFEQSxTQUFJLEdBQWEsRUFBRSxDQUFDO1FBRWxCLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDcEIsQ0FBQztDQUNGO0FBRUQsTUFBTSxHQUFHLEdBQUcsS0FBSyxJQUFxQixFQUFFO0lBQ3RDLE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQyxDQUFDIn0=
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9jb21waWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdG9jb21waWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDcEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUVyQixPQUFPLEtBQUssS0FBSyxNQUFNLG1CQUFtQixDQUFDO0FBRTNDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUNkLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUViLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUU5QixNQUFNLEtBQUs7SUFFVDtRQURBLFNBQUksR0FBYSxFQUFFLENBQUM7UUFFbEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQixDQUFDO0NBQ0Y7QUFFRCxNQUFNLEdBQUcsR0FBRyxLQUFLLElBQXFCLEVBQUU7SUFDdEMsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDLENBQUMifQ==
|
||||
@@ -1,12 +1,12 @@
|
||||
console.log('test');
|
||||
console.log('test2');
|
||||
|
||||
import * as early from '@pushrocks/early';
|
||||
import * as early from '@push.rocks/early';
|
||||
|
||||
early.start();
|
||||
early.stop();
|
||||
|
||||
import {anExportedString} from './tocompile2';
|
||||
import { anExportedString } from './tocompile2.js';
|
||||
console.log(anExportedString);
|
||||
|
||||
class test2 {
|
||||
|
||||
10
test/test.ts
10
test/test.ts
@@ -1,18 +1,18 @@
|
||||
import { tap, expect, expectAsync } from '@pushrocks/tapbundle';
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
|
||||
import * as tsbuild from '../ts/index';
|
||||
import * as tsbuild from '../ts/index.js';
|
||||
|
||||
let assetfiles: string[] = ['./test/assets/tocompile.ts', './test/assets/tocompile2.ts'];
|
||||
|
||||
let assetfiles2 = {
|
||||
'./test/assets/**/!(*.d.ts|*.js|output)': './test/assets/output'
|
||||
'./test/assets/**/!(*.d.ts|*.js|output)': './test/assets/output',
|
||||
};
|
||||
|
||||
tap.test('should convert files from an array with single files to output', async tools => {
|
||||
tap.test('should convert files from an array with single files to output', async (tools) => {
|
||||
tsbuild.compileFileArray(assetfiles, { outDir: './test/assets/output' });
|
||||
});
|
||||
|
||||
tap.test('should convert files from an array with single files to output', async tools => {
|
||||
tap.test('should convert files from an array with single files to output', async (tools) => {
|
||||
tsbuild.compileGlobStringObject(assetfiles2);
|
||||
});
|
||||
|
||||
|
||||
8
ts/00_commitinfo_data.ts
Normal file
8
ts/00_commitinfo_data.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @push.rocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@git.zone/tsbuild',
|
||||
version: '2.7.1',
|
||||
description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.'
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as early from '@pushrocks/early';
|
||||
import * as early from '@push.rocks/early';
|
||||
early.start('tsbuild');
|
||||
export * from './tsbuild.exports';
|
||||
export * from './tsbuild.cli';
|
||||
export * from './tsbuild.exports.js';
|
||||
export * from './tsbuild.cli.js';
|
||||
early.stop();
|
||||
4
ts/paths.ts
Normal file
4
ts/paths.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import * as plugins from './plugins.js';
|
||||
|
||||
export const cwd = process.cwd();
|
||||
export const packageDir = plugins.path.join(plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url), '../');
|
||||
29
ts/plugins.ts
Normal file
29
ts/plugins.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
// node native
|
||||
import * as path from 'path';
|
||||
|
||||
export {
|
||||
path
|
||||
}
|
||||
|
||||
// @git.zone scope
|
||||
import * as tspublish from '@git.zone/tspublish';
|
||||
|
||||
export {
|
||||
tspublish
|
||||
}
|
||||
|
||||
// @push.rocks scope
|
||||
import * as smartcli from '@push.rocks/smartcli';
|
||||
import * as smartdelay from '@push.rocks/smartdelay';
|
||||
import * as smartfile from '@push.rocks/smartfile';
|
||||
import * as smartpath from '@push.rocks/smartpath';
|
||||
import * as smartpromise from '@push.rocks/smartpromise';
|
||||
|
||||
export { smartcli, smartdelay, smartfile, smartpath, smartpromise };
|
||||
|
||||
// third party scope
|
||||
import typescript from 'typescript';
|
||||
|
||||
export {
|
||||
typescript
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
// import all the stuff we need
|
||||
import * as plugins from './tsbuild.plugins';
|
||||
import { CompilerOptions } from 'typescript';
|
||||
export { CompilerOptions, ScriptTarget, ModuleKind } from 'typescript';
|
||||
|
||||
/**
|
||||
* the default typescript compilerOptions
|
||||
*/
|
||||
export const compilerOptionsDefault: CompilerOptions = {
|
||||
declaration: true,
|
||||
emitDecoratorMetadata: true,
|
||||
experimentalDecorators: true,
|
||||
inlineSourceMap: true,
|
||||
noEmitOnError: true,
|
||||
outDir: 'dist_ts/',
|
||||
module: plugins.typescript.ModuleKind.ES2020,
|
||||
moduleResolution: plugins.typescript.ModuleResolutionKind.Node12,
|
||||
lib: [],
|
||||
noImplicitAny: false,
|
||||
esModuleInterop: true,
|
||||
target: plugins.typescript.ScriptTarget.ES2020,
|
||||
importsNotUsedAsValues: plugins.typescript.ImportsNotUsedAsValues.Preserve
|
||||
};
|
||||
|
||||
export const compilerOptionsWebDefault: CompilerOptions = {
|
||||
...compilerOptionsDefault,
|
||||
lib: [...compilerOptionsDefault.lib, 'lib.dom.d.ts']
|
||||
};
|
||||
|
||||
/**
|
||||
* merges compilerOptions with the default compiler options
|
||||
*/
|
||||
export const mergeCompilerOptions = (
|
||||
customTsOptions: CompilerOptions,
|
||||
argvArg?: any
|
||||
): CompilerOptions => {
|
||||
const defaultOptionsToMerge = (() => {
|
||||
if (argvArg && argvArg.web) {
|
||||
return compilerOptionsWebDefault;
|
||||
} else {
|
||||
return compilerOptionsDefault;
|
||||
}
|
||||
})();
|
||||
|
||||
// create merged options
|
||||
const mergedOptions: CompilerOptions = {
|
||||
...defaultOptionsToMerge,
|
||||
...customTsOptions,
|
||||
...argvArg && argvArg.skiplibcheck ? {
|
||||
skipLibCheck: true
|
||||
} : {},
|
||||
};
|
||||
|
||||
return mergedOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
* the internal main compiler function that compiles the files
|
||||
*/
|
||||
export const compiler = (
|
||||
fileNames: string[],
|
||||
options: plugins.typescript.CompilerOptions,
|
||||
argvArg?: any
|
||||
): Promise<any[]> => {
|
||||
console.log(`Compiling ${fileNames.length} files...`);
|
||||
const done = plugins.smartpromise.defer<any[]>();
|
||||
const program = plugins.typescript.createProgram(fileNames, options);
|
||||
const emitResult = program.emit();
|
||||
|
||||
// implement check only
|
||||
/*let emitResult = program.emit(undefined,(args) => {
|
||||
console.log(args)
|
||||
});*/
|
||||
|
||||
const allDiagnostics = plugins.typescript
|
||||
.getPreEmitDiagnostics(program)
|
||||
.concat(emitResult.diagnostics);
|
||||
allDiagnostics.forEach(diagnostic => {
|
||||
if (diagnostic.file) {
|
||||
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
|
||||
const message = plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
||||
console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
|
||||
} else {
|
||||
console.log(
|
||||
`${plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const exitCode = emitResult.emitSkipped ? 1 : 0;
|
||||
if (exitCode === 0) {
|
||||
console.log('TypeScript emit succeeded!');
|
||||
done.resolve(emitResult.emittedFiles);
|
||||
} else {
|
||||
console.error('TypeScript emit failed. Please investigate!');
|
||||
process.exit(exitCode);
|
||||
}
|
||||
|
||||
return done.promise;
|
||||
};
|
||||
596
ts/tsbuild.classes.tsbuild.ts
Normal file
596
ts/tsbuild.classes.tsbuild.ts
Normal file
@@ -0,0 +1,596 @@
|
||||
// import all the stuff we need
|
||||
import * as plugins from './plugins.js';
|
||||
import * as paths from './paths.js';
|
||||
import type { CompilerOptions, ScriptTarget, ModuleKind } from './tsbuild.exports.js';
|
||||
|
||||
/**
|
||||
* Interface for error summary data
|
||||
*/
|
||||
export interface IErrorSummary {
|
||||
errorsByFile: Record<string, plugins.typescript.Diagnostic[]>;
|
||||
generalErrors: plugins.typescript.Diagnostic[];
|
||||
totalErrors: number;
|
||||
totalFiles: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default compiler options for TypeScript compilation
|
||||
*/
|
||||
export const compilerOptionsDefault: CompilerOptions = {
|
||||
declaration: true,
|
||||
emitDecoratorMetadata: true,
|
||||
experimentalDecorators: true,
|
||||
inlineSourceMap: true,
|
||||
noEmitOnError: true,
|
||||
outDir: 'dist_ts/',
|
||||
module: plugins.typescript.ModuleKind.NodeNext,
|
||||
target: plugins.typescript.ScriptTarget.ESNext,
|
||||
moduleResolution: plugins.typescript.ModuleResolutionKind.NodeNext,
|
||||
lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'],
|
||||
noImplicitAny: false, // Allow implicit any by default
|
||||
esModuleInterop: true,
|
||||
useDefineForClassFields: false,
|
||||
verbatimModuleSyntax: true,
|
||||
baseUrl: './',
|
||||
};
|
||||
|
||||
/**
|
||||
* TsBuild class for handling TypeScript compilation
|
||||
*/
|
||||
export class TsBuild {
|
||||
private fileNames: string[] = [];
|
||||
private options: plugins.typescript.CompilerOptions;
|
||||
private argvArg?: any;
|
||||
private taskInfo?: any;
|
||||
|
||||
/**
|
||||
* Create a new TsBuild instance
|
||||
*/
|
||||
constructor(
|
||||
fileNames: string[] = [],
|
||||
customOptions: CompilerOptions = {},
|
||||
argvArg?: any,
|
||||
taskInfo?: any
|
||||
) {
|
||||
this.fileNames = fileNames;
|
||||
this.argvArg = argvArg;
|
||||
this.taskInfo = taskInfo;
|
||||
this.options = this.mergeCompilerOptions(customOptions, argvArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to read and process tsconfig.json
|
||||
*/
|
||||
private getTsConfigOptions(): CompilerOptions {
|
||||
let tsconfig: any;
|
||||
|
||||
// Try to read tsconfig.json, but don't fail if it doesn't exist
|
||||
try {
|
||||
tsconfig = plugins.smartfile.fs.toObjectSync(plugins.path.join(paths.cwd, 'tsconfig.json'));
|
||||
} catch (error) {
|
||||
// tsconfig.json doesn't exist or is invalid - use defaults
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!tsconfig || !tsconfig.compilerOptions) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// 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 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)) {
|
||||
if (Array.isArray(returnObject.paths[path]) && returnObject.paths[path].length > 0) {
|
||||
returnObject.paths[path][0] = returnObject.paths[path][0].replace('./ts_', './dist_ts_');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns critical default options that should not be overridden by tsconfig.json
|
||||
* These options are essential for tsbuild's functionality and build integrity
|
||||
*/
|
||||
private getCriticalDefaults(): CompilerOptions {
|
||||
return {
|
||||
outDir: 'dist_ts/', // Required for path transformation logic
|
||||
noEmitOnError: true, // Build integrity - prevent broken builds
|
||||
declaration: true, // Library consumers depend on .d.ts files
|
||||
emitDecoratorMetadata: true, // Required for dependency injection frameworks
|
||||
inlineSourceMap: true, // Consistent debugging experience
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Process command line arguments and return applicable compiler options
|
||||
*/
|
||||
private getCommandLineOptions(argvArg?: any): CompilerOptions {
|
||||
if (!argvArg) return {};
|
||||
|
||||
const options: CompilerOptions = {};
|
||||
|
||||
if (argvArg.skiplibcheck) {
|
||||
options.skipLibCheck = true;
|
||||
}
|
||||
|
||||
// Changed behavior: --disallowimplicitany instead of --allowimplicitany
|
||||
if (argvArg.disallowimplicitany) {
|
||||
options.noImplicitAny = true;
|
||||
}
|
||||
|
||||
if (argvArg.commonjs) {
|
||||
options.module = plugins.typescript.ModuleKind.CommonJS;
|
||||
options.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeJs;
|
||||
}
|
||||
|
||||
return 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(
|
||||
customTsOptions: CompilerOptions = {},
|
||||
argvArg?: any
|
||||
): CompilerOptions {
|
||||
// create merged options
|
||||
const mergedOptions: CompilerOptions = {
|
||||
...compilerOptionsDefault, // 1. All defaults
|
||||
...this.getTsConfigOptions(), // 2. User's tsconfig.json (all options)
|
||||
...this.getCriticalDefaults(), // 3. Protected overrides
|
||||
...customTsOptions, // 4. Programmatic options
|
||||
...this.getCommandLineOptions(argvArg), // 5. CLI flags (highest priority)
|
||||
};
|
||||
|
||||
return mergedOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to process TypeScript diagnostics and return error summary
|
||||
*/
|
||||
private processDiagnostics(diagnostics: readonly plugins.typescript.Diagnostic[]): IErrorSummary {
|
||||
const errorsByFile: Record<string, plugins.typescript.Diagnostic[]> = {};
|
||||
const generalErrors: plugins.typescript.Diagnostic[] = [];
|
||||
|
||||
// Categorize diagnostics
|
||||
diagnostics.forEach((diagnostic) => {
|
||||
if (diagnostic.file) {
|
||||
const fileName = diagnostic.file.fileName;
|
||||
if (!errorsByFile[fileName]) {
|
||||
errorsByFile[fileName] = [];
|
||||
}
|
||||
errorsByFile[fileName].push(diagnostic);
|
||||
} else {
|
||||
generalErrors.push(diagnostic);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
errorsByFile,
|
||||
generalErrors,
|
||||
totalErrors: diagnostics.length,
|
||||
totalFiles: Object.keys(errorsByFile).length
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to display error summary
|
||||
*/
|
||||
private displayErrorSummary(errorSummary: IErrorSummary): void {
|
||||
if (errorSummary.totalErrors === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { errorsByFile, generalErrors, totalErrors, totalFiles } = errorSummary;
|
||||
|
||||
// Print error summary header
|
||||
console.log('\n' + '='.repeat(80));
|
||||
console.log(`❌ Found ${totalErrors} error${totalErrors !== 1 ? 's' : ''} in ${totalFiles} file${totalFiles !== 1 ? 's' : ''}:`);
|
||||
console.log('='.repeat(80));
|
||||
|
||||
// Color codes for error formatting
|
||||
const colors = {
|
||||
reset: '\x1b[0m',
|
||||
red: '\x1b[31m',
|
||||
yellow: '\x1b[33m',
|
||||
cyan: '\x1b[36m',
|
||||
white: '\x1b[37m',
|
||||
brightRed: '\x1b[91m'
|
||||
};
|
||||
|
||||
// Print file-specific errors
|
||||
Object.entries(errorsByFile).forEach(([fileName, fileErrors]) => {
|
||||
// Show relative path if possible for cleaner output
|
||||
const displayPath = fileName.replace(process.cwd(), '').replace(/^\//, '');
|
||||
|
||||
console.log(`\n${colors.cyan}File: ${displayPath} ${colors.yellow}(${fileErrors.length} error${fileErrors.length !== 1 ? 's' : ''})${colors.reset}`);
|
||||
console.log('-'.repeat(80));
|
||||
|
||||
fileErrors.forEach((diagnostic) => {
|
||||
if (diagnostic.file && diagnostic.start !== undefined) {
|
||||
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
||||
const message = plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
||||
const errorCode = diagnostic.code ? `TS${diagnostic.code}` : 'Error';
|
||||
|
||||
console.log(`${colors.white}Line ${line + 1}, Col ${character + 1}${colors.reset}: ${colors.brightRed}${errorCode}${colors.reset} - ${message}`);
|
||||
|
||||
// Try to show the code snippet if possible
|
||||
try {
|
||||
const lineContent = diagnostic.file.text.split('\n')[line];
|
||||
if (lineContent) {
|
||||
// Show the line of code
|
||||
console.log(` ${lineContent.trimRight()}`);
|
||||
|
||||
// Show the error position indicator
|
||||
const indicator = ' '.repeat(character) + `${colors.red}^${colors.reset}`;
|
||||
console.log(` ${indicator}`);
|
||||
}
|
||||
} catch (e) {
|
||||
// Failed to get source text, skip showing the code snippet
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Print general errors
|
||||
if (generalErrors.length > 0) {
|
||||
console.log(`\n${colors.yellow}General Errors:${colors.reset}`);
|
||||
console.log('-'.repeat(80));
|
||||
|
||||
generalErrors.forEach((diagnostic) => {
|
||||
const message = plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
||||
const errorCode = diagnostic.code ? `TS${diagnostic.code}` : 'Error';
|
||||
console.log(`${colors.brightRed}${errorCode}${colors.reset}: ${message}`);
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n' + '='.repeat(80) + '\n');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a TypeScript program from file names and options
|
||||
*/
|
||||
private createProgram(
|
||||
options: plugins.typescript.CompilerOptions = this.options
|
||||
): plugins.typescript.Program {
|
||||
return plugins.typescript.createProgram(this.fileNames, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file names to be compiled
|
||||
*/
|
||||
public setFileNames(fileNames: string[]): void {
|
||||
this.fileNames = fileNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set compiler options
|
||||
*/
|
||||
public setOptions(options: CompilerOptions): void {
|
||||
this.options = { ...this.options, ...options };
|
||||
}
|
||||
|
||||
/**
|
||||
* The main compiler function that compiles the files and returns error summary
|
||||
*/
|
||||
public async compileWithErrorTracking(): Promise<{ emittedFiles: any[], errorSummary: IErrorSummary }> {
|
||||
if (this.options.skipLibCheck) {
|
||||
if (this.argvArg?.confirmskiplibcheck) {
|
||||
console.log('\n⚠️ WARNING ⚠️');
|
||||
console.log('You are skipping libcheck... Is that really wanted?');
|
||||
console.log('Continuing in 5 seconds...\n');
|
||||
await plugins.smartdelay.delayFor(5000);
|
||||
} else {
|
||||
// No delay by default; keep a short note unless in quiet/json modes
|
||||
if (!this.argvArg?.quiet && !this.argvArg?.json) {
|
||||
console.log('⚠️ skipLibCheck enabled; use --confirmskiplibcheck to pause with warning.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enhanced logging with task info
|
||||
const startTime = Date.now();
|
||||
if (this.taskInfo) {
|
||||
const { taskNumber, totalTasks, sourcePattern, destDir, fileCount } = this.taskInfo;
|
||||
const relativeDestDir = destDir.replace(process.cwd(), '').replace(/^\//, '');
|
||||
console.log(`\n🔨 [${taskNumber}/${totalTasks}] Compiling ${fileCount} file${fileCount !== 1 ? 's' : ''} from ${sourcePattern}`);
|
||||
console.log(` 📁 Output: ${relativeDestDir}`);
|
||||
} else {
|
||||
console.log(`🔨 Compiling ${this.fileNames.length} files...`);
|
||||
}
|
||||
|
||||
const done = plugins.smartpromise.defer<{ emittedFiles: any[], errorSummary: IErrorSummary }>();
|
||||
const program = this.createProgram();
|
||||
|
||||
// Check for pre-emit diagnostics first
|
||||
const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
|
||||
const preEmitErrorSummary = this.processDiagnostics(preEmitDiagnostics);
|
||||
|
||||
// Only continue to emit phase if no pre-emit errors
|
||||
if (preEmitErrorSummary.totalErrors > 0) {
|
||||
this.displayErrorSummary(preEmitErrorSummary);
|
||||
console.error('\n❌ TypeScript pre-emit checks failed. Please fix the issues listed above before proceeding.');
|
||||
console.error(' Type errors must be resolved before the compiler can emit output files.\n');
|
||||
// Return error summary instead of exiting to allow final summary display
|
||||
done.resolve({ emittedFiles: [], errorSummary: preEmitErrorSummary });
|
||||
return done.promise;
|
||||
}
|
||||
|
||||
// If no pre-emit errors, proceed with emit
|
||||
const emitResult = program.emit();
|
||||
const emitErrorSummary = this.processDiagnostics(emitResult.diagnostics);
|
||||
|
||||
// Combine error summaries
|
||||
const combinedErrorSummary: IErrorSummary = {
|
||||
errorsByFile: { ...preEmitErrorSummary.errorsByFile, ...emitErrorSummary.errorsByFile },
|
||||
generalErrors: [...preEmitErrorSummary.generalErrors, ...emitErrorSummary.generalErrors],
|
||||
totalErrors: preEmitErrorSummary.totalErrors + emitErrorSummary.totalErrors,
|
||||
totalFiles: Object.keys({ ...preEmitErrorSummary.errorsByFile, ...emitErrorSummary.errorsByFile }).length
|
||||
};
|
||||
|
||||
const exitCode = emitResult.emitSkipped ? 1 : 0;
|
||||
if (exitCode === 0) {
|
||||
const endTime = Date.now();
|
||||
const duration = endTime - startTime;
|
||||
|
||||
if (this.taskInfo) {
|
||||
const { taskNumber, totalTasks } = this.taskInfo;
|
||||
console.log(`✅ [${taskNumber}/${totalTasks}] Task completed in ${duration}ms`);
|
||||
} else {
|
||||
console.log(`✅ TypeScript emit succeeded! (${duration}ms)`);
|
||||
}
|
||||
|
||||
// Get count of emitted files by type
|
||||
const jsFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.js')).length || 0;
|
||||
const dtsFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.d.ts')).length || 0;
|
||||
const mapFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.map')).length || 0;
|
||||
|
||||
// If we have emitted files, show a summary
|
||||
if (emitResult.emittedFiles && emitResult.emittedFiles.length > 0) {
|
||||
console.log(` 📄 Generated ${emitResult.emittedFiles.length} files: ${jsFiles} .js, ${dtsFiles} .d.ts, ${mapFiles} source maps`);
|
||||
}
|
||||
|
||||
done.resolve({ emittedFiles: emitResult.emittedFiles || [], errorSummary: combinedErrorSummary });
|
||||
} else {
|
||||
this.displayErrorSummary(combinedErrorSummary);
|
||||
console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!');
|
||||
console.error(' No output files have been generated.\n');
|
||||
// Do not exit here; return error summary so caller can decide
|
||||
done.resolve({ emittedFiles: [], errorSummary: combinedErrorSummary });
|
||||
return done.promise;
|
||||
}
|
||||
|
||||
return done.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main compiler function that compiles the files
|
||||
*/
|
||||
public async compile(): Promise<any[]> {
|
||||
if (this.options.skipLibCheck) {
|
||||
if (this.argvArg?.confirmskiplibcheck) {
|
||||
console.log('\n⚠️ WARNING ⚠️');
|
||||
console.log('You are skipping libcheck... Is that really wanted?');
|
||||
console.log('Continuing in 5 seconds...\n');
|
||||
await plugins.smartdelay.delayFor(5000);
|
||||
} else {
|
||||
if (!this.argvArg?.quiet && !this.argvArg?.json) {
|
||||
console.log('⚠️ skipLibCheck enabled; use --confirmskiplibcheck to pause with warning.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`🔨 Compiling ${this.fileNames.length} files...`);
|
||||
const done = plugins.smartpromise.defer<any[]>();
|
||||
const program = this.createProgram();
|
||||
|
||||
// Check for pre-emit diagnostics first
|
||||
const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
|
||||
const preEmitErrorSummary = this.processDiagnostics(preEmitDiagnostics);
|
||||
|
||||
// Only continue to emit phase if no pre-emit errors
|
||||
if (preEmitErrorSummary.totalErrors > 0) {
|
||||
this.displayErrorSummary(preEmitErrorSummary);
|
||||
console.error('\n❌ TypeScript pre-emit checks failed. Please fix the issues listed above before proceeding.');
|
||||
console.error(' Type errors must be resolved before the compiler can emit output files.\n');
|
||||
// Throw instead of exiting to keep library pure
|
||||
throw new Error('TypeScript pre-emit checks failed.');
|
||||
}
|
||||
|
||||
// If no pre-emit errors, proceed with emit
|
||||
const emitResult = program.emit();
|
||||
const emitErrorSummary = this.processDiagnostics(emitResult.diagnostics);
|
||||
|
||||
const exitCode = emitResult.emitSkipped ? 1 : 0;
|
||||
if (exitCode === 0) {
|
||||
console.log('\n✅ TypeScript emit succeeded!');
|
||||
|
||||
// Get count of emitted files by type
|
||||
const jsFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.js')).length || 0;
|
||||
const dtsFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.d.ts')).length || 0;
|
||||
const mapFiles = emitResult.emittedFiles?.filter(f => f.endsWith('.map')).length || 0;
|
||||
|
||||
// If we have emitted files, show a summary
|
||||
if (emitResult.emittedFiles && emitResult.emittedFiles.length > 0) {
|
||||
console.log(` Generated ${emitResult.emittedFiles.length} files: ${jsFiles} .js, ${dtsFiles} .d.ts, ${mapFiles} source maps`);
|
||||
}
|
||||
|
||||
done.resolve(emitResult.emittedFiles);
|
||||
} else {
|
||||
this.displayErrorSummary(emitErrorSummary);
|
||||
console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!');
|
||||
console.error(' No output files have been generated.\n');
|
||||
// Throw instead of exiting to keep library pure
|
||||
throw new Error('TypeScript emit failed.');
|
||||
}
|
||||
|
||||
return done.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to check if files can be emitted without actually emitting them
|
||||
*/
|
||||
public async checkEmit(): Promise<boolean> {
|
||||
const fileCount = this.fileNames.length;
|
||||
console.log(`\n🔍 Checking if ${fileCount} file${fileCount !== 1 ? 's' : ''} can be emitted...`);
|
||||
|
||||
// Create a program with noEmit option
|
||||
const program = this.createProgram({
|
||||
...this.options,
|
||||
noEmit: true
|
||||
});
|
||||
|
||||
// Check for pre-emit diagnostics
|
||||
const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
|
||||
const preEmitErrorSummary = this.processDiagnostics(preEmitDiagnostics);
|
||||
|
||||
// Run the emit phase but with noEmit: true to check for emit errors without producing files
|
||||
const emitResult = program.emit(undefined, undefined, undefined, true);
|
||||
const emitErrorSummary = this.processDiagnostics(emitResult.diagnostics);
|
||||
|
||||
// Combine error summaries
|
||||
const combinedErrorSummary: IErrorSummary = {
|
||||
errorsByFile: { ...preEmitErrorSummary.errorsByFile, ...emitErrorSummary.errorsByFile },
|
||||
generalErrors: [...preEmitErrorSummary.generalErrors, ...emitErrorSummary.generalErrors],
|
||||
totalErrors: preEmitErrorSummary.totalErrors + emitErrorSummary.totalErrors,
|
||||
totalFiles: Object.keys({ ...preEmitErrorSummary.errorsByFile, ...emitErrorSummary.errorsByFile }).length
|
||||
};
|
||||
|
||||
const success = combinedErrorSummary.totalErrors === 0 && !emitResult.emitSkipped;
|
||||
|
||||
if (success) {
|
||||
console.log('\n✅ TypeScript emit check passed! All files can be emitted successfully.');
|
||||
console.log(` ${fileCount} file${fileCount !== 1 ? 's' : ''} ${fileCount !== 1 ? 'are' : 'is'} ready to be compiled.\n`);
|
||||
} else {
|
||||
this.displayErrorSummary(combinedErrorSummary);
|
||||
console.error('\n❌ TypeScript emit check failed. Please fix the issues listed above.');
|
||||
console.error(' The compilation cannot proceed until these errors are resolved.\n');
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to check TypeScript files for type errors without emission
|
||||
*/
|
||||
public async checkTypes(): Promise<boolean> {
|
||||
const fileCount = this.fileNames.length;
|
||||
console.log(`\n🔍 Type checking ${fileCount} TypeScript file${fileCount !== 1 ? 's' : ''}...`);
|
||||
|
||||
// Create a program with noEmit option explicitly set
|
||||
const program = this.createProgram({
|
||||
...this.options,
|
||||
noEmit: true
|
||||
});
|
||||
|
||||
// Check for type errors
|
||||
const diagnostics = plugins.typescript.getPreEmitDiagnostics(program);
|
||||
const errorSummary = this.processDiagnostics(diagnostics);
|
||||
|
||||
// Set success flag
|
||||
const success = errorSummary.totalErrors === 0;
|
||||
|
||||
if (success) {
|
||||
console.log('\n✅ TypeScript type check passed! No type errors found.');
|
||||
console.log(` All ${fileCount} file${fileCount !== 1 ? 's' : ''} passed type checking successfully.\n`);
|
||||
} else {
|
||||
this.displayErrorSummary(errorSummary);
|
||||
console.error('\n❌ TypeScript type check failed. Please fix the type errors listed above.');
|
||||
console.error(' The type checker found issues that need to be resolved.\n');
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges compilerOptions with the default compiler options (backward compatibility)
|
||||
*/
|
||||
export const mergeCompilerOptions = (
|
||||
customTsOptions: CompilerOptions,
|
||||
argvArg?: any
|
||||
): CompilerOptions => {
|
||||
const tsBuild = new TsBuild();
|
||||
return tsBuild.mergeCompilerOptions(customTsOptions, argvArg);
|
||||
};
|
||||
|
||||
/**
|
||||
* The internal main compiler function that compiles the files (backward compatibility)
|
||||
*/
|
||||
export const compiler = async (
|
||||
fileNames: string[],
|
||||
options: plugins.typescript.CompilerOptions,
|
||||
argvArg?: any
|
||||
): Promise<any[]> => {
|
||||
const tsBuild = new TsBuild(fileNames, options, argvArg);
|
||||
return tsBuild.compile();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to check if a TypeScript file can be emitted without actually emitting it (backward compatibility)
|
||||
*/
|
||||
export const emitCheck = async (
|
||||
fileNames: string[],
|
||||
options: plugins.typescript.CompilerOptions = {},
|
||||
argvArg?: any
|
||||
): Promise<boolean> => {
|
||||
const tsBuild = new TsBuild(fileNames, options, argvArg);
|
||||
return tsBuild.checkEmit();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to check TypeScript files for type errors without emission (backward compatibility)
|
||||
*/
|
||||
export const checkTypes = async (
|
||||
fileNames: string[],
|
||||
options: plugins.typescript.CompilerOptions = {},
|
||||
argvArg?: any
|
||||
): Promise<boolean> => {
|
||||
const tsBuild = new TsBuild(fileNames, options, argvArg);
|
||||
return tsBuild.checkTypes();
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as plugins from './tsbuild.plugins';
|
||||
import * as tsbuild from './tsbuild.exports';
|
||||
import * as plugins from './plugins.js';
|
||||
import * as paths from './paths.js';
|
||||
import * as tsbuild from './tsbuild.exports.js';
|
||||
|
||||
export const runCli = async () => {
|
||||
const tsbuildCli = new plugins.smartcli.Smartcli();
|
||||
@@ -7,8 +8,8 @@ export const runCli = async () => {
|
||||
/**
|
||||
* the standard task compiles anything in ts/ directory to dist directory
|
||||
*/
|
||||
tsbuildCli.standardTask().subscribe(async (argvArg) => {
|
||||
tsbuild.compileGlobStringObject(
|
||||
tsbuildCli.standardCommand().subscribe(async (argvArg) => {
|
||||
await tsbuild.compileGlobStringObject(
|
||||
{
|
||||
'./ts/**/*.ts': './dist_ts',
|
||||
},
|
||||
@@ -16,6 +17,10 @@ export const runCli = async () => {
|
||||
process.cwd(),
|
||||
argvArg
|
||||
);
|
||||
const summary = (argvArg as any)?.__tsbuildFinalErrorSummary;
|
||||
if (summary && summary.totalErrors > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -23,23 +28,311 @@ export const runCli = async () => {
|
||||
*/
|
||||
tsbuildCli.addCommand('custom').subscribe(async (argvArg) => {
|
||||
const listedDirectories = argvArg._;
|
||||
listedDirectories.shift();
|
||||
listedDirectories.shift(); // removes the first element that is "custom"
|
||||
const compilationCommandObject: { [key: string]: string } = {};
|
||||
for (const directory of listedDirectories) {
|
||||
compilationCommandObject[`./${directory}/**/*.ts`] = `./dist_${directory}`;
|
||||
}
|
||||
await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
|
||||
const summary = (argvArg as any)?.__tsbuildFinalErrorSummary;
|
||||
if (summary && summary.totalErrors > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
tsbuildCli.addCommand('element').subscribe(async (argvArg) => {
|
||||
await tsbuild.compileGlobStringObject(
|
||||
{
|
||||
'./ts_web/**/*.ts': 'dist_ts_web',
|
||||
},
|
||||
{},
|
||||
process.cwd(),
|
||||
{ web: true }
|
||||
);
|
||||
/**
|
||||
* the emitcheck command checks if a TypeScript file can be emitted without actually emitting it
|
||||
*/
|
||||
tsbuildCli.addCommand('emitcheck').subscribe(async (argvArg) => {
|
||||
const patterns = argvArg._.slice(1); // Remove the first element which is 'emitcheck'
|
||||
|
||||
if (patterns.length === 0) {
|
||||
console.error('\n❌ Error: Please provide at least one TypeScript file path or glob pattern');
|
||||
console.error(' Usage: tsbuild emitcheck <file_or_glob_pattern> [additional_patterns ...]\n');
|
||||
console.error(' Example: tsbuild emitcheck "src/**/*.ts" "test/**/*.ts"\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const cwd = process.cwd();
|
||||
let allFiles: string[] = [];
|
||||
|
||||
// Process each pattern - could be a direct file path or a glob pattern
|
||||
for (const pattern of patterns) {
|
||||
// Check if the pattern looks like a glob pattern
|
||||
if (pattern.includes('*') || pattern.includes('{') || pattern.includes('?')) {
|
||||
// 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')
|
||||
: [];
|
||||
|
||||
if (stringMatchedFiles.length === 0) {
|
||||
console.warn(`⚠️ Warning: No files matched the pattern '${pattern}'`);
|
||||
} else {
|
||||
console.log(`📂 Found ${stringMatchedFiles.length} files matching pattern '${pattern}'`);
|
||||
|
||||
// Transform to absolute paths
|
||||
const absoluteMatchedFiles = plugins.smartpath.transform.toAbsolute(
|
||||
stringMatchedFiles,
|
||||
cwd
|
||||
) as string[];
|
||||
|
||||
// Add to the list of all files to check
|
||||
allFiles = allFiles.concat(absoluteMatchedFiles);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`❌ Error processing glob pattern '${pattern}': ${err}`);
|
||||
}
|
||||
} else {
|
||||
// Handle as direct file path
|
||||
const filePath = plugins.path.isAbsolute(pattern)
|
||||
? pattern
|
||||
: plugins.path.join(cwd, pattern);
|
||||
|
||||
try {
|
||||
await plugins.smartfile.fs.fileExists(filePath);
|
||||
allFiles.push(filePath);
|
||||
} catch (err) {
|
||||
console.error(`❌ Error: File not found: ${filePath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter to only TypeScript files
|
||||
allFiles = allFiles.filter(file => file.endsWith('.ts') || file.endsWith('.tsx'));
|
||||
|
||||
if (allFiles.length === 0) {
|
||||
console.error('\n❌ Error: No TypeScript files found to check');
|
||||
console.error(' Please verify your file paths or glob patterns.\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`\n🔎 Found ${allFiles.length} TypeScript file${allFiles.length !== 1 ? 's' : ''} to check`);
|
||||
|
||||
// Process compiler options
|
||||
const compilerOptions = tsbuild.mergeCompilerOptions({}, argvArg);
|
||||
|
||||
// Run emit check
|
||||
const success = await tsbuild.emitCheck(allFiles, compilerOptions, argvArg);
|
||||
|
||||
// Exit with appropriate code
|
||||
process.exit(success ? 0 : 1);
|
||||
});
|
||||
|
||||
/**
|
||||
* 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/);
|
||||
|
||||
// Now tsFolders contains all other folders except 'ts_shared' and 'ts_interfaces'
|
||||
|
||||
// We've established a base order. Now let's look at tspublish.json based ranking.
|
||||
const tsPublishInstance = new plugins.tspublish.TsPublish();
|
||||
const tsPublishModules = await tsPublishInstance.getModuleSubDirs(paths.cwd);
|
||||
// tsPublishModules is an object: { [folderName]: tspublishJsonData }
|
||||
|
||||
// Create an array with folder names and their ranks
|
||||
const foldersWithOrder = [];
|
||||
|
||||
for (const folder of tsFolders) {
|
||||
let rank = Infinity; // Default rank if not specified
|
||||
if (tsPublishModules[folder] && tsPublishModules[folder].order !== undefined) {
|
||||
rank = tsPublishModules[folder].order;
|
||||
}
|
||||
foldersWithOrder.push({ folder, rank });
|
||||
}
|
||||
|
||||
// Sort the folders based on rank
|
||||
foldersWithOrder.sort((a, b) => a.rank - b.rank);
|
||||
|
||||
// Construct the sorted list of folders
|
||||
const sortedTsFolders = [];
|
||||
|
||||
// Add the rest of the folders in sorted order
|
||||
for (const item of foldersWithOrder) {
|
||||
sortedTsFolders.push(item.folder);
|
||||
}
|
||||
|
||||
// Let's make sure 'ts_shared' is always transpiled first
|
||||
const ensurePosition = (folderNameArg: string, ensuredPosition: number) => {
|
||||
if (tsFolders.indexOf(folderNameArg) > -1 && Object.keys(tsPublishModules).indexOf(folderNameArg) === -1) {
|
||||
sortedTsFolders.splice(tsFolders.indexOf(folderNameArg), 1);
|
||||
sortedTsFolders.splice(ensuredPosition, 0, folderNameArg);
|
||||
}
|
||||
}
|
||||
|
||||
ensurePosition('ts_interfaces', 0);
|
||||
ensurePosition('ts_shared', 1);
|
||||
|
||||
|
||||
const compilationCommandObject: { [key: string]: string } = {};
|
||||
const folderCount = sortedTsFolders.length;
|
||||
console.log(`\n📂 TypeScript Folder Compilation Plan (${folderCount} folder${folderCount !== 1 ? 's' : ''})`);
|
||||
console.log('┌' + '─'.repeat(60) + '┐');
|
||||
console.log('│ 🔄 Compilation Order │');
|
||||
console.log('├' + '─'.repeat(60) + '┤');
|
||||
|
||||
sortedTsFolders.forEach((folder, index) => {
|
||||
const prefix = index === folderCount - 1 ? '└─' : '├─';
|
||||
const position = `${index + 1}/${folderCount}`;
|
||||
console.log(`│ ${prefix} ${position.padStart(5)} ${folder.padEnd(46)} │`);
|
||||
});
|
||||
|
||||
console.log('└' + '─'.repeat(60) + '┘\n');
|
||||
|
||||
for (const tsFolder of sortedTsFolders) {
|
||||
compilationCommandObject[`./${tsFolder}/**/*.ts`] = `./dist_${tsFolder}`;
|
||||
}
|
||||
await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
|
||||
const summary = (argvArg as any)?.__tsbuildFinalErrorSummary;
|
||||
if (summary && summary.totalErrors > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* the check command checks TypeScript files against a glob pattern without emitting them
|
||||
*/
|
||||
tsbuildCli.addCommand('check').subscribe(async (argvArg) => {
|
||||
const patterns = argvArg._.slice(1); // Remove the first element which is 'check'
|
||||
|
||||
// If no patterns provided, default to checking ts/**/* and then test/**/*
|
||||
if (patterns.length === 0) {
|
||||
console.log('\n🔬 Running default type checking sequence...\n');
|
||||
|
||||
// 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')
|
||||
: [];
|
||||
|
||||
if (tsTsFiles.length > 0) {
|
||||
console.log(` Found ${tsTsFiles.length} TypeScript files in ts/`);
|
||||
const tsAbsoluteFiles = plugins.smartpath.transform.toAbsolute(
|
||||
tsTsFiles,
|
||||
process.cwd()
|
||||
) as string[];
|
||||
|
||||
const tsCompilerOptions = tsbuild.mergeCompilerOptions({}, argvArg);
|
||||
const tsSuccess = await tsbuild.checkTypes(tsAbsoluteFiles, tsCompilerOptions, argvArg);
|
||||
|
||||
if (!tsSuccess) {
|
||||
console.error('❌ Type checking failed for ts/**/*');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('✅ Type checking passed for ts/**/*\n');
|
||||
} else {
|
||||
console.log(' No TypeScript files found in ts/\n');
|
||||
}
|
||||
|
||||
// Then check test/**/* with skiplibcheck
|
||||
console.log('📂 Checking test/**/* files with --skiplibcheck...');
|
||||
const testFiles = await plugins.smartfile.fs.listFileTree(process.cwd(), 'test/**/*.ts');
|
||||
const testTsFiles = Array.isArray(testFiles)
|
||||
? testFiles.filter((item): item is string => typeof item === 'string')
|
||||
: [];
|
||||
|
||||
if (testTsFiles.length > 0) {
|
||||
console.log(` Found ${testTsFiles.length} TypeScript files in test/`);
|
||||
const testAbsoluteFiles = plugins.smartpath.transform.toAbsolute(
|
||||
testTsFiles,
|
||||
process.cwd()
|
||||
) as string[];
|
||||
|
||||
// Create new argvArg with skiplibcheck for test files
|
||||
const testArgvArg = { ...argvArg, skiplibcheck: true };
|
||||
const testCompilerOptions = tsbuild.mergeCompilerOptions({}, testArgvArg);
|
||||
const testSuccess = await tsbuild.checkTypes(testAbsoluteFiles, testCompilerOptions, testArgvArg);
|
||||
|
||||
if (!testSuccess) {
|
||||
console.error('❌ Type checking failed for test/**/*');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('✅ Type checking passed for test/**/*\n');
|
||||
} else {
|
||||
console.log(' No TypeScript files found in test/\n');
|
||||
}
|
||||
|
||||
console.log('✅ All default type checks passed!\n');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const cwd = process.cwd();
|
||||
let allFiles: string[] = [];
|
||||
|
||||
// Process each pattern - could be a direct file path or a glob pattern
|
||||
for (const pattern of patterns) {
|
||||
// Check if the pattern looks like a glob pattern
|
||||
if (pattern.includes('*') || pattern.includes('{') || pattern.includes('?')) {
|
||||
// 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')
|
||||
: [];
|
||||
|
||||
if (stringMatchedFiles.length === 0) {
|
||||
console.warn(`⚠️ Warning: No files matched the pattern '${pattern}'`);
|
||||
} else {
|
||||
console.log(`📂 Found ${stringMatchedFiles.length} files matching pattern '${pattern}'`);
|
||||
|
||||
// Transform to absolute paths
|
||||
const absoluteMatchedFiles = plugins.smartpath.transform.toAbsolute(
|
||||
stringMatchedFiles,
|
||||
cwd
|
||||
) as string[];
|
||||
|
||||
// Add to the list of all files to check
|
||||
allFiles = allFiles.concat(absoluteMatchedFiles);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`❌ Error processing glob pattern '${pattern}': ${err}`);
|
||||
}
|
||||
} else {
|
||||
// Handle as direct file path
|
||||
const filePath = plugins.path.isAbsolute(pattern)
|
||||
? pattern
|
||||
: plugins.path.join(cwd, pattern);
|
||||
|
||||
try {
|
||||
await plugins.smartfile.fs.fileExists(filePath);
|
||||
allFiles.push(filePath);
|
||||
} catch (err) {
|
||||
console.error(`❌ Error: File not found: ${filePath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter to only TypeScript files
|
||||
allFiles = allFiles.filter(file => file.endsWith('.ts') || file.endsWith('.tsx'));
|
||||
|
||||
if (allFiles.length === 0) {
|
||||
console.error('\n❌ Error: No TypeScript files found to check');
|
||||
console.error(' Please verify your file paths or glob patterns.\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`\n🔎 Found ${allFiles.length} TypeScript file${allFiles.length !== 1 ? 's' : ''} to check`);
|
||||
|
||||
// Process compiler options
|
||||
const compilerOptions = tsbuild.mergeCompilerOptions({}, argvArg);
|
||||
|
||||
// Run type check without emitting
|
||||
const success = await tsbuild.checkTypes(allFiles, compilerOptions, argvArg);
|
||||
|
||||
// Exit with appropriate code
|
||||
process.exit(success ? 0 : 1);
|
||||
});
|
||||
|
||||
tsbuildCli.startParse();
|
||||
|
||||
@@ -1,7 +1,35 @@
|
||||
import * as plugins from './tsbuild.plugins';
|
||||
import { compiler, CompilerOptions, mergeCompilerOptions } from './tsbuild.classes.compiler';
|
||||
import * as plugins from './plugins.js';
|
||||
import type { CompilerOptions, ScriptTarget, ModuleKind } from 'typescript';
|
||||
import { compiler, mergeCompilerOptions, emitCheck, checkTypes } from './tsbuild.classes.tsbuild.js';
|
||||
|
||||
export * from './tsbuild.classes.compiler';
|
||||
export type { CompilerOptions, ScriptTarget, ModuleKind };
|
||||
|
||||
export * from './tsbuild.classes.tsbuild.js';
|
||||
|
||||
/**
|
||||
* Interface for task information
|
||||
*/
|
||||
export interface ITaskInfo {
|
||||
taskNumber: number;
|
||||
totalTasks: number;
|
||||
sourcePattern: string;
|
||||
destDir: string;
|
||||
fileCount: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* compile an array of absolute file paths with error tracking
|
||||
*/
|
||||
export let compileFileArrayWithErrorTracking = async (
|
||||
fileStringArrayArg: string[],
|
||||
compilerOptionsArg: CompilerOptions = {},
|
||||
argvArg?: any,
|
||||
taskInfo?: ITaskInfo
|
||||
): Promise<{ emittedFiles: any[], errorSummary: import('./tsbuild.classes.tsbuild.js').IErrorSummary }> => {
|
||||
const { TsBuild } = await import('./tsbuild.classes.tsbuild.js');
|
||||
const tsBuild = new TsBuild(fileStringArrayArg, compilerOptionsArg, argvArg, taskInfo);
|
||||
return tsBuild.compileWithErrorTracking();
|
||||
};
|
||||
|
||||
/**
|
||||
* compile am array of absolute file paths
|
||||
@@ -14,6 +42,75 @@ export let compileFileArray = (
|
||||
return compiler(fileStringArrayArg, mergeCompilerOptions(compilerOptionsArg, argvArg), argvArg);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to merge error summaries
|
||||
*/
|
||||
function mergeErrorSummaries(summaries: import('./tsbuild.classes.tsbuild.js').IErrorSummary[]): import('./tsbuild.classes.tsbuild.js').IErrorSummary {
|
||||
const mergedErrorsByFile: Record<string, plugins.typescript.Diagnostic[]> = {};
|
||||
const mergedGeneralErrors: plugins.typescript.Diagnostic[] = [];
|
||||
let totalErrors = 0;
|
||||
|
||||
summaries.forEach(summary => {
|
||||
// Merge errors by file
|
||||
Object.entries(summary.errorsByFile).forEach(([fileName, errors]) => {
|
||||
if (!mergedErrorsByFile[fileName]) {
|
||||
mergedErrorsByFile[fileName] = [];
|
||||
}
|
||||
mergedErrorsByFile[fileName] = mergedErrorsByFile[fileName].concat(errors);
|
||||
});
|
||||
|
||||
// Merge general errors
|
||||
mergedGeneralErrors.push(...summary.generalErrors);
|
||||
totalErrors += summary.totalErrors;
|
||||
});
|
||||
|
||||
return {
|
||||
errorsByFile: mergedErrorsByFile,
|
||||
generalErrors: mergedGeneralErrors,
|
||||
totalErrors,
|
||||
totalFiles: Object.keys(mergedErrorsByFile).length
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to display final compilation summary
|
||||
*/
|
||||
function displayFinalErrorSummary(errorSummary: import('./tsbuild.classes.tsbuild.js').IErrorSummary): void {
|
||||
if (errorSummary.totalErrors === 0) {
|
||||
console.log('\n📊 \x1b[32mCompilation Summary: All tasks completed successfully! ✅\x1b[0m\n');
|
||||
return;
|
||||
}
|
||||
|
||||
const colors = {
|
||||
reset: '\x1b[0m',
|
||||
red: '\x1b[31m',
|
||||
yellow: '\x1b[33m',
|
||||
cyan: '\x1b[36m',
|
||||
brightRed: '\x1b[91m',
|
||||
brightYellow: '\x1b[93m'
|
||||
};
|
||||
|
||||
console.log('\n' + '='.repeat(80));
|
||||
console.log(`📊 ${colors.brightYellow}Final Compilation Summary${colors.reset}`);
|
||||
console.log('='.repeat(80));
|
||||
|
||||
if (errorSummary.totalFiles > 0) {
|
||||
console.log(`${colors.brightRed}❌ Files with errors (${errorSummary.totalFiles}):${colors.reset}`);
|
||||
|
||||
Object.entries(errorSummary.errorsByFile).forEach(([fileName, errors]) => {
|
||||
const displayPath = fileName.replace(process.cwd(), '').replace(/^\//, '');
|
||||
console.log(` ${colors.red}•${colors.reset} ${colors.cyan}${displayPath}${colors.reset} ${colors.yellow}(${errors.length} error${errors.length !== 1 ? 's' : ''})${colors.reset}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (errorSummary.generalErrors.length > 0) {
|
||||
console.log(`${colors.brightRed}❌ General errors: ${errorSummary.generalErrors.length}${colors.reset}`);
|
||||
}
|
||||
|
||||
console.log(`\n${colors.brightRed}Total: ${errorSummary.totalErrors} error${errorSummary.totalErrors !== 1 ? 's' : ''} across ${errorSummary.totalFiles} file${errorSummary.totalFiles !== 1 ? 's' : ''}${colors.reset}`);
|
||||
console.log('='.repeat(80) + '\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* compile advanced glob configurations
|
||||
* @param globStringArrayArg a array of glob strings
|
||||
@@ -22,35 +119,105 @@ export let compileFileArray = (
|
||||
* }
|
||||
*/
|
||||
export let compileGlobStringObject = async (
|
||||
globStringObjectArg: any,
|
||||
globStringObjectArg: Record<string, string>,
|
||||
tsOptionsArg: CompilerOptions = {},
|
||||
cwdArg: string = process.cwd(),
|
||||
argvArg?: any
|
||||
) => {
|
||||
let compiledFiles: plugins.smartfile.Smartfile[] = [];
|
||||
let compiledFiles: any[] = [];
|
||||
const errorSummaries: import('./tsbuild.classes.tsbuild.js').IErrorSummary[] = [];
|
||||
|
||||
const totalTasks = Object.keys(globStringObjectArg).length;
|
||||
let currentTask = 0;
|
||||
|
||||
// Log the compilation tasks in a nice format (skip for --quiet or --json)
|
||||
const isQuiet = argvArg?.quiet === true;
|
||||
const isJson = argvArg?.json === true;
|
||||
if (!isQuiet && !isJson) {
|
||||
console.log(`\n👷 TypeScript Compilation Tasks (${totalTasks} task${totalTasks !== 1 ? 's' : ''}):`);
|
||||
Object.entries(globStringObjectArg).forEach(([source, dest]) => {
|
||||
console.log(` 📂 ${source} → ${dest}`);
|
||||
});
|
||||
console.log('');
|
||||
}
|
||||
|
||||
for (const keyArg in globStringObjectArg) {
|
||||
if (globStringObjectArg[keyArg]) {
|
||||
console.log(
|
||||
`TypeScript assignment: transpile from ${keyArg} to ${globStringObjectArg[keyArg]}`
|
||||
);
|
||||
// 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);
|
||||
const absoluteFilePathArray: string[] = plugins.smartpath.transform.toAbsolute(
|
||||
fileTreeArray,
|
||||
|
||||
// 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
|
||||
const absoluteFilePathArray = plugins.smartpath.transform.toAbsolute(
|
||||
stringFileTreeArray,
|
||||
cwdArg
|
||||
);
|
||||
) as string[];
|
||||
|
||||
// Get destination directory as absolute path
|
||||
const destDir: string = plugins.smartpath.transform.toAbsolute(
|
||||
globStringObjectArg[keyArg],
|
||||
cwdArg
|
||||
);
|
||||
tsOptionsArg = {
|
||||
) as string;
|
||||
|
||||
// Update compiler options with the output directory
|
||||
const updatedTsOptions: CompilerOptions = {
|
||||
...tsOptionsArg,
|
||||
outDir: destDir
|
||||
outDir: destDir,
|
||||
};
|
||||
compiledFiles = compiledFiles.concat(
|
||||
compiledFiles,
|
||||
await compileFileArray(absoluteFilePathArray, tsOptionsArg, argvArg)
|
||||
);
|
||||
|
||||
// Compile with error tracking
|
||||
currentTask++;
|
||||
const taskInfo = {
|
||||
taskNumber: currentTask,
|
||||
totalTasks,
|
||||
sourcePattern: keyArg,
|
||||
destDir: globStringObjectArg[keyArg],
|
||||
fileCount: absoluteFilePathArray.length
|
||||
};
|
||||
|
||||
const result = await compileFileArrayWithErrorTracking(absoluteFilePathArray, updatedTsOptions, argvArg, taskInfo);
|
||||
compiledFiles = compiledFiles.concat(result.emittedFiles);
|
||||
errorSummaries.push(result.errorSummary);
|
||||
}
|
||||
}
|
||||
|
||||
// Display final error summary after all compilation tasks
|
||||
const finalErrorSummary = mergeErrorSummaries(errorSummaries);
|
||||
|
||||
// Output summary based on mode
|
||||
if (isJson) {
|
||||
const result = {
|
||||
success: finalErrorSummary.totalErrors === 0,
|
||||
totals: {
|
||||
errors: finalErrorSummary.totalErrors,
|
||||
filesWithErrors: finalErrorSummary.totalFiles,
|
||||
tasks: totalTasks,
|
||||
},
|
||||
errorsByFile: Object.fromEntries(
|
||||
Object.entries(finalErrorSummary.errorsByFile).map(([file, diags]) => [
|
||||
file,
|
||||
diags.map(d => ({
|
||||
code: d.code,
|
||||
message: plugins.typescript.flattenDiagnosticMessageText(d.messageText as any, '\n'),
|
||||
}))
|
||||
])
|
||||
),
|
||||
};
|
||||
console.log(JSON.stringify(result));
|
||||
} else if (!isQuiet) {
|
||||
displayFinalErrorSummary(finalErrorSummary);
|
||||
}
|
||||
|
||||
// Attach summary to argvArg so CLI can decide exit behavior
|
||||
if (argvArg && typeof argvArg === 'object') {
|
||||
(argvArg as any).__tsbuildFinalErrorSummary = finalErrorSummary;
|
||||
}
|
||||
|
||||
return compiledFiles;
|
||||
};
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import * as smartcli from '@pushrocks/smartcli';
|
||||
import * as smartfile from '@pushrocks/smartfile';
|
||||
import * as smartpath from '@pushrocks/smartpath';
|
||||
import * as smartpromise from '@pushrocks/smartpromise';
|
||||
import * as typescript from 'typescript';
|
||||
|
||||
export { smartcli, smartfile, smartpath, smartpromise, typescript };
|
||||
11
tsconfig.json
Normal file
11
tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"useDefineForClassFields": false,
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true
|
||||
}
|
||||
}
|
||||
17
tslint.json
17
tslint.json
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": ["tslint:latest", "tslint-config-prettier"],
|
||||
"rules": {
|
||||
"semicolon": [true, "always"],
|
||||
"no-console": false,
|
||||
"ordered-imports": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"member-ordering": {
|
||||
"options":{
|
||||
"order": [
|
||||
"static-method"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultSeverity": "warning"
|
||||
}
|
||||
Reference in New Issue
Block a user