|
1 | 1 | import * as ts from "typescript";
|
2 |
| -import { createDefaultFormatCodeSettings } from "./utils"; |
3 |
| - |
4 |
| -// from https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#pretty-printer-using-the-ls-formatter |
5 |
| - |
6 |
| -// Note: this uses ts.formatting which is part of the typescript 1.4 package but is not currently |
7 |
| -// exposed in the public typescript.d.ts. The typings should be exposed in the next release. |
8 |
| -export default function format(fileName: string, text: string, options = createDefaultFormatCodeSettings()) { |
9 |
| - |
10 |
| - // Parse the source text |
11 |
| - let sourceFile = ts.createSourceFile(fileName, text, ts.ScriptTarget.Latest, true); |
12 | 2 |
|
13 |
| - // Get the formatting edits on the input sources |
14 |
| - let edits = (ts as any).formatting.formatDocument(sourceFile, getRuleProvider(options), options); |
15 |
| - |
16 |
| - // Apply the edits on the input code |
17 |
| - return applyEdits(text, edits); |
| 3 | +import { createDefaultFormatCodeSettings } from "./utils"; |
18 | 4 |
|
19 |
| - function getRuleProvider(settings: ts.FormatCodeSettings) { |
20 |
| - // Share this between multiple formatters using the same options. |
21 |
| - // This represents the bulk of the space the formatter uses. |
22 |
| - let ruleProvider = new (ts as any).formatting.RulesProvider(); |
23 |
| - ruleProvider.ensureUpToDate(settings); |
24 |
| - return ruleProvider; |
| 5 | +class LanguageServiceHost implements ts.LanguageServiceHost { |
| 6 | + files: { [fileName: string]: ts.IScriptSnapshot; } = {}; |
| 7 | + addFile(fileName: string, text: string) { |
| 8 | + this.files[fileName] = ts.ScriptSnapshot.fromString(text); |
25 | 9 | }
|
26 | 10 |
|
27 |
| - function applyEdits(text: string, edits: ts.TextChange[]): string { |
28 |
| - // Apply edits in reverse on the existing text |
29 |
| - let result = text; |
| 11 | + // for ts.LanguageServiceHost |
30 | 12 |
|
31 |
| - // An issue with `ts.formatting.formatDocument` is that it does |
32 |
| - // not always give the edits array in ascending order of change start |
33 |
| - // point. This can result that we add or remove some character in |
34 |
| - // the begining of the document, making the all the other edits |
35 |
| - // offsets invalid. |
| 13 | + getCompilationSettings = () => ts.getDefaultCompilerOptions(); |
| 14 | + getScriptFileNames = () => Object.keys(this.files); |
| 15 | + getScriptVersion = (_fileName: string) => "1"; |
| 16 | + getScriptSnapshot = (fileName: string) => this.files[fileName]; |
| 17 | + getCurrentDirectory = () => process.cwd(); |
| 18 | + getDefaultLibFileName = (_options: ts.CompilerOptions) => "lib"; |
| 19 | +} |
36 | 20 |
|
37 |
| - // We resolve this by sorting edits by ascending start point |
38 |
| - edits.sort((a, b) => a.span.start - b.span.start); |
39 |
| - for (let i = edits.length - 1; i >= 0; i--) { |
40 |
| - let change = edits[i]; |
41 |
| - let head = result.slice(0, change.span.start); |
42 |
| - let tail = result.slice(change.span.start + change.span.length); |
43 |
| - result = head + change.newText + tail; |
44 |
| - } |
45 |
| - return result; |
46 |
| - } |
| 21 | +export default function format(fileName: string, text: string, options = createDefaultFormatCodeSettings()) { |
| 22 | + const host = new LanguageServiceHost(); |
| 23 | + host.addFile(fileName, text); |
| 24 | + |
| 25 | + const languageService = ts.createLanguageService(host, ts.createDocumentRegistry()); |
| 26 | + const edits = languageService.getFormattingEditsForDocument(fileName, options); |
| 27 | + edits |
| 28 | + .sort((a, b) => a.span.start - b.span.start) |
| 29 | + .reverse() |
| 30 | + .forEach(edit => { |
| 31 | + const head = text.slice(0, edit.span.start); |
| 32 | + const tail = text.slice(edit.span.start + edit.span.length); |
| 33 | + text = `${head}${edit.newText}${tail}`; |
| 34 | + }); |
| 35 | + |
| 36 | + return text; |
47 | 37 | }
|
0 commit comments