Created
January 31, 2024 16:44
-
-
Save rluvaton/a01089455037c937f2a6428bdc30aafa to your computer and use it in GitHub Desktop.
TypeCheck only on typescript project files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ts from 'typescript'; | |
import path from 'node:path'; | |
import Debug from 'debug'; | |
const debug = Debug('type-check-only-project-files'); | |
// ---------------------------------------------------------------- | |
// This file is a helper file that can be used to run type check | |
// only for the files that in the project and not for any other file | |
// ---------------------------------------------------------------- | |
const args = process.argv.slice(2); | |
if (!args.length || args.find(item => item === '--help' || item === '-h')) { | |
console.log(`Usage: node scripts/type-check.mjs <tsconfig path>`); | |
process.exit(0); | |
} | |
const tsconfigPath = args[0]; | |
if (!tsconfigPath) { | |
console.error('No tsconfig path provided.'); | |
process.exit(1); | |
} | |
console.log('Running type check with tsconfig:', tsconfigPath); | |
const cwd = process.cwd(); | |
function typeCheck() { | |
const configFile = path.isAbsolute(tsconfigPath) | |
? tsconfigPath | |
: ts.findConfigFile(cwd, ts.sys.fileExists, tsconfigPath); | |
if (!configFile) { | |
console.error('No tsconfig file found for path:', tsconfigPath); | |
process.exit(1); | |
} | |
const config = ts.readConfigFile(configFile, ts.sys.readFile); | |
// File names are only the files that in the project (without files in the tsconfig paths when they outside the project) | |
const { options, fileNames, raw } = ts.parseJsonConfigFileContent( | |
config.config, | |
ts.sys, | |
// Resolve to the folder where the tsconfig file located | |
path.dirname(tsconfigPath) | |
); | |
if (!options.skipLibCheck) { | |
console.error('The tsconfig must have skipLibCheck set to true as it wont be respected in the type check'); | |
process.exit(1); | |
} | |
const program = ts.createProgram({ | |
rootNames: fileNames, | |
options | |
}); | |
debug('fileNames', fileNames); | |
debug('parsed options raw', raw); | |
if (fileNames.length === 0) { | |
console.error('No files in the project.', { | |
fileNames, | |
options | |
}); | |
process.exit(1); | |
} | |
// Contain all files that the project depends | |
// so, no modules libs are there and files in the tsconfig paths even when outside the project | |
const sourceFiles = program.getSourceFiles(); | |
// To lower case as process.cwd() return in the actual case while the SourceFile.path returns in lower case | |
const absoluteFileNames = new Set(fileNames.map(item => path.join(cwd, item).toLowerCase())); | |
// Get the source files that only in the project | |
const projectSourceFiles = sourceFiles.filter(item => absoluteFileNames.has(item.path.toLowerCase())); | |
debug(`Number of files in project: ${projectSourceFiles.length}`); | |
if (projectSourceFiles.length === 0) { | |
console.error('No files found in project.', { | |
absoluteFileNames: Array.from(absoluteFileNames), | |
sourceFiles: sourceFiles.map(item => item.path) | |
}); | |
process.exit(1); | |
} | |
let projectDiagnostics = []; | |
// For each project source file run type check | |
// this only do type-check in the passed files and not for any other file (so tsconfig files that outside the project are not type checked) | |
for (const sourceFile of projectSourceFiles) { | |
debug('Running type check for file:', sourceFile.path); | |
const numberOfResultsBefore = projectDiagnostics.length; | |
projectDiagnostics = projectDiagnostics.concat( | |
// This do type check for a single file which prevent type checking files that outside the project | |
ts.getPreEmitDiagnostics(program, sourceFile) | |
); | |
if (projectDiagnostics.length > numberOfResultsBefore) { | |
debug( | |
`Have ${projectDiagnostics.length - numberOfResultsBefore} type check results for file`, | |
sourceFile.path | |
); | |
} else { | |
debug('No type check results for file', sourceFile.path); | |
} | |
} | |
if (projectDiagnostics.length > 0) { | |
debug(`Got ${projectDiagnostics.length} type check results for project`); | |
console.error( | |
ts.formatDiagnosticsWithColorAndContext(projectDiagnostics, { | |
getCanonicalFileName: fileName => fileName, | |
getCurrentDirectory: () => cwd, | |
getNewLine: () => ts.sys.newLine | |
}) | |
); | |
process.exit(1); | |
} | |
console.log(`TypeScript type checking successful for ${tsconfigPath} 🎉`); | |
} | |
// Call the function to perform type checking | |
typeCheck(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment