Compare commits
	
		
			4 Commits
		
	
	
		
			v2.2.6
			...
			9f42670865
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9f42670865 | |||
| 6cc9f41bd2 | |||
| 5d32ac85e0 | |||
| 4f2ac6922a | 
							
								
								
									
										14
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								changelog.md
									
									
									
									
									
								
							@@ -1,5 +1,19 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 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)
 | 
					## 2025-03-04 - 2.2.6 - fix(package)
 | 
				
			||||||
Fix repository URL in package.json
 | 
					Fix repository URL in package.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@git.zone/tsbuild",
 | 
					  "name": "@git.zone/tsbuild",
 | 
				
			||||||
  "version": "2.2.6",
 | 
					  "version": "2.3.0",
 | 
				
			||||||
  "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",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								readme.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								readme.md
									
									
									
									
									
								
							@@ -121,6 +121,31 @@ compiling in this order:
 | 
				
			|||||||
[ 'ts_interfaces', 'ts_shared', 'ts_core', 'ts_utils', 'ts_modules' ]
 | 
					[ 'ts_interfaces', 'ts_shared', 'ts_core', 'ts_utils', 'ts_modules' ]
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### EmitCheck Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Checks if TypeScript files can be emitted without actually emitting them:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					npx tsbuild emitcheck <file_or_glob_pattern> [additional_patterns ...]
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This command:
 | 
				
			||||||
 | 
					1. Performs type checking on the specified TypeScript file(s)
 | 
				
			||||||
 | 
					2. Supports both direct file paths and glob patterns
 | 
				
			||||||
 | 
					3. Reports any errors that would prevent successful compilation
 | 
				
			||||||
 | 
					4. Exits with code 0 if all files can be emitted, or 1 if any cannot
 | 
				
			||||||
 | 
					5. Doesn't produce any output files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example usage with specific files:
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					npx tsbuild emitcheck src/main.ts src/utils.ts
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example usage with glob patterns:
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					npx tsbuild emitcheck "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:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,6 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
export const commitinfo = {
 | 
					export const commitinfo = {
 | 
				
			||||||
  name: '@git.zone/tsbuild',
 | 
					  name: '@git.zone/tsbuild',
 | 
				
			||||||
  version: '2.2.6',
 | 
					  version: '2.3.0',
 | 
				
			||||||
  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.'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -93,17 +93,15 @@ export const compiler = async (
 | 
				
			|||||||
  console.log(`Compiling ${fileNames.length} files...`);
 | 
					  console.log(`Compiling ${fileNames.length} files...`);
 | 
				
			||||||
  const done = plugins.smartpromise.defer<any[]>();
 | 
					  const done = plugins.smartpromise.defer<any[]>();
 | 
				
			||||||
  const program = plugins.typescript.createProgram(fileNames, options);
 | 
					  const program = plugins.typescript.createProgram(fileNames, options);
 | 
				
			||||||
  const emitResult = program.emit();
 | 
					 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  // implement check only
 | 
					  // Check for pre-emit diagnostics first
 | 
				
			||||||
  /*let emitResult = program.emit(undefined,(args) => {
 | 
					  const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
				
			||||||
    console.log(args)
 | 
					  let hasErrors = false;
 | 
				
			||||||
  });*/
 | 
					 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  const allDiagnostics = plugins.typescript
 | 
					  // Log pre-emit diagnostics if any
 | 
				
			||||||
    .getPreEmitDiagnostics(program)
 | 
					  if (preEmitDiagnostics.length > 0) {
 | 
				
			||||||
    .concat(emitResult.diagnostics);
 | 
					    preEmitDiagnostics.forEach((diagnostic) => {
 | 
				
			||||||
  allDiagnostics.forEach((diagnostic) => {
 | 
					      hasErrors = true;
 | 
				
			||||||
      if (diagnostic.file) {
 | 
					      if (diagnostic.file) {
 | 
				
			||||||
        const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
 | 
					        const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
 | 
				
			||||||
        const message = plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
 | 
					        const message = plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
 | 
				
			||||||
@@ -114,6 +112,31 @@ export const compiler = async (
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Only continue to emit phase if no pre-emit errors
 | 
				
			||||||
 | 
					  if (hasErrors) {
 | 
				
			||||||
 | 
					    console.error('TypeScript pre-emit checks failed. Please fix the issues above.');
 | 
				
			||||||
 | 
					    process.exit(1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // If no pre-emit errors, proceed with emit
 | 
				
			||||||
 | 
					  const emitResult = program.emit();
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Check for emit diagnostics
 | 
				
			||||||
 | 
					  if (emitResult.diagnostics.length > 0) {
 | 
				
			||||||
 | 
					    emitResult.diagnostics.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;
 | 
					  const exitCode = emitResult.emitSkipped ? 1 : 0;
 | 
				
			||||||
  if (exitCode === 0) {
 | 
					  if (exitCode === 0) {
 | 
				
			||||||
@@ -126,3 +149,67 @@ export const compiler = async (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return done.promise;
 | 
					  return done.promise;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Function to check if a TypeScript file can be emitted without actually emitting it
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const emitCheck = async (
 | 
				
			||||||
 | 
					  fileNames: string[],
 | 
				
			||||||
 | 
					  options: plugins.typescript.CompilerOptions = {},
 | 
				
			||||||
 | 
					  argvArg?: any
 | 
				
			||||||
 | 
					): Promise<boolean> => {
 | 
				
			||||||
 | 
					  console.log(`Checking if ${fileNames.length} files can be emitted...`);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Create a program
 | 
				
			||||||
 | 
					  const program = plugins.typescript.createProgram(fileNames, {
 | 
				
			||||||
 | 
					    ...options,
 | 
				
			||||||
 | 
					    noEmit: true
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Check for pre-emit diagnostics
 | 
				
			||||||
 | 
					  const preEmitDiagnostics = plugins.typescript.getPreEmitDiagnostics(program);
 | 
				
			||||||
 | 
					  let hasErrors = false;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Log pre-emit diagnostics if any
 | 
				
			||||||
 | 
					  if (preEmitDiagnostics.length > 0) {
 | 
				
			||||||
 | 
					    preEmitDiagnostics.forEach((diagnostic) => {
 | 
				
			||||||
 | 
					      hasErrors = true;
 | 
				
			||||||
 | 
					      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')}`
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Run the emit phase but with noEmit: true to check for emit errors without producing files
 | 
				
			||||||
 | 
					  const emitResult = program.emit(undefined, undefined, undefined, true);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // Check for emit diagnostics
 | 
				
			||||||
 | 
					  if (emitResult.diagnostics.length > 0) {
 | 
				
			||||||
 | 
					    emitResult.diagnostics.forEach((diagnostic) => {
 | 
				
			||||||
 | 
					      hasErrors = true;
 | 
				
			||||||
 | 
					      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')}`
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  if (!hasErrors && !emitResult.emitSkipped) {
 | 
				
			||||||
 | 
					    console.log('TypeScript emit check passed! File can be emitted successfully.');
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    console.error('TypeScript emit check failed. Please fix the issues above.');
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,87 @@ export const runCli = async () => {
 | 
				
			|||||||
    await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
 | 
					    await tsbuild.compileGlobStringObject(compilationCommandObject, {}, process.cwd(), argvArg);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 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('Error: Please provide at least one TypeScript file path or glob pattern');
 | 
				
			||||||
 | 
					      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('Error: No TypeScript files found to check');
 | 
				
			||||||
 | 
					      process.exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    console.log(`Found ${allFiles.length} TypeScript files 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
 | 
					   * the custom command compiles any customDir to dist_customDir
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 } from './tsbuild.classes.compiler.js';
 | 
					import { compiler, mergeCompilerOptions, emitCheck } from './tsbuild.classes.compiler.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type { CompilerOptions, ScriptTarget, ModuleKind };
 | 
					export type { CompilerOptions, ScriptTarget, ModuleKind };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user