Skip to content

Commit

Permalink
feat(tsfmt): using Language Service API instead of Old Compiler API
Browse files Browse the repository at this point in the history
  • Loading branch information
vvakame committed Aug 22, 2017
1 parent 74f7eb9 commit 1520cf8
Showing 1 changed file with 29 additions and 39 deletions.
68 changes: 29 additions & 39 deletions lib/formatter.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,37 @@
import * as ts from "typescript";
import { createDefaultFormatCodeSettings } from "./utils";

// from https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#pretty-printer-using-the-ls-formatter

// Note: this uses ts.formatting which is part of the typescript 1.4 package but is not currently
// exposed in the public typescript.d.ts. The typings should be exposed in the next release.
export default function format(fileName: string, text: string, options = createDefaultFormatCodeSettings()) {

// Parse the source text
let sourceFile = ts.createSourceFile(fileName, text, ts.ScriptTarget.Latest, true);

// Get the formatting edits on the input sources
let edits = (ts as any).formatting.formatDocument(sourceFile, getRuleProvider(options), options);

// Apply the edits on the input code
return applyEdits(text, edits);
import { createDefaultFormatCodeSettings } from "./utils";

function getRuleProvider(settings: ts.FormatCodeSettings) {
// Share this between multiple formatters using the same options.
// This represents the bulk of the space the formatter uses.
let ruleProvider = new (ts as any).formatting.RulesProvider();
ruleProvider.ensureUpToDate(settings);
return ruleProvider;
class LanguageServiceHost implements ts.LanguageServiceHost {
files: { [fileName: string]: ts.IScriptSnapshot; } = {};
addFile(fileName: string, text: string) {
this.files[fileName] = ts.ScriptSnapshot.fromString(text);
}

function applyEdits(text: string, edits: ts.TextChange[]): string {
// Apply edits in reverse on the existing text
let result = text;
// for ts.LanguageServiceHost

// An issue with `ts.formatting.formatDocument` is that it does
// not always give the edits array in ascending order of change start
// point. This can result that we add or remove some character in
// the begining of the document, making the all the other edits
// offsets invalid.
getCompilationSettings = () => ts.getDefaultCompilerOptions();
getScriptFileNames = () => Object.keys(this.files);
getScriptVersion = (_fileName: string) => "1";
getScriptSnapshot = (fileName: string) => this.files[fileName];
getCurrentDirectory = () => process.cwd();
getDefaultLibFileName = (_options: ts.CompilerOptions) => "lib";
}

// We resolve this by sorting edits by ascending start point
edits.sort((a, b) => a.span.start - b.span.start);
for (let i = edits.length - 1; i >= 0; i--) {
let change = edits[i];
let head = result.slice(0, change.span.start);
let tail = result.slice(change.span.start + change.span.length);
result = head + change.newText + tail;
}
return result;
}
export default function format(fileName: string, text: string, options = createDefaultFormatCodeSettings()) {
const host = new LanguageServiceHost();
host.addFile(fileName, text);

const languageService = ts.createLanguageService(host, ts.createDocumentRegistry());
const edits = languageService.getFormattingEditsForDocument(fileName, options);
edits
.sort((a, b) => a.span.start - b.span.start)
.reverse()
.forEach(edit => {
const head = text.slice(0, edit.span.start);
const tail = text.slice(edit.span.start + edit.span.length);
text = `${head}${edit.newText}${tail}`;
});

return text;
}

0 comments on commit 1520cf8

Please sign in to comment.