diff --git a/.gitignore b/.gitignore index ef13c79..2e827e6 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ node_modules/ dist/ dist_*/ -# custom \ No newline at end of file +# custom +.claude \ No newline at end of file diff --git a/changelog.md b/changelog.md index 3cebf5d..3016e28 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,16 @@ # Changelog +## 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 diff --git a/package.json b/package.json index 73d7165..e141062 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "scripts": { "test": "tsrun test/test.ts", - "build": "node cli.ts.js --web --allowimplicitany", + "build": "node cli.ts.js --web", "buildDocs": "tsdoc" }, "repository": { @@ -65,5 +65,6 @@ ], "browserslist": [ "last 1 chrome versions" - ] + ], + "packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39" } diff --git a/readme.md b/readme.md index 4ca6bb5..277eb95 100644 --- a/readme.md +++ b/readme.md @@ -146,17 +146,42 @@ Example usage with glob patterns: 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 [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 Additional flags can be passed to any command to modify the compilation behavior: - `--skiplibcheck`: Skip type checking of declaration files (shows warning) -- `--allowimplicitany`: Allow variables to be implicitly typed as `any` +- `--disallowimplicitany`: Disallow variables to be implicitly typed as `any` (implicit any is allowed by default) - `--commonjs`: Use CommonJS module format instead of ESNext Example: ```bash -npx tsbuild --skiplibcheck --allowimplicitany +npx tsbuild --skiplibcheck --disallowimplicitany ``` ## Default Compiler Options @@ -175,7 +200,7 @@ By default, `@git.zone/tsbuild` uses the following compiler options: target: ScriptTarget.ESNext, moduleResolution: ModuleResolutionKind.NodeNext, lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'], - noImplicitAny: true, + noImplicitAny: false, // Now allowing implicit any by default esModuleInterop: true, useDefineForClassFields: false, verbatimModuleSyntax: true, diff --git a/readme.plan.md b/readme.plan.md new file mode 100644 index 0000000..761e6de --- /dev/null +++ b/readme.plan.md @@ -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 \ No newline at end of file diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 62d5ebf..88ce384 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@git.zone/tsbuild', - version: '2.3.2', + version: '2.4.0', description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.' } diff --git a/ts/tsbuild.classes.tsbuild.ts b/ts/tsbuild.classes.tsbuild.ts index ef3e8ee..da8b531 100644 --- a/ts/tsbuild.classes.tsbuild.ts +++ b/ts/tsbuild.classes.tsbuild.ts @@ -17,7 +17,7 @@ export const compilerOptionsDefault: CompilerOptions = { target: plugins.typescript.ScriptTarget.ESNext, moduleResolution: plugins.typescript.ModuleResolutionKind.NodeNext, lib: ['lib.dom.d.ts', 'lib.es2022.d.ts'], - noImplicitAny: true, + noImplicitAny: false, // Allow implicit any by default esModuleInterop: true, useDefineForClassFields: false, verbatimModuleSyntax: true, @@ -49,7 +49,6 @@ export class TsBuild { * Helper function to read and process tsconfig.json */ 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 returnObject: CompilerOptions = {}; @@ -57,16 +56,66 @@ export class TsBuild { return returnObject; } + // Process baseUrl if (tsconfig.compilerOptions.baseUrl) { - console.log('baseUrl found in tsconfig.json'); returnObject.baseUrl = tsconfig.compilerOptions.baseUrl; } + // Process paths if (tsconfig.compilerOptions.paths) { - console.log('paths found in tsconfig.json'); - returnObject.paths = tsconfig.compilerOptions.paths; - for (const path of Object.keys(tsconfig.compilerOptions.paths)) { - returnObject.paths[path][0] = returnObject.paths[path][0].replace('./ts_', './dist_ts_'); + 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_'); + } + } + } + + // 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]; } } @@ -85,8 +134,9 @@ export class TsBuild { options.skipLibCheck = true; } - if (argvArg.allowimplicitany) { - options.noImplicitAny = false; + // Changed behavior: --disallowimplicitany instead of --allowimplicitany + if (argvArg.disallowimplicitany) { + options.noImplicitAny = true; } if (argvArg.commonjs) { @@ -112,7 +162,6 @@ export class TsBuild { ...this.getTsConfigOptions(), }; - console.log(mergedOptions); return mergedOptions; } @@ -120,22 +169,94 @@ export class TsBuild { * Helper function to handle and log TypeScript diagnostics */ private handleDiagnostics(diagnostics: readonly plugins.typescript.Diagnostic[]): boolean { - let hasErrors = false; + if (diagnostics.length === 0) { + return false; + } + // Group errors by file for better readability + const errorsByFile: Record = {}; + const generalErrors: plugins.typescript.Diagnostic[] = []; + + // Categorize diagnostics 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}`); + const fileName = diagnostic.file.fileName; + if (!errorsByFile[fileName]) { + errorsByFile[fileName] = []; + } + errorsByFile[fileName].push(diagnostic); } else { - console.log( - `${plugins.typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}` - ); + generalErrors.push(diagnostic); } }); - return hasErrors; + // Print error summary header + 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; } /** @@ -166,14 +287,13 @@ export class TsBuild { */ public async compile(): Promise { if (this.options.skipLibCheck) { - console.log('? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?'); + console.log('\n⚠️ WARNING ⚠️'); console.log('You are skipping libcheck... Is that really wanted?'); - console.log('continuing in 5 seconds...'); - console.log('? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?'); + console.log('Continuing in 5 seconds...\n'); await plugins.smartdelay.delayFor(5000); } - console.log(`Compiling ${this.fileNames.length} files...`); + console.log(`🔨 Compiling ${this.fileNames.length} files...`); const done = plugins.smartpromise.defer(); const program = this.createProgram(); @@ -183,7 +303,8 @@ export class TsBuild { // Only continue to emit phase if no pre-emit errors if (hasPreEmitErrors) { - console.error('TypeScript pre-emit checks failed. Please fix the issues above.'); + 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'); process.exit(1); } @@ -193,10 +314,22 @@ export class TsBuild { const exitCode = emitResult.emitSkipped ? 1 : 0; if (exitCode === 0) { - console.log('TypeScript emit succeeded!'); + 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 { - console.error('TypeScript emit failed. Please investigate!'); + console.error('\n❌ TypeScript emit failed. Please investigate the errors listed above!'); + console.error(' No output files have been generated.\n'); process.exit(exitCode); } @@ -207,7 +340,8 @@ export class TsBuild { * Function to check if files can be emitted without actually emitting them */ public async checkEmit(): Promise { - console.log(`Checking if ${this.fileNames.length} files can be emitted...`); + 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({ @@ -226,9 +360,42 @@ export class TsBuild { const success = !hasPreEmitErrors && !hasEmitErrors && !emitResult.emitSkipped; if (success) { - console.log('TypeScript emit check passed! File can be emitted successfully.'); + 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 { - console.error('TypeScript emit check failed. Please fix the issues above.'); + 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 { + 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; @@ -268,4 +435,16 @@ export const emitCheck = async ( ): Promise => { 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 => { + const tsBuild = new TsBuild(fileNames, options, argvArg); + return tsBuild.checkTypes(); }; \ No newline at end of file diff --git a/ts/tsbuild.cli.ts b/ts/tsbuild.cli.ts index 319bbd0..8a0dff9 100644 --- a/ts/tsbuild.cli.ts +++ b/ts/tsbuild.cli.ts @@ -39,7 +39,9 @@ export const runCli = async () => { 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'); + console.error('\n❌ Error: Please provide at least one TypeScript file path or glob pattern'); + console.error(' Usage: tsbuild emitcheck [additional_patterns ...]\n'); + console.error(' Example: tsbuild emitcheck "src/**/*.ts" "test/**/*.ts"\n'); process.exit(1); } @@ -61,9 +63,9 @@ export const runCli = async () => { : []; if (stringMatchedFiles.length === 0) { - console.warn(`Warning: No files matched the pattern '${pattern}'`); + console.warn(`⚠️ Warning: No files matched the pattern '${pattern}'`); } else { - console.log(`Found ${stringMatchedFiles.length} files matching pattern '${pattern}'`); + console.log(`📂 Found ${stringMatchedFiles.length} files matching pattern '${pattern}'`); // Transform to absolute paths const absoluteMatchedFiles = plugins.smartpath.transform.toAbsolute( @@ -75,7 +77,7 @@ export const runCli = async () => { allFiles = allFiles.concat(absoluteMatchedFiles); } } catch (err) { - console.error(`Error processing glob pattern '${pattern}': ${err}`); + console.error(`❌ Error processing glob pattern '${pattern}': ${err}`); } } else { // Handle as direct file path @@ -87,7 +89,7 @@ export const runCli = async () => { await plugins.smartfile.fs.fileExists(filePath); allFiles.push(filePath); } catch (err) { - console.error(`Error: File not found: ${filePath}`); + console.error(`❌ Error: File not found: ${filePath}`); process.exit(1); } } @@ -97,11 +99,12 @@ export const runCli = async () => { allFiles = allFiles.filter(file => file.endsWith('.ts') || file.endsWith('.tsx')); if (allFiles.length === 0) { - console.error('Error: No TypeScript files found to check'); + 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(`Found ${allFiles.length} TypeScript files to check`); + console.log(`\n🔎 Found ${allFiles.length} TypeScript file${allFiles.length !== 1 ? 's' : ''} to check`); // Process compiler options const compilerOptions = tsbuild.mergeCompilerOptions({}, argvArg); @@ -161,13 +164,97 @@ export const runCli = async () => { const compilationCommandObject: { [key: string]: string } = {}; - console.log(`compiling in this order:`); - console.log(sortedTsFolders); + console.log(`\n🔄 Compiling TS folders in this order:`); + console.log(' ' + sortedTsFolders.join('\n ') + '\n'); for (const tsFolder of sortedTsFolders) { compilationCommandObject[`./${tsFolder}/**/*.ts`] = `./dist_${tsFolder}`; } 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 (patterns.length === 0) { + console.error('\n❌ Error: Please provide at least one TypeScript file path or glob pattern'); + console.error(' Usage: tsbuild check [additional_patterns ...]\n'); + console.error(' Example: tsbuild check "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 type check without emitting + const success = await tsbuild.checkTypes(allFiles, compilerOptions, argvArg); + + // Exit with appropriate code + process.exit(success ? 0 : 1); + }); tsbuildCli.startParse(); }; diff --git a/ts/tsbuild.exports.ts b/ts/tsbuild.exports.ts index b7dd8b4..e3da0c5 100644 --- a/ts/tsbuild.exports.ts +++ b/ts/tsbuild.exports.ts @@ -1,6 +1,6 @@ import * as plugins from './plugins.js'; import type { CompilerOptions, ScriptTarget, ModuleKind } from 'typescript'; -import { compiler, mergeCompilerOptions, emitCheck } from './tsbuild.classes.tsbuild.js'; +import { compiler, mergeCompilerOptions, emitCheck, checkTypes } from './tsbuild.classes.tsbuild.js'; export type { CompilerOptions, ScriptTarget, ModuleKind }; @@ -32,12 +32,16 @@ export let compileGlobStringObject = async ( ) => { 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) { // Type safety check for key if (keyArg && typeof keyArg === 'string' && globStringObjectArg[keyArg]) { - console.log( - `TypeScript assignment: transpile from ${keyArg} to ${globStringObjectArg[keyArg]}` - ); // Get files matching the glob pattern const fileTreeArray = await plugins.smartfile.fs.listFileTree(cwdArg, keyArg);