The majority of this file is devoted to a class called the ChangeTracker
. This class is nearly always
created via ChangeTracker.with
where you would give it a context object.
Here is an example context object:
{
cancellationToken:CancellationTokenObject {cancellationToken: TestCancellationToken}
errorCode:2304
formatContext:Object {options: Object, getRule: }
host:NativeLanguageServiceHost {cancellationToken: TestCancellationToken, settings: Object, sys: System, …}
preferences:Object {}
program:Object {getRootFileNames: , getSourceFile: , getSourceFileByPath: , …}
sourceFile:SourceFileObject {pos: 0, end: 7, flags: 65536, …}
span:Object {start: 0, length: 6}
}
You only really see ChangeTrack
in use within the codefixes and refactors given that the other case where
TypeScript emits files is a single operation of emission.
The change tracker keeps track of individual changes to be applied to a file. There are currently four main
APIs that it works with:
type Change = ReplaceWithSingleNode | ReplaceWithMultipleNodes | RemoveNode | ChangeText;
The ChangeTrack
class is then used to provide high level API to describe the sort of changes you might want to
make, which eventually fall into one of the four categories above.
The end result of using a ChangeTrack
object is an array of FileTextChanges
objects. The ChangeTrack.with
function lets you work with a tracker instance elsewhere and passes back the ChangeTrack
objects.
The core work in generating changes occurs in:
Going from an AST node to text is done by creating a printer
in getNonformattedText
. The printer
returns an unformatted node, which is then ran through [a formatter][./formatting.md] and the raw string
substitution is done in [applyChanges
][9].
Changes look like this:
[{ fileName: "/b.js", textChanges: [{ span: { start: 0, length: 0 }, newText: "// @ts-ignore\n" }] }];
newFileChanges
handles passing the set of