Dramatic simplifications from using TypeScript-provided machinery which appeared sometime between when this code was originally written and now
This commit is contained in:
parent
958cbae171
commit
14702c66b9
|
@ -50,35 +50,17 @@ export function main(argv: string[]) {
|
||||||
.argv;
|
.argv;
|
||||||
|
|
||||||
if (options.watch) {
|
if (options.watch) {
|
||||||
function run() {
|
if (options.clear) clearScreen(options);
|
||||||
const toWatch = new ToWatch();
|
runBuildOnce(options);
|
||||||
console.log((options.clear ? '\x1b[2J\x1b[H' : '\n') + (new Date()) + ': Running build');
|
|
||||||
runBuildOnce(options, toWatch);
|
|
||||||
const watchers: Array<ts.FileWatcher> = [];
|
|
||||||
let rebuildTriggered = false;
|
|
||||||
const cb = () => {
|
|
||||||
if (!rebuildTriggered) {
|
|
||||||
rebuildTriggered = true;
|
|
||||||
watchers.forEach(w => w.close());
|
|
||||||
queueMicrotask(run);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
toWatch.files.forEach(f => {
|
|
||||||
const w = ts.sys.watchFile?.(f, cb);
|
|
||||||
if (w) watchers.push(w);
|
|
||||||
});
|
|
||||||
toWatch.directories.forEach(d => {
|
|
||||||
const w = ts.sys.watchDirectory?.(d, cb, true);
|
|
||||||
if (w) watchers.push(w);
|
|
||||||
});
|
|
||||||
console.log('\n' + (new Date()) + ': Waiting for changes to input files');
|
|
||||||
}
|
|
||||||
run();
|
|
||||||
} else {
|
} else {
|
||||||
ts.sys.exit(runBuildOnce(options) ? 0 : 1);
|
ts.sys.exit(runBuildOnce(options) ? 0 : 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearScreen(options: CommandLineArguments) {
|
||||||
|
process.stdout.write(options.clear ? '\x1b[2J\x1b[H' : '\n');
|
||||||
|
}
|
||||||
|
|
||||||
function finalSlash(s: string): string {
|
function finalSlash(s: string): string {
|
||||||
if (s[s.length - 1] !== '/') s = s + '/';
|
if (s[s.length - 1] !== '/') s = s + '/';
|
||||||
return s;
|
return s;
|
||||||
|
@ -90,15 +72,7 @@ const formatDiagnosticsHost: ts.FormatDiagnosticsHost = {
|
||||||
getCanonicalFileName: f => f,
|
getCanonicalFileName: f => f,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ToWatch {
|
function runBuildOnce(options: CommandLineArguments): boolean {
|
||||||
files: Set<string> = new Set();
|
|
||||||
directories: Set<string> = new Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
function runBuildOnce(options: CommandLineArguments, toWatch = new ToWatch()) {
|
|
||||||
let problemCount = 0;
|
|
||||||
let hasErrors = false;
|
|
||||||
|
|
||||||
const syndicateInfo: Map<string, SyndicateInfo> = new Map();
|
const syndicateInfo: Map<string, SyndicateInfo> = new Map();
|
||||||
|
|
||||||
function createProgram(commandLineOptions: CommandLineArguments): ts.CreateProgram<any>
|
function createProgram(commandLineOptions: CommandLineArguments): ts.CreateProgram<any>
|
||||||
|
@ -138,7 +112,6 @@ function runBuildOnce(options: CommandLineArguments, toWatch = new ToWatch()) {
|
||||||
languageVersion: ts.ScriptTarget,
|
languageVersion: ts.ScriptTarget,
|
||||||
onError?: ((message: string) => void),
|
onError?: ((message: string) => void),
|
||||||
shouldCreateNewSourceFile?: boolean): ts.SourceFile | undefined => {
|
shouldCreateNewSourceFile?: boolean): ts.SourceFile | undefined => {
|
||||||
toWatch.files.add(fileName);
|
|
||||||
if ((rootNames?.indexOf(fileName) ?? -1) !== -1) {
|
if ((rootNames?.indexOf(fileName) ?? -1) !== -1) {
|
||||||
try {
|
try {
|
||||||
const inputText = host.readFile(fileName);
|
const inputText = host.readFile(fileName);
|
||||||
|
@ -220,63 +193,56 @@ function runBuildOnce(options: CommandLineArguments, toWatch = new ToWatch()) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!syntheticSourceFiles.has(d.file.fileName)) {
|
if (!syntheticSourceFiles.has(d.file.fileName)) {
|
||||||
syntheticSourceFiles.set(
|
const sf = ts.createSourceFile(d.file.fileName,
|
||||||
d.file.fileName,
|
info.originalSource,
|
||||||
ts.createSourceFile(d.file.fileName,
|
info.languageVersion,
|
||||||
info.originalSource,
|
false,
|
||||||
info.languageVersion,
|
ts.ScriptKind.Unknown);
|
||||||
false,
|
(sf as any).resolvedPath = d.file.fileName;
|
||||||
ts.ScriptKind.Unknown));
|
syntheticSourceFiles.set(d.file.fileName, sf);
|
||||||
}
|
}
|
||||||
d.file = syntheticSourceFiles.get(d.file.fileName);
|
d.file = syntheticSourceFiles.get(d.file.fileName);
|
||||||
const p = info.targetToSourceMap.get(d.start)!;
|
|
||||||
d.start = p.firstItem.start.pos + p.offset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reportDiagnostic(d: ts.Diagnostic) {
|
function reportDiagnostic(d: ts.Diagnostic) {
|
||||||
if (d.category === ts.DiagnosticCategory.Error) problemCount++;
|
|
||||||
fixupDiagnostic(d);
|
fixupDiagnostic(d);
|
||||||
|
// Sneakily access ts.screenStartingMessageCodes, internally used to decide whether to
|
||||||
|
// clear the screen or not.
|
||||||
|
const shouldClear = ((ts as any).screenStartingMessageCodes ?? []).indexOf(d.code) !== -1;
|
||||||
|
if (shouldClear) clearScreen(options);
|
||||||
console.log(ts.formatDiagnosticsWithColorAndContext([d], formatDiagnosticsHost).trimEnd());
|
console.log(ts.formatDiagnosticsWithColorAndContext([d], formatDiagnosticsHost).trimEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
function reportErrorSummary(n: number) {
|
const getCustomTransformers = (_project: string) => ({ before: [fixSourceMap] });
|
||||||
if (n > 0) {
|
|
||||||
console.error(`\n - ${n} errors reported`);
|
const sbh = ts.createSolutionBuilderWithWatchHost(ts.sys,
|
||||||
hasErrors = true;
|
createProgram(options),
|
||||||
}
|
reportDiagnostic,
|
||||||
|
reportDiagnostic,
|
||||||
|
reportDiagnostic);
|
||||||
|
if (sbh.getCustomTransformers) {
|
||||||
|
console.warn('SolutionBuilderHost already has getCustomTransformers');
|
||||||
}
|
}
|
||||||
|
sbh.getCustomTransformers = getCustomTransformers;
|
||||||
|
|
||||||
const sbh = ts.createSolutionBuilderHost(ts.sys,
|
const sb = ts.createSolutionBuilderWithWatch(sbh, ['.'], {
|
||||||
createProgram(options),
|
|
||||||
reportDiagnostic,
|
|
||||||
reportDiagnostic,
|
|
||||||
reportErrorSummary);
|
|
||||||
|
|
||||||
const sb = ts.createSolutionBuilder(sbh, ['.'], {
|
|
||||||
verbose: options.verbose,
|
verbose: options.verbose,
|
||||||
});
|
});
|
||||||
|
|
||||||
let project = sb.getNextInvalidatedProject();
|
const exitStatus = sb.build(void 0, void 0, void 0, getCustomTransformers);
|
||||||
|
|
||||||
// Sneakily get into secret members of the ts.SolutionBuilder and
|
switch (exitStatus) {
|
||||||
// ts.ParsedCommandline objects to prime our set of watched
|
case ts.ExitStatus.Success:
|
||||||
// files/directories, in case all the projects are up-to-date and
|
case ts.ExitStatus.DiagnosticsPresent_OutputsGenerated:
|
||||||
// our createProgram function is never called.
|
return true;
|
||||||
//
|
|
||||||
(((sb as any).getAllParsedConfigs?.() ?? []) as Array<ts.ParsedCommandLine>).forEach(c => {
|
|
||||||
const f = (c.options as any).configFilePath;
|
|
||||||
if (f) toWatch.files.add(f);
|
|
||||||
c.fileNames.forEach(f => toWatch.files.add(f));
|
|
||||||
Object.keys(c.wildcardDirectories ?? {}).forEach(d => toWatch.directories.add(d));
|
|
||||||
});
|
|
||||||
|
|
||||||
while (project !== void 0) {
|
case ts.ExitStatus.DiagnosticsPresent_OutputsSkipped:
|
||||||
project.done(void 0, void 0, {
|
case ts.ExitStatus.InvalidProject_OutputsSkipped:
|
||||||
before: [fixSourceMap]
|
case ts.ExitStatus.ProjectReferenceCycle_OutputsSkipped:
|
||||||
});
|
return false;
|
||||||
project = sb.getNextInvalidatedProject();
|
|
||||||
|
default:
|
||||||
|
((_: never) => { throw new Error("Unexpected ts.ExitStatus: " + _) })(exitStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (problemCount === 0) && !hasErrors;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue