From 5ca1d789752a84cd67b33faf5829b12dc6d1389e Mon Sep 17 00:00:00 2001 From: Hinton Date: Tue, 22 Jul 2025 14:12:52 +0200 Subject: [PATCH] Task 1 --- .gitignore | 1 + .kiro/specs/ts-strict-migration/tasks.md | 2 +- package.json | 6 + scripts/README-strict-mode.md | 223 +++++++++++++++ scripts/strict-mode-utils.js | 294 +++++++++++++++++++ scripts/test-strict-compliance.js | 344 +++++++++++++++++++++++ 6 files changed, 869 insertions(+), 1 deletion(-) create mode 100644 scripts/README-strict-mode.md create mode 100755 scripts/strict-mode-utils.js create mode 100755 scripts/test-strict-compliance.js diff --git a/.gitignore b/.gitignore index 0fa968aa47c..ff57e6fb012 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,4 @@ apps/**/config/local.json # Nx .nx +strict-compliance-report.json diff --git a/.kiro/specs/ts-strict-migration/tasks.md b/.kiro/specs/ts-strict-migration/tasks.md index b13a878e6ac..b51a9d7ca73 100644 --- a/.kiro/specs/ts-strict-migration/tasks.md +++ b/.kiro/specs/ts-strict-migration/tasks.md @@ -1,6 +1,6 @@ # Implementation Plan -- [-] 1. Set up infrastructure and tooling for strict mode migration +- [x] 1. Set up infrastructure and tooling for strict mode migration - Create utility scripts to identify files with @ts-strict-ignore comments - Implement automated testing for strict mode compliance diff --git a/package.json b/package.json index 089ef3342e9..7db6a4a585c 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,12 @@ "test:watch": "jest --clearCache && jest --watch", "test:watch:all": "jest --watchAll", "test:types": "node ./scripts/test-types.js", + "test:strict": "node ./scripts/test-strict-compliance.js", + "test:strict:all": "node ./scripts/test-strict-compliance.js all", + "test:strict:plugin": "node ./scripts/test-strict-compliance.js plugin", + "strict:find": "node ./scripts/strict-mode-utils.js find", + "strict:progress": "node ./scripts/strict-mode-utils.js progress", + "strict:test": "node ./scripts/strict-mode-utils.js test", "test:locales": "tsc --project ./scripts/tsconfig.json && node ./scripts/dist/test-locales.js", "lint:dep-ownership": "tsc --project ./scripts/tsconfig.json && node ./scripts/dist/dep-ownership.js", "docs:json": "compodoc -p ./tsconfig.json -e json -d . --disableRoutesGraph", diff --git a/scripts/README-strict-mode.md b/scripts/README-strict-mode.md new file mode 100644 index 00000000000..a462261498f --- /dev/null +++ b/scripts/README-strict-mode.md @@ -0,0 +1,223 @@ +# TypeScript Strict Mode Migration Utilities + +This directory contains utilities to help with the TypeScript strict mode migration process for the Bitwarden client codebase. + +## Overview + +The migration involves systematically enabling TypeScript strict mode across all applications and libraries. Currently, the codebase uses `typescript-strict-plugin` to allow gradual migration by excluding files with `@ts-strict-ignore` comments from strict checking. + +## Utilities + +### 1. Strict Mode Utils (`strict-mode-utils.js`) + +A comprehensive utility for managing the strict mode migration process. + +#### Commands + +```bash +# Find all files with @ts-strict-ignore comments +node scripts/strict-mode-utils.js find + +# Generate migration progress report +node scripts/strict-mode-utils.js progress + +# Test strict mode compliance for entire codebase +node scripts/strict-mode-utils.js test + +# Test strict mode compliance for specific project +node scripts/strict-mode-utils.js test libs/platform + +# Check typescript-strict-plugin status +node scripts/strict-mode-utils.js plugin +``` + +#### NPM Scripts + +```bash +# Find files with @ts-strict-ignore comments +npm run strict:find + +# Generate progress report +npm run strict:progress + +# Test strict mode compliance +npm run strict:test +``` + +### 2. Strict Compliance Tester (`test-strict-compliance.js`) + +Automated testing for strict mode compliance across projects. + +#### Commands + +```bash +# Test all projects for strict mode compliance +node scripts/test-strict-compliance.js all + +# Test projects matching a pattern +node scripts/test-strict-compliance.js pattern libs/platform +node scripts/test-strict-compliance.js pattern apps/ + +# Test current typescript-strict-plugin functionality +node scripts/test-strict-compliance.js plugin +``` + +#### NPM Scripts + +```bash +# Test all projects +npm run test:strict:all + +# Test typescript-strict-plugin +npm run test:strict:plugin +``` + +## Migration Process + +### Current State + +- **Total files with @ts-strict-ignore**: ~1,245 files +- **TypeScript strict plugin**: Active (version 2.4.4) +- **Base configuration**: `"strict": false` with plugin providing selective checking + +### Migration Categories + +The migration follows this order (as defined in the spec): + +1. **Core Libraries** (`libs/platform`, `libs/common`) +2. **Domain Libraries** (`libs/auth`, `libs/vault`, etc.) +3. **UI Libraries** (`libs/components`, `libs/angular`) +4. **Applications** (`apps/cli`, `apps/browser`, `apps/desktop`, `apps/web`) +5. **Licensed Features** (`bitwarden_license/`) + +### Per-Category Progress + +| Category | Files with @ts-strict-ignore | +| ------------------ | ---------------------------- | +| libs/common | 381 files | +| apps/web | 239 files | +| apps/browser | 114 files | +| bitwarden_license | 115 files | +| other | 67 files | +| libs/components | 62 files | +| libs/tools | 54 files | +| libs/angular | 51 files | +| apps/cli | 45 files | +| apps/desktop | 39 files | +| libs/auth | 33 files | +| libs/vault | 28 files | +| libs/admin-console | 17 files | + +## Usage Examples + +### Finding Files to Migrate + +```bash +# Get overview of migration status +npm run strict:progress + +# Find all files that need migration +npm run strict:find +``` + +### Testing Compliance + +```bash +# Test if a specific library is ready for strict mode +node scripts/test-strict-compliance.js pattern libs/storage + +# Test all projects (warning: this will take time and likely show many failures) +npm run test:strict:all +``` + +### During Migration + +1. **Before starting a library migration**: + + ```bash + # Check current status + node scripts/test-strict-compliance.js pattern libs/platform + ``` + +2. **After fixing strict mode violations**: + + ```bash + # Test compliance + node scripts/test-strict-compliance.js pattern libs/platform + + # Check progress + npm run strict:progress + ``` + +3. **Final validation**: + + ```bash + # Test that typescript-strict-plugin still works + npm run test:strict:plugin + + # Generate final report + npm run strict:progress + ``` + +## Output Files + +### `strict-compliance-report.json` + +Generated by the compliance tester, contains: + +- Timestamp of test run +- Summary statistics (total, passed, failed, pass rate) +- Detailed results for each project tested +- Error details for failed projects + +## Integration with Existing Tools + +### Existing Type Checking + +The existing `npm run test:types` command runs: + +- `npx tsc-strict` (typescript-strict-plugin) +- Type checking for all library tsconfig.json files + +### New Strict Mode Testing + +The new utilities complement existing tools by: + +- Testing native TypeScript strict mode (without plugin) +- Providing detailed progress tracking +- Enabling targeted testing of specific projects +- Generating comprehensive reports + +## Migration Workflow + +1. **Assessment**: Use `strict:progress` to see current state +2. **Planning**: Use `strict:find` to identify files in target library +3. **Testing**: Use `test-strict-compliance.js pattern ` to test current compliance +4. **Implementation**: Fix strict mode violations in the library +5. **Validation**: Re-test with compliance tester +6. **Configuration**: Update library's tsconfig.json to enable strict mode +7. **Final Check**: Ensure all tests pass and plugin still works + +## Notes + +- The utilities create temporary tsconfig files for testing but clean them up automatically +- Failed tests include error output to help identify what needs to be fixed +- The progress report shows the current state without making any changes +- All utilities are safe to run and don't modify source code + +## Troubleshooting + +### Common Issues + +1. **"Cannot find module" errors**: Ensure you're running from the project root +2. **Permission errors**: Make sure the scripts have execute permissions +3. **TypeScript compilation errors**: These are expected during migration and indicate what needs to be fixed + +### Getting Help + +Run any utility without arguments to see usage information: + +```bash +node scripts/strict-mode-utils.js +node scripts/test-strict-compliance.js +``` diff --git a/scripts/strict-mode-utils.js b/scripts/strict-mode-utils.js new file mode 100755 index 00000000000..cd75f120df1 --- /dev/null +++ b/scripts/strict-mode-utils.js @@ -0,0 +1,294 @@ +#!/usr/bin/env node + +/** + * Utility scripts for TypeScript strict mode migration + * + * This script provides utilities to: + * 1. Identify files with @ts-strict-ignore comments + * 2. Test strict mode compliance + * 3. Track migration progress + */ + +const fs = require("fs"); +const path = require("path"); +const { execSync } = require("child_process"); + +class StrictModeUtils { + constructor() { + this.rootDir = path.resolve(__dirname, ".."); + this.tsStrictIgnorePattern = /@ts-strict-ignore/; + } + + /** + * Recursively find all TypeScript files in a directory + */ + findTsFiles(dir, excludeDirs = ["node_modules", "dist", "coverage", ".git", ".angular"]) { + const results = []; + + try { + const files = fs.readdirSync(dir); + + for (const file of files) { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); + + if (stat.isDirectory()) { + if (!excludeDirs.includes(file)) { + results.push(...this.findTsFiles(filePath, excludeDirs)); + } + } else if (file.endsWith(".ts") && !file.endsWith(".d.ts")) { + results.push(filePath); + } + } + } catch (error) { + console.warn(`Warning: Could not read directory ${dir}: ${error.message}`); + } + + return results; + } + + /** + * Find all files with @ts-strict-ignore comments + */ + findFilesWithStrictIgnore() { + console.log("๐Ÿ” Scanning for files with @ts-strict-ignore comments...\n"); + + const tsFiles = this.findTsFiles(this.rootDir); + const filesWithIgnore = []; + + for (const filePath of tsFiles) { + try { + const content = fs.readFileSync(filePath, "utf8"); + if (this.tsStrictIgnorePattern.test(content)) { + const relativePath = path.relative(this.rootDir, filePath); + filesWithIgnore.push({ + path: relativePath, + fullPath: filePath, + }); + } + } catch (error) { + console.warn(`Warning: Could not read file ${filePath}: ${error.message}`); + } + } + + return filesWithIgnore; + } + + /** + * Generate a report of files with @ts-strict-ignore comments + */ + generateIgnoreReport() { + const filesWithIgnore = this.findFilesWithStrictIgnore(); + + console.log(`๐Ÿ“Š Found ${filesWithIgnore.length} files with @ts-strict-ignore comments:\n`); + + // Group by directory for better organization + const byDirectory = {}; + filesWithIgnore.forEach((file) => { + const dir = path.dirname(file.path); + if (!byDirectory[dir]) { + byDirectory[dir] = []; + } + byDirectory[dir].push(file.path); + }); + + // Sort directories and display + const sortedDirs = Object.keys(byDirectory).sort(); + for (const dir of sortedDirs) { + console.log(`๐Ÿ“ ${dir}/`); + byDirectory[dir].forEach((file) => { + const fileName = path.basename(file); + console.log(` - ${fileName}`); + }); + console.log(); + } + + return filesWithIgnore; + } + + /** + * Test strict mode compliance for a specific project + */ + testStrictCompliance(projectPath = null) { + console.log("๐Ÿงช Testing TypeScript strict mode compliance...\n"); + + try { + let command; + if (projectPath) { + const tsConfigPath = path.join(projectPath, "tsconfig.json"); + if (!fs.existsSync(tsConfigPath)) { + throw new Error(`tsconfig.json not found at ${tsConfigPath}`); + } + command = `npx tsc --noEmit --strict --project ${tsConfigPath}`; + console.log(`Testing project: ${projectPath}`); + } else { + command = "npx tsc --noEmit --strict"; + console.log("Testing entire codebase with strict mode..."); + } + + console.log(`Running: ${command}\n`); + + const output = execSync(command, { + cwd: this.rootDir, + encoding: "utf8", + stdio: "pipe", + }); + + console.log("โœ… Strict mode compliance test passed!"); + if (output.trim()) { + console.log("Output:", output); + } + + return { success: true, output }; + } catch (error) { + console.log("โŒ Strict mode compliance test failed!"); + console.log("Error output:"); + console.log(error.stdout || error.message); + + return { success: false, error: error.stdout || error.message }; + } + } + + /** + * Check if typescript-strict-plugin is being used + */ + checkStrictPlugin() { + console.log("๐Ÿ”Œ Checking typescript-strict-plugin usage...\n"); + + try { + // Check if plugin is in package.json + const packageJsonPath = path.join(this.rootDir, "package.json"); + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); + const hasPlugin = + packageJson.devDependencies && packageJson.devDependencies["typescript-strict-plugin"]; + + // Check if plugin is configured in tsconfig + const tsConfigPath = path.join(this.rootDir, "tsconfig.base.json"); + const tsConfig = JSON.parse(fs.readFileSync(tsConfigPath, "utf8")); + const hasPluginConfig = + tsConfig.compilerOptions && + tsConfig.compilerOptions.plugins && + tsConfig.compilerOptions.plugins.some((p) => p.name === "typescript-strict-plugin"); + + console.log(`Plugin in package.json: ${hasPlugin ? "โœ…" : "โŒ"}`); + console.log(`Plugin in tsconfig: ${hasPluginConfig ? "โœ…" : "โŒ"}`); + + if (hasPlugin) { + console.log(`Plugin version: ${packageJson.devDependencies["typescript-strict-plugin"]}`); + } + + return { hasPlugin, hasPluginConfig }; + } catch (error) { + console.error("Error checking plugin status:", error.message); + return { hasPlugin: false, hasPluginConfig: false }; + } + } + + /** + * Generate migration progress report + */ + generateProgressReport() { + console.log("๐Ÿ“ˆ Generating migration progress report...\n"); + + const filesWithIgnore = this.findFilesWithStrictIgnore(); + const pluginStatus = this.checkStrictPlugin(); + + // Count files by category + const categories = { + "libs/platform": 0, + "libs/common": 0, + "libs/auth": 0, + "libs/vault": 0, + "libs/key-management": 0, + "libs/admin-console": 0, + "libs/billing": 0, + "libs/tools": 0, + "libs/components": 0, + "libs/angular": 0, + "apps/cli": 0, + "apps/browser": 0, + "apps/desktop": 0, + "apps/web": 0, + bitwarden_license: 0, + other: 0, + }; + + filesWithIgnore.forEach((file) => { + let categorized = false; + for (const category of Object.keys(categories)) { + if (file.path.startsWith(category)) { + categories[category]++; + categorized = true; + break; + } + } + if (!categorized) { + categories.other++; + } + }); + + console.log("Migration Progress by Category:"); + console.log("================================"); + + for (const [category, count] of Object.entries(categories)) { + if (count > 0) { + console.log(`${category.padEnd(25)} ${count.toString().padStart(3)} files`); + } + } + + console.log(`\nTotal files with @ts-strict-ignore: ${filesWithIgnore.length}`); + console.log(`TypeScript strict plugin active: ${pluginStatus.hasPlugin ? "Yes" : "No"}`); + + return { + totalFiles: filesWithIgnore.length, + categories, + pluginActive: pluginStatus.hasPlugin, + }; + } +} + +// CLI interface +if (require.main === module) { + const utils = new StrictModeUtils(); + const command = process.argv[2]; + + switch (command) { + case "find": + utils.generateIgnoreReport(); + break; + + case "test": + const projectPath = process.argv[3]; + utils.testStrictCompliance(projectPath); + break; + + case "progress": + utils.generateProgressReport(); + break; + + case "plugin": + utils.checkStrictPlugin(); + break; + + default: + console.log("TypeScript Strict Mode Migration Utilities"); + console.log("=========================================="); + console.log(""); + console.log("Usage: node scripts/strict-mode-utils.js "); + console.log(""); + console.log("Commands:"); + console.log(" find - Find all files with @ts-strict-ignore comments"); + console.log(" test - Test strict mode compliance (optionally for specific project)"); + console.log(" progress - Generate migration progress report"); + console.log(" plugin - Check typescript-strict-plugin status"); + console.log(""); + console.log("Examples:"); + console.log(" node scripts/strict-mode-utils.js find"); + console.log(" node scripts/strict-mode-utils.js test"); + console.log(" node scripts/strict-mode-utils.js test libs/platform"); + console.log(" node scripts/strict-mode-utils.js progress"); + break; + } +} + +module.exports = StrictModeUtils; diff --git a/scripts/test-strict-compliance.js b/scripts/test-strict-compliance.js new file mode 100755 index 00000000000..0d5d10b6f75 --- /dev/null +++ b/scripts/test-strict-compliance.js @@ -0,0 +1,344 @@ +#!/usr/bin/env node + +/** + * Automated testing script for TypeScript strict mode compliance + * + * This script tests strict mode compliance across different parts of the codebase + * and provides detailed reporting for the migration process. + */ + +const fs = require("fs"); +const path = require("path"); +const { execSync, spawn } = require("child_process"); +const StrictModeUtils = require("./strict-mode-utils"); + +class StrictComplianceTester { + constructor() { + this.rootDir = path.resolve(__dirname, ".."); + this.utils = new StrictModeUtils(); + this.results = { + passed: [], + failed: [], + skipped: [], + }; + } + + /** + * Get all TypeScript configuration files in the project + */ + getTsConfigFiles() { + const tsConfigs = []; + + // Find all tsconfig.json files + const findTsConfigs = ( + dir, + excludeDirs = ["node_modules", "dist", "coverage", ".git", ".angular"], + ) => { + try { + const files = fs.readdirSync(dir); + + for (const file of files) { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); + + if (stat.isDirectory()) { + if (!excludeDirs.includes(file)) { + findTsConfigs(filePath, excludeDirs); + } + } else if (file === "tsconfig.json") { + const relativePath = path.relative(this.rootDir, filePath); + // Skip shared directory as mentioned in test-types.js + if (!relativePath.includes("libs/shared/")) { + tsConfigs.push({ + path: relativePath, + fullPath: filePath, + directory: path.dirname(relativePath), + }); + } + } + } + } catch (error) { + console.warn(`Warning: Could not read directory ${dir}: ${error.message}`); + } + }; + + findTsConfigs(this.rootDir); + return tsConfigs; + } + + /** + * Test strict mode compliance for a specific TypeScript configuration + */ + async testProjectStrictCompliance(tsConfigInfo) { + const { path: configPath, directory } = tsConfigInfo; + + console.log(`\n๐Ÿงช Testing ${directory}...`); + + try { + // Create a temporary strict tsconfig for testing + const originalConfig = JSON.parse(fs.readFileSync(tsConfigInfo.fullPath, "utf8")); + const testConfig = { + ...originalConfig, + compilerOptions: { + ...originalConfig.compilerOptions, + strict: true, + // Enable all strict flags explicitly + noImplicitAny: true, + strictNullChecks: true, + strictFunctionTypes: true, + strictBindCallApply: true, + strictPropertyInitialization: true, + noImplicitReturns: true, + noImplicitThis: true, + }, + }; + + // Remove typescript-strict-plugin if present + if (testConfig.compilerOptions.plugins) { + testConfig.compilerOptions.plugins = testConfig.compilerOptions.plugins.filter( + (plugin) => plugin.name !== "typescript-strict-plugin", + ); + } + + const tempConfigPath = path.join( + path.dirname(tsConfigInfo.fullPath), + "tsconfig.strict-test.json", + ); + fs.writeFileSync(tempConfigPath, JSON.stringify(testConfig, null, 2)); + + try { + const command = `npx tsc --noEmit --project ${tempConfigPath}`; + const output = execSync(command, { + cwd: this.rootDir, + encoding: "utf8", + stdio: "pipe", + }); + + console.log(` โœ… ${directory} - PASSED`); + this.results.passed.push({ + project: directory, + configPath, + output: output.trim(), + }); + + return { success: true, project: directory, output }; + } finally { + // Clean up temporary config file + if (fs.existsSync(tempConfigPath)) { + fs.unlinkSync(tempConfigPath); + } + } + } catch (error) { + console.log(` โŒ ${directory} - FAILED`); + + const errorOutput = error.stdout || error.stderr || error.message; + this.results.failed.push({ + project: directory, + configPath, + error: errorOutput, + }); + + return { success: false, project: directory, error: errorOutput }; + } + } + + /** + * Test strict mode compliance for all projects + */ + async testAllProjects() { + console.log("๐Ÿš€ Starting comprehensive strict mode compliance testing...\n"); + + const tsConfigs = this.getTsConfigFiles(); + console.log(`Found ${tsConfigs.length} TypeScript configuration files to test.\n`); + + // Test each project + for (const tsConfig of tsConfigs) { + await this.testProjectStrictCompliance(tsConfig); + } + + this.generateTestReport(); + return this.results; + } + + /** + * Test specific projects by pattern + */ + async testProjectsByPattern(pattern) { + console.log(`๐ŸŽฏ Testing projects matching pattern: ${pattern}\n`); + + const tsConfigs = this.getTsConfigFiles(); + const matchingConfigs = tsConfigs.filter((config) => config.directory.includes(pattern)); + + if (matchingConfigs.length === 0) { + console.log(`No projects found matching pattern: ${pattern}`); + return this.results; + } + + console.log(`Found ${matchingConfigs.length} matching projects:\n`); + matchingConfigs.forEach((config) => console.log(` - ${config.directory}`)); + console.log(); + + for (const tsConfig of matchingConfigs) { + await this.testProjectStrictCompliance(tsConfig); + } + + this.generateTestReport(); + return this.results; + } + + /** + * Generate a detailed test report + */ + generateTestReport() { + console.log("\n๐Ÿ“Š STRICT MODE COMPLIANCE TEST REPORT"); + console.log("=====================================\n"); + + const total = + this.results.passed.length + this.results.failed.length + this.results.skipped.length; + const passRate = total > 0 ? ((this.results.passed.length / total) * 100).toFixed(1) : 0; + + console.log(`Total Projects Tested: ${total}`); + console.log(`Passed: ${this.results.passed.length} (${passRate}%)`); + console.log(`Failed: ${this.results.failed.length}`); + console.log(`Skipped: ${this.results.skipped.length}\n`); + + if (this.results.passed.length > 0) { + console.log("โœ… PASSED PROJECTS:"); + console.log("-------------------"); + this.results.passed.forEach((result) => { + console.log(` ${result.project}`); + }); + console.log(); + } + + if (this.results.failed.length > 0) { + console.log("โŒ FAILED PROJECTS:"); + console.log("-------------------"); + this.results.failed.forEach((result) => { + console.log(` ${result.project}`); + // Show first few lines of error for context + const errorLines = result.error.split("\n").slice(0, 3); + errorLines.forEach((line) => { + if (line.trim()) { + console.log(` ${line.trim()}`); + } + }); + console.log(); + }); + } + + // Save detailed report to file + const reportPath = path.join(this.rootDir, "strict-compliance-report.json"); + fs.writeFileSync( + reportPath, + JSON.stringify( + { + timestamp: new Date().toISOString(), + summary: { + total, + passed: this.results.passed.length, + failed: this.results.failed.length, + skipped: this.results.skipped.length, + passRate: parseFloat(passRate), + }, + results: this.results, + }, + null, + 2, + ), + ); + + console.log(`๐Ÿ“„ Detailed report saved to: ${reportPath}\n`); + + if (this.results.failed.length === 0) { + console.log("๐ŸŽ‰ All projects are strict mode compliant!"); + } else { + console.log( + `โš ๏ธ ${this.results.failed.length} projects need attention before enabling strict mode.`, + ); + } + } + + /** + * Test current typescript-strict-plugin functionality + */ + testStrictPlugin() { + console.log("๐Ÿ”Œ Testing typescript-strict-plugin functionality...\n"); + + try { + const command = "npx tsc-strict"; + console.log(`Running: ${command}`); + + const output = execSync(command, { + cwd: this.rootDir, + encoding: "utf8", + stdio: "pipe", + }); + + console.log("โœ… typescript-strict-plugin test passed!"); + if (output.trim()) { + console.log("Output:", output); + } + + return { success: true, output }; + } catch (error) { + console.log("โŒ typescript-strict-plugin test failed!"); + console.log("Error:", error.stdout || error.message); + + return { success: false, error: error.stdout || error.message }; + } + } +} + +// CLI interface +if (require.main === module) { + const tester = new StrictComplianceTester(); + const command = process.argv[2]; + const pattern = process.argv[3]; + + async function main() { + switch (command) { + case "all": + await tester.testAllProjects(); + break; + + case "pattern": + if (!pattern) { + console.error("Error: Pattern required for pattern command"); + console.log("Usage: node scripts/test-strict-compliance.js pattern "); + process.exit(1); + } + await tester.testProjectsByPattern(pattern); + break; + + case "plugin": + tester.testStrictPlugin(); + break; + + default: + console.log("TypeScript Strict Mode Compliance Tester"); + console.log("========================================"); + console.log(""); + console.log("Usage: node scripts/test-strict-compliance.js [options]"); + console.log(""); + console.log("Commands:"); + console.log(" all - Test all projects for strict mode compliance"); + console.log(" pattern - Test projects matching a specific pattern"); + console.log(" plugin - Test current typescript-strict-plugin functionality"); + console.log(""); + console.log("Examples:"); + console.log(" node scripts/test-strict-compliance.js all"); + console.log(" node scripts/test-strict-compliance.js pattern libs/platform"); + console.log(" node scripts/test-strict-compliance.js pattern apps/"); + console.log(" node scripts/test-strict-compliance.js plugin"); + break; + } + } + + main().catch((error) => { + console.error("Error:", error); + process.exit(1); + }); +} + +module.exports = StrictComplianceTester;