Last active
June 29, 2023 10:08
-
-
Save lifeart/5168d2e4c98068525db3182c36fdf063 to your computer and use it in GitHub Desktop.
Typescript custom diagnostics
This file contains 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
const ts = require('typescript'); | |
const fs = require('fs'); | |
const path = require('path'); | |
function getFileInfo(file, start) { | |
const { fileName } = file; | |
const { line, character } = file.getLineAndCharacterOfPosition(start); | |
return { fileName, line: line + 1, character: character + 1 }; | |
} | |
function reportDiagnostics(diagnostics) { | |
const errors = diagnostics.map(diagnostic => { | |
const { file, messageText, start } = diagnostic; | |
if (file) { | |
const { fileName, line, character } = getFileInfo(file, start); | |
return `Error ${fileName} (${line},${character}): ${ts.flattenDiagnosticMessageText(messageText, '\n')}`; | |
} else { | |
return `Error: ${ts.flattenDiagnosticMessageText(messageText, '\n')}`; | |
} | |
}); | |
console.error(errors.join('\n')); | |
} | |
function readConfigFile(configFileName) { | |
const configFileText = fs.readFileSync(configFileName).toString(); | |
const result = ts.parseConfigFileTextToJson(configFileName, configFileText); | |
return ts.parseJsonConfigFileContent(result.config, ts.sys, path.dirname(configFileName)); | |
} | |
function compile(configFileName) { | |
const config = readConfigFile(configFileName); | |
const program = ts.createProgram(config.fileNames, config.options); | |
const emitResult = program.emit(); | |
const results = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics); | |
reportDiagnostics(results); | |
console.warn('Compilation completed'); | |
process.exit(0); | |
} | |
compile('jsconfig.json'); |
This file contains 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
// https://github.com/microsoft/TypeScript-wiki/blob/main/Using-the-Compiler-API.md | |
const ts = require('typescript'); | |
const fs = require('fs'); | |
const path = require('path'); | |
const MAX_ERRORS = 411; | |
const MAX_FILES_WITH_ERRORS = 109; | |
/** | |
* | |
* @param {Array<import('typescript').Diagnostic>} diagnostics | |
*/ | |
function reportDiagnostics(diagnostics) { | |
const files = {}; | |
const generalErrors = []; | |
diagnostics.forEach(diagnostic => { | |
if (diagnostic.file) { | |
const { fileName } = diagnostic.file; | |
if (fileName.includes('bower_components') || fileName.includes('polyfills') || fileName.includes('vendor')) { | |
return; | |
} | |
} | |
let message = 'Error'; | |
if (diagnostic.file) { | |
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); | |
message += ` ${diagnostic.file.fileName} (${line + 1},${character + 1})`; | |
message += ': ' + ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); | |
if (!(diagnostic.file.fileName in files)) { | |
files[diagnostic.file.fileName] = []; | |
files[diagnostic.file.fileName]._line = line + 1; | |
files[diagnostic.file.fileName]._character = character + 1; | |
} | |
files[diagnostic.file.fileName].push(message); | |
} else { | |
message += ': ' + ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); | |
generalErrors.push(message); | |
} | |
}); | |
if (generalErrors.length) { | |
console.error(generalErrors.join('\n')); | |
} | |
const filesWithErrors = []; | |
Object.keys(files).forEach(fileName => { | |
filesWithErrors.push({ | |
name: fileName, | |
errors: files[fileName], | |
line: files[fileName]._line, | |
character: files[fileName]._character, | |
amountOfErrors: files[fileName].length, | |
}); | |
}); | |
filesWithErrors.sort((a, b) => { | |
return b.amountOfErrors - a.amountOfErrors; | |
}); | |
console.warn('-----'); | |
console.warn('Top 5 files with errors:'); | |
console.warn('-----'); | |
console.warn( | |
filesWithErrors | |
.slice(0, 5) | |
.map(el => `${el.amountOfErrors} .${el.name.split('frontend').pop()}:${el.line}:${el.character}`) | |
.join('\n'), | |
); | |
console.warn('-----'); | |
console.warn('Easy to fix errors:'); | |
console.warn('-----'); | |
console.warn( | |
filesWithErrors | |
.slice(-5) | |
.map(el => `${el.amountOfErrors} .${el.name.split('frontend').pop()}:${el.line}:${el.character}`) | |
.join('\n'), | |
); | |
console.warn('-----'); | |
const totalErrors = filesWithErrors.reduce((acc, el) => { | |
return acc + el.amountOfErrors; | |
}, 0); | |
console.warn('Total Errors: ' + totalErrors + ', total files with errors: ' + filesWithErrors.length); | |
console.warn('-----'); | |
return { | |
totalErrors, | |
filesWithErrors: filesWithErrors.length, | |
}; | |
} | |
function readConfigFile(configFileName) { | |
// Read config file | |
const configFileText = fs.readFileSync(configFileName).toString(); | |
// Parse JSON, after removing comments. Just fancier JSON.parse | |
const result = ts.parseConfigFileTextToJson(configFileName, configFileText); | |
const configObject = result.config; | |
if (!configObject) { | |
reportDiagnostics([result.error]); | |
process.exit(1); | |
} | |
// Extract config information | |
const configParseResult = ts.parseJsonConfigFileContent(configObject, ts.sys, path.dirname(configFileName)); | |
if (configParseResult.errors.length > 0) { | |
reportDiagnostics(configParseResult.errors); | |
process.exit(1); | |
} | |
return configParseResult; | |
} | |
function compile(configFileName) { | |
// Extract configuration from config file | |
let config = readConfigFile(configFileName); | |
// Compile | |
let program = ts.createProgram(config.fileNames, config.options); | |
let emitResult = program.emit(); | |
// Report errors | |
const { totalErrors, filesWithErrors } = reportDiagnostics( | |
ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics), | |
); | |
if (totalErrors > MAX_ERRORS) { | |
console.error(`Total amount of errors (${totalErrors}) is bigger than ${MAX_ERRORS}`); | |
process.exit(1); | |
} else if (filesWithErrors > MAX_FILES_WITH_ERRORS) { | |
console.error( | |
`Acceptable amount of files with errors (${filesWithErrors}) is bigger than ${MAX_FILES_WITH_ERRORS}`, | |
); | |
process.exit(1); | |
} else { | |
console.warn('All fine at the moment, amount of errors within range'); | |
process.exit(0); | |
} | |
} | |
compile('jsconfig.json'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment