Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TS Server #2041

Merged
merged 46 commits into from
Feb 19, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
acd4914
Rename the main node package filename to match the package name
mhegazy Feb 1, 2015
e4128af
Merge branch 'master' into TSServer
mhegazy Feb 10, 2015
9735b74
Add support for stat and modified time on sys
mhegazy Feb 12, 2015
27a9084
Add indexer on the Formatting options interface
mhegazy Feb 12, 2015
17f19b2
Initial checkin for server code
mhegazy Feb 12, 2015
7b28f20
Wire the build for the server code
mhegazy Feb 12, 2015
abec4f9
Wire tests to use the new server
mhegazy Feb 12, 2015
54f3250
Add fomratting tests
mhegazy Feb 12, 2015
0963644
Add type annotations
mhegazy Feb 12, 2015
ee3ee05
wire package.json command for the server
mhegazy Feb 12, 2015
07d37fa
Simplify host logic in client
mhegazy Feb 12, 2015
6e94f39
Remove redundant type definitions
mhegazy Feb 12, 2015
4a44b74
Supportt abbreviation
mhegazy Feb 12, 2015
c987ab9
Wire navto tests
mhegazy Feb 12, 2015
3e86e55
Use commmandNames module
mhegazy Feb 12, 2015
c0b1254
Support brace matching
mhegazy Feb 12, 2015
93aa3f1
Add test for format on key
mhegazy Feb 12, 2015
99373db
Add test for goto def
mhegazy Feb 13, 2015
a0b557e
Recover from git corruption
mhegazy Feb 14, 2015
dfd8a06
Always default to using JSON and do not format it
mhegazy Feb 14, 2015
b175045
use ts.getDefaultLibFileName to get the default library file name
mhegazy Feb 15, 2015
ce828d0
Get details for member completions as well as completions matching pr…
mhegazy Feb 15, 2015
89267bc
Move fileWatching logic to the server to allow for testing on non-nod…
mhegazy Feb 15, 2015
d396ddf
Add test for completions
mhegazy Feb 15, 2015
9867e06
Add a new definition test
mhegazy Feb 15, 2015
11e2460
Add test for find references
mhegazy Feb 15, 2015
178e8f7
Add test for quickInfo
mhegazy Feb 15, 2015
40d3cb7
Add test for rename
mhegazy Feb 15, 2015
2a02655
Add navbar test
mhegazy Feb 16, 2015
50ca35a
Make method names inline with matching LS function names
mhegazy Feb 16, 2015
8944df1
use EncodedFile everywhere in responses
mhegazy Feb 16, 2015
76c7fdf
Add test for completionEntryDetails
mhegazy Feb 16, 2015
d9d2e99
Remove debugging statemetns
mhegazy Feb 16, 2015
f5c1bfb
renmae protodef.d.ts to protocol.d.ts and protocol.ts to session.ts
mhegazy Feb 16, 2015
d081c9c
rename output file to tsserver.js
mhegazy Feb 16, 2015
ca34838
Remove unused code
mhegazy Feb 16, 2015
8a9ac8d
Change ServerProtocol module to ts.server.protocol
mhegazy Feb 16, 2015
bdd0bf3
Comment formatting
mhegazy Feb 16, 2015
bbcdb61
remove unused cancellationToken class
mhegazy Feb 16, 2015
54e6756
Remove unused code and only expose needed types/classes
mhegazy Feb 16, 2015
32e2f4d
Accept APISamples baselines
mhegazy Feb 16, 2015
d2712dd
Removed file mapping compression technique due to brittleness of
Feb 17, 2015
cadd57c
Change rename response to return the rename info + nested location
Feb 17, 2015
3868fb5
Removed deleteLen from change request; added endLine, endCol that mark
Feb 18, 2015
4b59083
Split completions req/response pair into two messages "completions" and
Feb 18, 2015
d364f61
Style fixes.
Feb 19, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions Jakefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var child_process = require("child_process");
// Variables
var compilerDirectory = "src/compiler/";
var servicesDirectory = "src/services/";
var serverDirectory = "src/server/";
var harnessDirectory = "src/harness/";
var libraryDirectory = "src/lib/";
var scriptsDirectory = "scripts/";
Expand Down Expand Up @@ -90,6 +91,16 @@ var servicesSources = [
return path.join(servicesDirectory, f);
}));

var serverSources = [
"node.d.ts",
"editorServices.ts",
"protocol.d.ts",
"session.ts",
"server.ts"
].map(function (f) {
return path.join(serverDirectory, f);
});

var definitionsRoots = [
"compiler/types.d.ts",
"compiler/scanner.d.ts",
Expand Down Expand Up @@ -130,6 +141,13 @@ var harnessSources = [
"services/preProcessFile.ts"
].map(function (f) {
return path.join(unittestsDirectory, f);
})).concat([
"protocol.d.ts",
"session.ts",
"client.ts",
"editorServices.ts",
].map(function (f) {
return path.join(serverDirectory, f);
}));

var librarySourceMap = [
Expand Down Expand Up @@ -327,6 +345,7 @@ var tscFile = path.join(builtLocalDirectory, compilerFilename);
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false);

var servicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
var nodePackageFile = path.join(builtLocalDirectory, "typescript.js");
compileFile(servicesFile, servicesSources,[builtLocalDirectory, copyright].concat(servicesSources),
/*prefixes*/ [copyright],
/*useBuiltCompiler*/ true,
Expand All @@ -336,7 +355,10 @@ compileFile(servicesFile, servicesSources,[builtLocalDirectory, copyright].conca
/*preserveConstEnums*/ true,
/*keepComments*/ false,
/*noResolve*/ false,
/*stripInternal*/ false);
/*stripInternal*/ false,
/*callback*/ function () {
jake.cpR(servicesFile, nodePackageFile, {silent: true});
});

var nodeDefinitionsFile = path.join(builtLocalDirectory, "typescript.d.ts");
var standaloneDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts");
Expand Down Expand Up @@ -378,9 +400,12 @@ compileFile(nodeDefinitionsFile, servicesSources,[builtLocalDirectory, copyright
jake.rmRf(tempDirPath, {silent: true});
});

