From ba4aad79dc751cca9faf4826fac8c53543b653c5 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Mon, 24 Jun 2019 15:42:56 -0700 Subject: [PATCH] Adds some docs for how a formatter works --- src/services/formatting/README.md | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/services/formatting/README.md diff --git a/src/services/formatting/README.md b/src/services/formatting/README.md new file mode 100644 index 00000000000..7e3bf6c46a9 --- /dev/null +++ b/src/services/formatting/README.md @@ -0,0 +1,43 @@ +# How does TypeScript formatting work? + +To format code you need to have a formatting context and a sourcefile. The formatting context contains +all user settings like tab size, newline character, etc. The sourcefile is self explanatory. + +The end result of formatting is represented by TextChange objects which hold the new string content, and +the text to replace it with. + +```ts +export interface TextChange { + span: TextSpan; // start, length + newText: string; +} +``` + +## Internals + +Most of the exposed APIs internally are `format*` and they all set up and configure `formatSpan` which could be considered the root call for formatting. Span in this case refers to the range of +the sourcefile which should be formatted. + +The formatSpan then uses a scanner (either with or without JSX support) which starts at the highest +node the covers the span of text and recurses down through the node's children. + +As it recurses, `processNode` is called on the children setting the indentation is decided and passed +through into each of that node's children. + +The meat of formatting decisions is made via `processPair`, the pair here being the current node and the previous node. `processPair` which mutates the formatting context to represent the current place in the scanner and requests a set of rules which can be applied to the items via `createRulesMap`. + +There are a lot of rules, which you can find in [rules.ts](./rules.ts) each one has a left and right reference to nodes or token ranges and note of what action should be applied by the formatter. + +### Where is this used? + +The formatter is used mainly from the language service for formatting with an editor, but [services/textChanges.ts](/src/services/textChanges.ts) also uses this formatter when emitting code for quick fixes. + +The formatter is not exported publicly, and so all usage comes through the language server. + +### Sample code + +```ts +const nonFormattedText = `[js source code]`; +const sourceFile = createSourceFile("any file name", nonFormattedText, ScriptTarget.ESNext, /*setParentNodes*/ true, ScriptKind.JS); +const changes = formatting.formatDocument(sourceFile, formatContext); +```