Compare commits
No commits in common. "master" and "v2.3.2" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
@ -18,4 +18,3 @@ dist/
|
|||||||
dist_*/
|
dist_*/
|
||||||
|
|
||||||
# custom
|
# custom
|
||||||
.claude
|
|
30
changelog.md
30
changelog.md
@ -1,35 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 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)
|
## 2025-03-20 - 2.3.2 - fix(compileGlobStringObject)
|
||||||
Fix duplicate file outputs in glob pattern processing
|
Fix duplicate file outputs in glob pattern processing
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@git.zone/tsbuild",
|
"name": "@git.zone/tsbuild",
|
||||||
"version": "2.5.1",
|
"version": "2.3.2",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.",
|
"description": "A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
@ -11,7 +11,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "tsrun test/test.ts",
|
"test": "tsrun test/test.ts",
|
||||||
"build": "node cli.ts.js --web",
|
"build": "node cli.ts.js --web --allowimplicitany",
|
||||||
"buildDocs": "tsdoc"
|
"buildDocs": "tsdoc"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -65,6 +65,5 @@
|
|||||||
],
|
],
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"last 1 chrome versions"
|
"last 1 chrome versions"
|
||||||
],
|
]
|
||||||
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
|
|
||||||
}
|
}
|
||||||
|
31
readme.md
31
readme.md
@ -146,42 +146,17 @@ Example usage with glob patterns:
|
|||||||
npx tsbuild emitcheck "src/**/*.ts" "test/**/*.ts"
|
npx tsbuild emitcheck "src/**/*.ts" "test/**/*.ts"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Check Command
|
|
||||||
|
|
||||||
Performs type checking on TypeScript files specified by glob patterns without emitting them:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npx tsbuild check <glob_pattern> [additional_patterns ...]
|
|
||||||
```
|
|
||||||
|
|
||||||
This command:
|
|
||||||
1. Efficiently type checks TypeScript files matching the given glob patterns
|
|
||||||
2. Supports multiple glob patterns and direct file paths
|
|
||||||
3. Reports any type errors found in the matched files
|
|
||||||
4. Exits with code 0 if all files pass type checking, or 1 if any have errors
|
|
||||||
5. Doesn't produce any output files
|
|
||||||
|
|
||||||
Example usage:
|
|
||||||
```bash
|
|
||||||
npx tsbuild check ts/**/*
|
|
||||||
```
|
|
||||||
|
|
||||||
Example usage with multiple patterns:
|
|
||||||
```bash
|
|
||||||
npx tsbuild check "src/**/*.ts" "test/**/*.ts"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Compiler Options
|
## Compiler Options
|
||||||
|
|
||||||
Additional flags can be passed to any command to modify the compilation behavior:
|
Additional flags can be passed to any command to modify the compilation behavior:
|
||||||
|
|
||||||
- `--skiplibcheck`: Skip type checking of declaration files (shows warning)
|
- `--skiplibcheck`: Skip type checking of declaration files (shows warning)
|
||||||
- `--disallowimplicitany`: Disallow variables to be implicitly typed as `any` (implicit any is allowed by default)
|
- `--allowimplicitany`: Allow variables to be implicitly typed as `any`
|
||||||
- `--commonjs`: Use CommonJS module format instead of ESNext
|
- `--commonjs`: Use CommonJS module format instead of ESNext
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```bash
|
```bash
|
||||||
npx tsbuild --skiplibcheck --disallowimplicitany
|
npx tsbuild --skiplibcheck --allowimplicitany
|
||||||
```
|
```
|
||||||
|
|
||||||
## Default Compiler Options
|
## Default Compiler Options
|
||||||
@ -200,7 +175,7 @@ By default, `@git.zone/tsbuild` uses the following compiler options:
|
|||||||
target: ScriptTarget.ESNext,
|
target: ScriptTarget.ESNext,
|
||||||
moduleResolution: ModuleResolutionKind.NodeNext,
|
moduleResolution: ModuleResolutionKind.NodeNext,
|
||||||
lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'],
|
lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'],
|
||||||
noImplicitAny: false, // Now allowing implicit any by default
|
noImplicitAny: true,
|
||||||
esModuleInterop: true,
|
esModuleInterop: true,
|
||||||
useDefineForClassFields: false,
|
useDefineForClassFields: false,
|
||||||
verbatimModuleSyntax: true,
|
verbatimModuleSyntax: true,
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
# 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
|
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@git.zone/tsbuild',
|
name: '@git.zone/tsbuild',
|
||||||
version: '2.5.1',
|
version: '2.3.2',
|
||||||
description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.'
|
description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.'
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ export const compilerOptionsDefault: CompilerOptions = {
|
|||||||
target: plugins.typescript.ScriptTarget.ESNext,
|
target: plugins.typescript.ScriptTarget.ESNext,
|
||||||
moduleResolution: plugins.typescript.ModuleResolutionKind.NodeNext,
|
moduleResolution: plugins.typescript.ModuleResolutionKind.NodeNext,
|
||||||
lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'],
|
lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'],
|
||||||
noImplicitAny: false, // Allow implicit any by default
|
noImplicitAny: true,
|
||||||
esModuleInterop: true,
|
esModuleInterop: true,
|
||||||
useDefineForClassFields: false,
|
useDefineForClassFields: false,
|
||||||
verbatimModuleSyntax: true,
|
verbatimModuleSyntax: true,
|
||||||
@ -49,6 +49,7 @@ export class TsBuild {
|
|||||||
* Helper function to read and process tsconfig.json
|
* Helper function to read and process tsconfig.json
|
||||||
*/
|
*/
|
||||||
private getTsConfigOptions(): CompilerOptions {
|
private getTsConfigOptions(): CompilerOptions {
|
||||||
|
console.log(`looking at tsconfig.json at ${paths.cwd}`);
|
||||||
const tsconfig = plugins.smartfile.fs.toObjectSync(plugins.path.join(paths.cwd, 'tsconfig.json'));
|
const tsconfig = plugins.smartfile.fs.toObjectSync(plugins.path.join(paths.cwd, 'tsconfig.json'));
|
||||||
const returnObject: CompilerOptions = {};
|
const returnObject: CompilerOptions = {};
|
||||||
|
|
||||||
@ -56,68 +57,18 @@ export class TsBuild {
|
|||||||
return returnObject;
|
return returnObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process baseUrl
|
|
||||||
if (tsconfig.compilerOptions.baseUrl) {
|
if (tsconfig.compilerOptions.baseUrl) {
|
||||||
|
console.log('baseUrl found in tsconfig.json');
|
||||||
returnObject.baseUrl = tsconfig.compilerOptions.baseUrl;
|
returnObject.baseUrl = tsconfig.compilerOptions.baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process paths
|
|
||||||
if (tsconfig.compilerOptions.paths) {
|
if (tsconfig.compilerOptions.paths) {
|
||||||
returnObject.paths = { ...tsconfig.compilerOptions.paths };
|
console.log('paths found in tsconfig.json');
|
||||||
for (const path of Object.keys(returnObject.paths)) {
|
returnObject.paths = tsconfig.compilerOptions.paths;
|
||||||
if (Array.isArray(returnObject.paths[path]) && returnObject.paths[path].length > 0) {
|
for (const path of Object.keys(tsconfig.compilerOptions.paths)) {
|
||||||
returnObject.paths[path][0] = returnObject.paths[path][0].replace('./ts_', './dist_ts_');
|
returnObject.paths[path][0] = returnObject.paths[path][0].replace('./ts_', './dist_ts_');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Process target
|
|
||||||
if (tsconfig.compilerOptions.target) {
|
|
||||||
if (typeof tsconfig.compilerOptions.target === 'string') {
|
|
||||||
const targetKey = tsconfig.compilerOptions.target.toUpperCase();
|
|
||||||
if (targetKey in plugins.typescript.ScriptTarget) {
|
|
||||||
returnObject.target = plugins.typescript.ScriptTarget[targetKey as keyof typeof plugins.typescript.ScriptTarget];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process module
|
|
||||||
if (tsconfig.compilerOptions.module) {
|
|
||||||
if (typeof tsconfig.compilerOptions.module === 'string') {
|
|
||||||
const moduleKey = tsconfig.compilerOptions.module.toUpperCase();
|
|
||||||
if (moduleKey in plugins.typescript.ModuleKind) {
|
|
||||||
returnObject.module = plugins.typescript.ModuleKind[moduleKey as keyof typeof plugins.typescript.ModuleKind];
|
|
||||||
} else if (moduleKey === 'NODENEXT') {
|
|
||||||
returnObject.module = plugins.typescript.ModuleKind.NodeNext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process moduleResolution
|
|
||||||
if (tsconfig.compilerOptions.moduleResolution) {
|
|
||||||
if (typeof tsconfig.compilerOptions.moduleResolution === 'string') {
|
|
||||||
const moduleResolutionKey = tsconfig.compilerOptions.moduleResolution.toUpperCase();
|
|
||||||
if (moduleResolutionKey in plugins.typescript.ModuleResolutionKind) {
|
|
||||||
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind[
|
|
||||||
moduleResolutionKey as keyof typeof plugins.typescript.ModuleResolutionKind
|
|
||||||
];
|
|
||||||
} else if (moduleResolutionKey === 'NODENEXT') {
|
|
||||||
returnObject.moduleResolution = plugins.typescript.ModuleResolutionKind.NodeNext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy boolean options directly
|
|
||||||
const booleanOptions = [
|
|
||||||
'experimentalDecorators', 'useDefineForClassFields',
|
|
||||||
'esModuleInterop', 'verbatimModuleSyntax'
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const option of booleanOptions) {
|
|
||||||
if (option in tsconfig.compilerOptions) {
|
|
||||||
(returnObject as any)[option] = (tsconfig.compilerOptions as any)[option];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnObject;
|
return returnObject;
|
||||||
}
|
}
|
||||||
@ -134,9 +85,8 @@ export class TsBuild {
|
|||||||
options.skipLibCheck = true;
|
options.skipLibCheck = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changed behavior: --disallowimplicitany instead of --allowimplicitany
|
if (argvArg.allowimplicitany) {
|
||||||
if (argvArg.disallowimplicitany) {
|
options.noImplicitAny = false;
|
||||||
options.noImplicitAny = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argvArg.commonjs) {
|
if (argvArg.commonjs) {
|
||||||
@ -162,6 +112,7 @@ export class TsBuild {
|
|||||||
...this.getTsConfigOptions(),
|
...this.getTsConfigOptions(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(mergedOptions);
|
||||||
return mergedOptions;
|
return mergedOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,94 +120,22 @@ export class TsBuild {
|
|||||||
* Helper function to handle and log TypeScript diagnostics
|
* Helper function to handle and log TypeScript diagnostics
|
||||||
*/
|
*/
|
||||||
private handleDiagnostics(diagnostics: readonly plugins.typescript.Diagnostic[]): boolean {
|
private handleDiagnostics(diagnostics: readonly plugins.typescript.Diagnostic[]): boolean {
|
||||||
if (diagnostics.length === 0) {
|
let hasErrors = false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Group errors by file for better readability
|
|
||||||
const errorsByFile: Record<string, plugins.typescript.Diagnostic[]> = {};
|
|
||||||
const generalErrors: plugins.typescript.Diagnostic[] = [];
|
|
||||||
|
|
||||||
// Categorize diagnostics
|
|
||||||
diagnostics.forEach((diagnostic) => {
|
diagnostics.forEach((diagnostic) => {
|
||||||
|
hasErrors = true;
|
||||||
if (diagnostic.file) {
|
if (diagnostic.file) {
|
||||||
const fileName = diagnostic.file.fileName;
|
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
|
||||||
if (!errorsByFile[fileName]) {
|
const message = plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
||||||
errorsByFile[fileName] = [];
|
console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
|
||||||
}
|
|
||||||
errorsByFile[fileName].push(diagnostic);
|
|
||||||
} else {
|
} else {
|
||||||
generalErrors.push(diagnostic);
|
console.log(
|
||||||
|
`${plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Print error summary header
|
return hasErrors;
|
||||||
const totalErrorCount = diagnostics.length;
|
|
||||||
const fileCount = Object.keys(errorsByFile).length;
|
|
||||||
|
|
||||||
console.log('\n' + '='.repeat(80));
|
|
||||||
console.log(`❌ Found ${totalErrorCount} error${totalErrorCount !== 1 ? 's' : ''} in ${fileCount} file${fileCount !== 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');
|
|
||||||
|
|
||||||
return diagnostics.length > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -287,13 +166,14 @@ export class TsBuild {
|
|||||||
*/
|
*/
|
||||||
public async compile(): Promise<any[]> {
|
public async compile(): Promise<any[]> {
|
||||||
if (this.options.skipLibCheck) {
|
if (this.options.skipLibCheck) {
|
||||||
console.log('\n⚠️ WARNING ⚠️');
|
console.log('? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?');
|
||||||
console.log('You are skipping libcheck... Is that really wanted?');
|
console.log('You are skipping libcheck... Is that really wanted?');
|
||||||
console.log('Continuing in 5 seconds...\n');
|
console.log('continuing in 5 seconds...');
|
||||||
|
console.log('? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?');
|
||||||
await plugins.smartdelay.delayFor(5000);
|
await plugins.smartdelay.delayFor(5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`🔨 Compiling ${this.fileNames.length} files...`);
|
console.log(`Compiling ${this.fileNames.length} files...`);
|
||||||
const done = plugins.smartpromise.defer<any[]>();
|
const done = plugins.smartpromise.defer<any[]>();
|
||||||
const program = this.createProgram();
|
const program = this.createProgram();
|
||||||
|
|
||||||
@ -303,8 +183,7 @@ export class TsBuild {
|
|||||||
|
|
||||||
// Only continue to emit phase if no pre-emit errors
|
// Only continue to emit phase if no pre-emit errors
|
||||||
if (hasPreEmitErrors) {
|
if (hasPreEmitErrors) {
|
||||||
console.error('\n❌ TypeScript pre-emit checks failed. Please fix the issues listed above before proceeding.');
|
console.error('TypeScript pre-emit checks failed. Please fix the issues above.');
|
||||||
console.error(' Type errors must be resolved before the compiler can emit output files.\n');
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,22 +193,10 @@ export class TsBuild {
|
|||||||
|
|
||||||
const exitCode = emitResult.emitSkipped ? 1 : 0;
|
const exitCode = emitResult.emitSkipped ? 1 : 0;
|
||||||
if (exitCode === 0) {
|
if (exitCode === 0) {
|
||||||
console.log('\n✅ TypeScript emit succeeded!');
|
console.log('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);
|
done.resolve(emitResult.emittedFiles);
|
||||||
} else {
|
} else {
|
||||||
console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!');
|
console.error('TypeScript emit failed. Please investigate!');
|
||||||
console.error(' No output files have been generated.\n');
|
|
||||||
process.exit(exitCode);
|
process.exit(exitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,8 +207,7 @@ export class TsBuild {
|
|||||||
* Function to check if files can be emitted without actually emitting them
|
* Function to check if files can be emitted without actually emitting them
|
||||||
*/
|
*/
|
||||||
public async checkEmit(): Promise<boolean> {
|
public async checkEmit(): Promise<boolean> {
|
||||||
const fileCount = this.fileNames.length;
|
console.log(`Checking if ${this.fileNames.length} files can be emitted...`);
|
||||||
console.log(`\n🔍 Checking if ${fileCount} file${fileCount !== 1 ? 's' : ''} can be emitted...`);
|
|
||||||
|
|
||||||
// Create a program with noEmit option
|
// Create a program with noEmit option
|
||||||
const program = this.createProgram({
|
const program = this.createProgram({
|
||||||
@ -360,42 +226,9 @@ export class TsBuild {
|
|||||||
const success = !hasPreEmitErrors && !hasEmitErrors && !emitResult.emitSkipped;
|
const success = !hasPreEmitErrors && !hasEmitErrors && !emitResult.emitSkipped;
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
console.log('\n✅ TypeScript emit check passed! All files can be emitted successfully.');
|
console.log('TypeScript emit check passed! File can be emitted successfully.');
|
||||||
console.log(` ${fileCount} file${fileCount !== 1 ? 's' : ''} ${fileCount !== 1 ? 'are' : 'is'} ready to be compiled.\n`);
|
|
||||||
} else {
|
} else {
|
||||||
console.error('\n❌ TypeScript emit check failed. Please fix the issues listed above.');
|
console.error('TypeScript emit check failed. Please fix the issues 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 hasErrors = this.handleDiagnostics(diagnostics);
|
|
||||||
|
|
||||||
// Set success flag
|
|
||||||
const success = !hasErrors;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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;
|
return success;
|
||||||
@ -436,15 +269,3 @@ export const emitCheck = async (
|
|||||||
const tsBuild = new TsBuild(fileNames, options, argvArg);
|
const tsBuild = new TsBuild(fileNames, options, argvArg);
|
||||||
return tsBuild.checkEmit();
|
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();
|
|
||||||
};
|
|
@ -39,9 +39,7 @@ export const runCli = async () => {
|
|||||||
const patterns = argvArg._.slice(1); // Remove the first element which is 'emitcheck'
|
const patterns = argvArg._.slice(1); // Remove the first element which is 'emitcheck'
|
||||||
|
|
||||||
if (patterns.length === 0) {
|
if (patterns.length === 0) {
|
||||||
console.error('\n❌ Error: Please provide at least one TypeScript file path or glob pattern');
|
console.error('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);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,9 +61,9 @@ export const runCli = async () => {
|
|||||||
: [];
|
: [];
|
||||||
|
|
||||||
if (stringMatchedFiles.length === 0) {
|
if (stringMatchedFiles.length === 0) {
|
||||||
console.warn(`⚠️ Warning: No files matched the pattern '${pattern}'`);
|
console.warn(`Warning: No files matched the pattern '${pattern}'`);
|
||||||
} else {
|
} else {
|
||||||
console.log(`📂 Found ${stringMatchedFiles.length} files matching pattern '${pattern}'`);
|
console.log(`Found ${stringMatchedFiles.length} files matching pattern '${pattern}'`);
|
||||||
|
|
||||||
// Transform to absolute paths
|
// Transform to absolute paths
|
||||||
const absoluteMatchedFiles = plugins.smartpath.transform.toAbsolute(
|
const absoluteMatchedFiles = plugins.smartpath.transform.toAbsolute(
|
||||||
@ -77,7 +75,7 @@ export const runCli = async () => {
|
|||||||
allFiles = allFiles.concat(absoluteMatchedFiles);
|
allFiles = allFiles.concat(absoluteMatchedFiles);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`❌ Error processing glob pattern '${pattern}': ${err}`);
|
console.error(`Error processing glob pattern '${pattern}': ${err}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Handle as direct file path
|
// Handle as direct file path
|
||||||
@ -89,7 +87,7 @@ export const runCli = async () => {
|
|||||||
await plugins.smartfile.fs.fileExists(filePath);
|
await plugins.smartfile.fs.fileExists(filePath);
|
||||||
allFiles.push(filePath);
|
allFiles.push(filePath);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`❌ Error: File not found: ${filePath}`);
|
console.error(`Error: File not found: ${filePath}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,12 +97,11 @@ export const runCli = async () => {
|
|||||||
allFiles = allFiles.filter(file => file.endsWith('.ts') || file.endsWith('.tsx'));
|
allFiles = allFiles.filter(file => file.endsWith('.ts') || file.endsWith('.tsx'));
|
||||||
|
|
||||||
if (allFiles.length === 0) {
|
if (allFiles.length === 0) {
|
||||||
console.error('\n❌ Error: No TypeScript files found to check');
|
console.error('Error: No TypeScript files found to check');
|
||||||
console.error(' Please verify your file paths or glob patterns.\n');
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`\n🔎 Found ${allFiles.length} TypeScript file${allFiles.length !== 1 ? 's' : ''} to check`);
|
console.log(`Found ${allFiles.length} TypeScript files to check`);
|
||||||
|
|
||||||
// Process compiler options
|
// Process compiler options
|
||||||
const compilerOptions = tsbuild.mergeCompilerOptions({}, argvArg);
|
const compilerOptions = tsbuild.mergeCompilerOptions({}, argvArg);
|
||||||
@ -164,164 +161,13 @@ export const runCli = async () => {
|
|||||||
|
|
||||||
|
|
||||||
const compilationCommandObject: { [key: string]: string } = {};
|
const compilationCommandObject: { [key: string]: string } = {};
|
||||||
const folderCount = sortedTsFolders.length;
|
console.log(`compiling in this order:`);
|
||||||
console.log(`\n📂 TypeScript Folder Compilation Plan (${folderCount} folder${folderCount !== 1 ? 's' : ''})`);
|
console.log(sortedTsFolders);
|
||||||
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) {
|
for (const tsFolder of sortedTsFolders) {
|
||||||
compilationCommandObject[`./${tsFolder}/**/*.ts`] = `./dist_${tsFolder}`;
|
compilationCommandObject[`./${tsFolder}/**/*.ts`] = `./dist_${tsFolder}`;
|
||||||
}
|
}
|
||||||
await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
|
await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
tsbuildCli.startParse();
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as plugins from './plugins.js';
|
import * as plugins from './plugins.js';
|
||||||
import type { CompilerOptions, ScriptTarget, ModuleKind } from 'typescript';
|
import type { CompilerOptions, ScriptTarget, ModuleKind } from 'typescript';
|
||||||
import { compiler, mergeCompilerOptions, emitCheck, checkTypes } from './tsbuild.classes.tsbuild.js';
|
import { compiler, mergeCompilerOptions, emitCheck } from './tsbuild.classes.tsbuild.js';
|
||||||
|
|
||||||
export type { CompilerOptions, ScriptTarget, ModuleKind };
|
export type { CompilerOptions, ScriptTarget, ModuleKind };
|
||||||
|
|
||||||
@ -32,16 +32,12 @@ export let compileGlobStringObject = async (
|
|||||||
) => {
|
) => {
|
||||||
let compiledFiles: any[] = [];
|
let compiledFiles: any[] = [];
|
||||||
|
|
||||||
// Log the compilation tasks in a nice format
|
|
||||||
console.log('\n👷 TypeScript Compilation Tasks:');
|
|
||||||
Object.entries(globStringObjectArg).forEach(([source, dest]) => {
|
|
||||||
console.log(` 📂 ${source} → ${dest}`);
|
|
||||||
});
|
|
||||||
console.log('');
|
|
||||||
|
|
||||||
for (const keyArg in globStringObjectArg) {
|
for (const keyArg in globStringObjectArg) {
|
||||||
// Type safety check for key
|
// Type safety check for key
|
||||||
if (keyArg && typeof keyArg === 'string' && globStringObjectArg[keyArg]) {
|
if (keyArg && typeof keyArg === 'string' && globStringObjectArg[keyArg]) {
|
||||||
|
console.log(
|
||||||
|
`TypeScript assignment: transpile from ${keyArg} to ${globStringObjectArg[keyArg]}`
|
||||||
|
);
|
||||||
|
|
||||||
// Get files matching the glob pattern
|
// Get files matching the glob pattern
|
||||||
const fileTreeArray = await plugins.smartfile.fs.listFileTree(cwdArg, keyArg);
|
const fileTreeArray = await plugins.smartfile.fs.listFileTree(cwdArg, keyArg);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user