var serverFile = path.join(builtLocalDirectory, "tsserver.js");
compileFile(serverFile, serverSources,[builtLocalDirectory, copyright].concat(serverSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true);

// Local target to build the compiler and services
desc("Builds the full compiler and services");
task("local", ["generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile]);
task("local", ["generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile]);

// Local target to build only tsc.js
desc("Builds only the compiler");
Expand Down Expand Up @@ -435,7 +460,7 @@ task("generate-spec", [specMd])
// Makes a new LKG. This target does not build anything, but errors if not all the outputs are present in the built/local directory
desc("Makes a new LKG out of the built js files");
task("LKG", ["clean", "release", "local"].concat(libraryTargets), function() {
var expectedFiles = [tscFile, servicesFile, nodeDefinitionsFile, standaloneDefinitionsFile, internalNodeDefinitionsFile, internalStandaloneDefinitionsFile].concat(libraryTargets);
var expectedFiles = [tscFile, servicesFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, internalNodeDefinitionsFile, internalStandaloneDefinitionsFile].concat(libraryTargets);
var missingFiles = expectedFiles.filter(function (f) {
return !fs.existsSync(f);
});
Expand Down
2 changes: 2 additions & 0 deletions bin/tsserver
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
require('./tsserver.js')
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@
"url": "https://github.com/Microsoft/TypeScript.git"
},
"preferGlobal": true,
"main": "./bin/typescriptServices.js",
"main": "./bin/typescript.js",
"bin": {
"tsc": "./bin/tsc"
"tsc": "./bin/tsc",
"tsserver": "./bin/tsserver"
},
"engines": {
"node": ">=0.8.0"
Expand Down
7 changes: 6 additions & 1 deletion src/harness/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ module FourSlash {
return new Harness.LanguageService.NativeLanugageServiceAdapter(cancellationToken, compilationOptions);
case FourSlashTestType.Shims:
return new Harness.LanguageService.ShimLanugageServiceAdapter(cancellationToken, compilationOptions);
case FourSlashTestType.Server:
return new Harness.LanguageService.ServerLanugageServiceAdapter(cancellationToken, compilationOptions);
default:
throw new Error("Unknown FourSlash test type: ");
}
Expand Down Expand Up @@ -418,6 +420,9 @@ module FourSlash {
this.activeFile = fileToOpen;
var fileName = fileToOpen.fileName.replace(Harness.IO.directoryName(fileToOpen.fileName), '').substr(1);
this.scenarioActions.push('<OpenFile FileName="" SrcFileId="' + fileName + '" FileId="' + fileName + '" />');

// Let the host know that this file is now open
this.languageServiceAdapterHost.openFile(fileToOpen.fileName);
}

public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, negative: boolean) {
Expand Down Expand Up @@ -1927,7 +1932,7 @@ module FourSlash {
}

var missingItem = { name: name, kind: kind };
this.raiseError('verifyGetScriptLexicalStructureListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')');
this.raiseError('verifyGetScriptLexicalStructureListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items, null, " ") + ')');
}

private navigationBarItemsContains(items: ts.NavigationBarItem[], name: string, kind: string) {
Expand Down
7 changes: 6 additions & 1 deletion src/harness/fourslashRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

const enum FourSlashTestType {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It woudl be great if you documented. Explain that fourslash always tests the LS api. And, we can take advantage of that to test the shim and server layers by wrapping them so tehy expose the LS api. etc. etc.

Native,
Shims
Shims,
Server
}

class FourSlashRunner extends RunnerBase {
Expand All @@ -22,6 +23,10 @@ class FourSlashRunner extends RunnerBase {
this.basePath = 'tests/cases/fourslash/shims';
this.testSuiteName = 'fourslash-shims';
break;
case FourSlashTestType.Server:
this.basePath = 'tests/cases/fourslash/server';
this.testSuiteName = 'fourslash-server';
break;
}
}

Expand Down
7 changes: 4 additions & 3 deletions src/harness/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@

/// <reference path='..\services\services.ts' />
/// <reference path='..\services\shims.ts' />
/// <reference path='..\server\session.ts' />
/// <reference path='..\server\client.ts' />
/// <reference path='..\server\node.d.ts' />
/// <reference path='external\mocha.d.ts'/>
/// <reference path='external\chai.d.ts'/>
/// <reference path='sourceMapRecorder.ts'/>
/// <reference path='runnerbase.ts'/>

declare var require: any;
declare var process: any;
var Buffer = require('buffer').Buffer;
var Buffer: BufferConstructor = require('buffer').Buffer;

// this will work in the browser via browserify
var _chai: typeof chai = require('chai');
Expand Down
178 changes: 161 additions & 17 deletions src/harness/harnessLanguageService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference path='..\services\services.ts' />
/// <reference path='..\services\shims.ts' />
/// <reference path='..\server\client.ts' />
/// <reference path='harness.ts' />

module Harness.LanguageService {
Expand All @@ -23,18 +24,18 @@ module Harness.LanguageService {
this.version++;
}

public editContent(minChar: number, limChar: number, newText: string): void {
public editContent(start: number, end: number, newText: string): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to stop doing end.

// Apply edits
var prefix = this.content.substring(0, minChar);
var prefix = this.content.substring(0, start);
var middle = newText;
var suffix = this.content.substring(limChar);
var suffix = this.content.substring(end);
this.setContent(prefix + middle + suffix);

// Store edit range + new length of script
this.editRanges.push({
length: this.content.length,
textChangeRange: ts.createTextChangeRange(
ts.createTextSpanFromBounds(minChar, limChar), newText.length)
ts.createTextSpanFromBounds(start, end), newText.length)
});

// Update version #
Expand Down Expand Up @@ -145,24 +146,17 @@ module Harness.LanguageService {
this.fileNameToScript[fileName] = new ScriptInfo(fileName, content);
}

public updateScript(fileName: string, content: string) {
public editScript(fileName: string, start: number, end: number, newText: string) {
var script = this.getScriptInfo(fileName);
if (script !== null) {
script.updateContent(content);
script.editContent(start, end, newText);
return;
}

this.addScript(fileName, content);
throw new Error("No script with name '" + fileName + "'");
}

public editScript(fileName: string, minChar: number, limChar: number, newText: string) {
var script = this.getScriptInfo(fileName);
if (script !== null) {
script.editContent(minChar, limChar, newText);
return;
}

throw new Error("No script with name '" + fileName + "'");
public openFile(fileName: string): void {
}

/**
Expand Down Expand Up @@ -236,8 +230,7 @@ module Harness.LanguageService {
getFilenames(): string[] { return this.nativeHost.getFilenames(); }
getScriptInfo(fileName: string): ScriptInfo { return this.nativeHost.getScriptInfo(fileName); }
addScript(fileName: string, content: string): void { this.nativeHost.addScript(fileName, content); }
updateScript(fileName: string, content: string): void { return this.nativeHost.updateScript(fileName, content); }
editScript(fileName: string, minChar: number, limChar: number, newText: string): void { this.nativeHost.editScript(fileName, minChar, limChar, newText); }
editScript(fileName: string, start: number, end: number, newText: string): void { this.nativeHost.editScript(fileName, start, end, newText); }
lineColToPosition(fileName: string, line: number, col: number): number { return this.nativeHost.lineColToPosition(fileName, line, col); }
positionToZeroBasedLineCol(fileName: string, position: number): ts.LineAndCharacter { return this.nativeHost.positionToZeroBasedLineCol(fileName, position); }

Expand Down Expand Up @@ -442,5 +435,156 @@ module Harness.LanguageService {
return convertResult;
}
}

// Server adapter
class SessionClientHost extends NativeLanguageServiceHost implements ts.server.SessionClientHost {
private client: ts.server.SessionClient;

constructor(cancellationToken: ts.CancellationToken, settings: ts.CompilerOptions) {
super(cancellationToken, settings);
}

onMessage(message: string): void {

}

writeMessage(message: string): void {

}

setClient(client: ts.server.SessionClient) {
this.client = client;
}

openFile(fileName: string): void {
super.openFile(fileName);
this.client.openFile(fileName);
}

editScript(fileName: string, start: number, end: number, newText: string) {
super.editScript(fileName, start, end, newText);
this.client.changeFile(fileName, start, end, newText);
}
}

class SessionServerHost implements ts.server.ServerHost, ts.server.Logger {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd really like to see all classes documented to explain what purpose they serve.

args: string[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fields should be private.

newLine: string;
useCaseSensitiveFileNames: boolean = false;

constructor(private host: NativeLanguageServiceHost) {
this.newLine = this.host.getNewLine();
}

onMessage(message: string): void {

}

writeMessage(message: string): void {
}

write(message: string): void {
this.writeMessage(message);
}

readFile(fileName: string): string {
if (fileName.indexOf(Harness.Compiler.defaultLibFileName) >= 0) {
fileName = Harness.Compiler.defaultLibFileName;
}

var snapshot = this.host.getScriptSnapshot(fileName);
return snapshot && snapshot.getText(0, snapshot.getLength());
}

writeFile(name: string, text: string, writeByteOrderMark: boolean): void {
}

resolvePath(path: string): string {
return path;
}

fileExists(path: string): boolean {
return !!this.host.getScriptSnapshot(path);
}

directoryExists(path: string): boolean {
return false;
}

getExecutingFilePath(): string {
return "";
}

exit(exitCode: number): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this not also throw?

}

createDirectory(directoryName: string): void {
throw new Error("Not Implemented Yet.");
}

getCurrentDirectory(): string {
return this.host.getCurrentDirectory();
}

readDirectory(path: string, extension?: string): string[] {
throw new Error("Not implemented Yet.");
}

watchFile(fileName: string, callback: (fileName: string) => void): ts.FileWatcher {
return { close() { } };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this on a new line. Also, maybe this should throw.

}

close(): void {
}

info(message: string): void {
return this.host.log(message);
}

msg(message: string) {
return this.host.log(message);
}

endGroup(): void {
}

perftrc(message: string): void {
return this.host.log(message);
}

startGroup(): void {
}
}

export class ServerLanugageServiceAdapter implements LanguageServiceAdapter {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe LanguageServiceServerAdapter, but I wouldn't really know because I don't know what this is doing.

private host: SessionClientHost;
private client: ts.server.SessionClient;
constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) {
// This is the main host that tests use to direct tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what this comment means.

var clientHost = new SessionClientHost(cancellationToken, options);
var client = new ts.server.SessionClient(clientHost);

// This host is just a proxy for the clientHost, it uses the client
// host to answer server queries about files on disk
var serverHost = new SessionServerHost(clientHost);
var server = new ts.server.Session(serverHost, serverHost);

// Fake the connection between the client and the server
serverHost.writeMessage = client.onMessage.bind(client);
clientHost.writeMessage = server.onMessage.bind(server);

// Wire the client to the host to get notifications when a file is open
// or edited.
clientHost.setClient(client);

// Set the properties
this.client = client;
this.host = clientHost;
}
getHost() { return this.host; }
getLanguageService(): ts.LanguageService { return this.client; }
getClassifier(): ts.Classifier { throw new Error("getClassifier is not available using the server interface."); }
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { throw new Error("getPreProcessedFileInfo is not available using the server interface."); }
}
}

Loading