Skip to content

Instantly share code, notes, and snippets.

@mihailik
Last active June 1, 2020 13:08
TypeScript custom transformers with ts.createSolutionBuilderWithWatch
var ts = require('typescript');
var diagReport = ts.createBuilderStatusReporter(ts.sys, ts.sys.writeOutputIsTTY && ts.sys.writeOutputIsTTY());
var host = ts.createWatchCompilerHost(
[__filename],
{ allowJs: true, checkJs: true, outFile: __filename + '.out.js' },
ts.sys,
createAndPatchProgram,
void 0,
reportWatch);
var buildStart = Date.now();
ts.createWatchProgram(host);
function reportWatch(diag, newLine, options, errorCount) {
ts.sys.write(typeof errorCount === 'number' ?
'\x1b[90m ' + (((Date.now() - buildStart) / 1000) + 's ').slice(0, 10) + '\x1b[0m' :
'WATCH DIAG ');
diagReport(diag);
if (typeof errorCount !== 'number') buildStart = Date.now();
}
var prog;
function createAndPatchProgram() {
prog = ts.createEmitAndSemanticDiagnosticsBuilderProgram.apply(ts, arguments);
prog.__oldEmit = prog.emit;
prog.emit = overrideEmit;
return prog;
}
function overrideEmit(targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers) {
return this.__oldEmit(
targetSourceFile,
writeFile,
cancellationToken,
emitOnlyDtsFiles,
{ after: [transformInjectStatementNumbers] }
);
}
var checker;
/** @param {import('typescript').TransformationContext} context */
function transformInjectStatementNumbers(context) {
checker = prog.getProgram().getTypeChecker();
return transformFile;
function transformFile(sourceFile) {
return ts.updateSourceFileNode(
sourceFile,
sourceFile.statements.map(decorateStatementWithComplexityAndType));
}
}
function decorateStatementWithComplexityAndType(statement) {
var nodeCount = 0;
var type;
ts.forEachChild(statement, visitStatementChild);
return ts.addSyntheticLeadingComment(
statement, ts.SyntaxKind.SingleLineCommentTrivia,
' complexity: ' + nodeCount +
(!type ? '' : ' = ' + checker.typeToString(type)));
function visitStatementChild(child) {
nodeCount++;
if (!type) type = checker.getTypeAtLocation(child);
if (type.getFlags() === ts.TypeFlags.Any) type = null;
ts.forEachChild(child, visitStatementChild);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment