Merge pull request #8700 from Microsoft/Fix8692

Fix #8692: fix "tsserver as a library" (lssl) build target
This commit is contained in:
Mohamed Hegazy 2016-05-21 12:24:23 -07:00
commit b637d76b49
9 changed files with 168 additions and 148 deletions

View file

@ -160,7 +160,7 @@ var harnessSources = harnessCoreSources.concat([
"protocol.d.ts",
"session.ts",
"client.ts",
"editorServices.ts",
"editorServices.ts"
].map(function (f) {
return path.join(serverDirectory, f);
}));
@ -174,7 +174,7 @@ var es2015LibrarySources = [
"es2015.proxy.d.ts",
"es2015.reflect.d.ts",
"es2015.symbol.d.ts",
"es2015.symbol.wellknown.d.ts",
"es2015.symbol.wellknown.d.ts"
];
var es2015LibrarySourceMap = es2015LibrarySources.map(function(source) {
@ -183,25 +183,25 @@ var es2015LibrarySourceMap = es2015LibrarySources.map(function(source) {
var es2016LibrarySource = [ "es2016.array.include.d.ts" ];
var es2016LibrarySourceMap = es2016LibrarySource.map(function(source) {
var es2016LibrarySourceMap = es2016LibrarySource.map(function (source) {
return { target: "lib." + source, sources: ["header.d.ts", source] };
})
});
var es2017LibrarySource = ["es2017.object.d.ts"];
var es2017LibrarySourceMap = es2017LibrarySource.map(function(source) {
var es2017LibrarySourceMap = es2017LibrarySource.map(function (source) {
return { target: "lib." + source, sources: ["header.d.ts", source] };
})
});
var hostsLibrarySources = ["dom.generated.d.ts", "webworker.importscripts.d.ts", "scripthost.d.ts"]
var hostsLibrarySources = ["dom.generated.d.ts", "webworker.importscripts.d.ts", "scripthost.d.ts"];
var librarySourceMap = [
// Host library
{ target: "lib.dom.d.ts", sources: ["header.d.ts", "dom.generated.d.ts"], },
{ target: "lib.dom.iterable.d.ts", sources: ["header.d.ts", "dom.iterable.d.ts"], },
{ target: "lib.webworker.d.ts", sources: ["header.d.ts", "webworker.generated.d.ts"], },
{ target: "lib.scripthost.d.ts", sources: ["header.d.ts", "scripthost.d.ts"], },
{ target: "lib.dom.d.ts", sources: ["header.d.ts", "dom.generated.d.ts"] },
{ target: "lib.dom.iterable.d.ts", sources: ["header.d.ts", "dom.iterable.d.ts"] },
{ target: "lib.webworker.d.ts", sources: ["header.d.ts", "webworker.generated.d.ts"] },
{ target: "lib.scripthost.d.ts", sources: ["header.d.ts", "scripthost.d.ts"] },
// JavaScript library
{ target: "lib.es5.d.ts", sources: ["header.d.ts", "es5.d.ts"] },
{ target: "lib.es2015.d.ts", sources: ["header.d.ts", "es2015.d.ts"] },
@ -209,8 +209,8 @@ var librarySourceMap = [
{ target: "lib.es2017.d.ts", sources: ["header.d.ts", "es2017.d.ts"] },
// JavaScript + all host library
{ target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources), },
{ target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts"), },
{ target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources) },
{ target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }
].concat(es2015LibrarySourceMap, es2016LibrarySourceMap, es2017LibrarySourceMap);
var libraryTargets = librarySourceMap.map(function (f) {
@ -251,7 +251,7 @@ function concatenateFiles(destinationFile, sourceFiles) {
}
var useDebugMode = true;
var host = (process.env.TYPESCRIPT_HOST || process.env.host || "node");
var host = process.env.TYPESCRIPT_HOST || process.env.host || "node";
var compilerFilename = "tsc.js";
var LKGCompiler = path.join(LKGDirectory, compilerFilename);
var builtLocalCompiler = path.join(builtLocalDirectory, compilerFilename);
@ -300,7 +300,7 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
options += " --out " + outFile;
}
else {
options += " --module commonjs"
options += " --module commonjs";
}
if(opts.noResolve) {
@ -315,7 +315,7 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
}
if (opts.stripInternal) {
options += " --stripInternal"
options += " --stripInternal";
}
var cmd = host + " " + compilerPath + " " + options + " ";
@ -453,9 +453,9 @@ file(scriptsTsdJson);
task("tsd-scripts", [scriptsTsdJson], function () {
var cmd = "tsd --config " + scriptsTsdJson + " install";
console.log(cmd)
console.log(cmd);
exec(cmd);
}, { async: true })
}, { async: true });
var importDefinitelyTypedTestsDirectory = path.join(scriptsDirectory, "importDefinitelyTypedTests");
var importDefinitelyTypedTestsJs = path.join(importDefinitelyTypedTestsDirectory, "importDefinitelyTypedTests.js");
@ -525,9 +525,9 @@ compileFile(servicesFileInBrowserTest, servicesSources,[builtLocalDirectory, cop
var serverFile = path.join(builtLocalDirectory, "tsserver.js");
compileFile(serverFile, serverSources,[builtLocalDirectory, copyright].concat(serverSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true);
var lsslFile = path.join(builtLocalDirectory, "tslssl.js");
var tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js");
compileFile(
lsslFile,
tsserverLibraryFile,
languageServiceLibrarySources,
[builtLocalDirectory, copyright].concat(languageServiceLibrarySources),
/*prefixes*/ [copyright],
@ -536,7 +536,7 @@ compileFile(
// Local target to build the language service server library
desc("Builds language service server library");
task("lssl", [lsslFile]);
task("lssl", [tsserverLibraryFile]);
// Local target to build the compiler and services
desc("Builds the full compiler and services");
@ -595,8 +595,8 @@ 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, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile].concat(libraryTargets);
task("LKG", ["clean", "release", "local", "lssl"].concat(libraryTargets), function() {
var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile].concat(libraryTargets);
var missingFiles = expectedFiles.filter(function (f) {
return !fs.existsSync(f);
});
@ -622,7 +622,7 @@ directory(builtLocalDirectory);
var run = path.join(builtLocalDirectory, "run.js");
compileFile(run, harnessSources, [builtLocalDirectory, tscFile].concat(libraryTargets).concat(harnessSources), [], /*useBuiltCompiler:*/ true);
var internalTests = "internal/"
var internalTests = "internal/";
var localBaseline = "tests/baselines/local/";
var refBaseline = "tests/baselines/reference/";
@ -709,7 +709,7 @@ function runConsoleTests(defaultReporter, defaultSubsets) {
testTimeout = 100000;
}
colors = process.env.colors || process.env.color
colors = process.env.colors || process.env.color;
colors = colors ? ' --no-colors ' : ' --colors ';
reporter = process.env.reporter || process.env.r || defaultReporter;
var lintFlag = process.env.lint !== 'false';
@ -718,7 +718,7 @@ function runConsoleTests(defaultReporter, defaultSubsets) {
// default timeout is 2sec which really should be enough, but maybe we just need a small amount longer
var subsetRegexes;
if(defaultSubsets.length === 0) {
subsetRegexes = [tests]
subsetRegexes = [tests];
}
else {
var subsets = tests ? tests.split("|") : defaultSubsets;
@ -765,8 +765,8 @@ task("generate-code-coverage", ["tests", builtLocalDirectory], function () {
}, { async: true });
// Browser tests
var nodeServerOutFile = 'tests/webTestServer.js'
var nodeServerInFile = 'tests/webTestServer.ts'
var nodeServerOutFile = "tests/webTestServer.js";
var nodeServerInFile = "tests/webTestServer.ts";
compileFile(nodeServerOutFile, [nodeServerInFile], [builtLocalDirectory, tscFile], [], /*useBuiltCompiler:*/ true, { noOutFile: true });
desc("Runs browserify on run.js to produce a file suitable for running tests in the browser");
@ -778,7 +778,7 @@ task("browserify", ["tests", builtLocalDirectory, nodeServerOutFile], function()
desc("Runs the tests using the built run.js file like 'jake runtests'. Syntax is jake runtests-browser. Additional optional parameters tests=[regex], port=, browser=[chrome|IE]");
task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFileInBrowserTest], function() {
cleanTestDirs();
host = "node"
host = "node";
port = process.env.port || process.env.p || '8888';
browser = process.env.browser || process.env.b || "IE";
tests = process.env.test || process.env.tests || process.env.t;
@ -792,13 +792,13 @@ task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFi
}
tests = tests ? tests : '';
var cmd = host + " tests/webTestServer.js " + port + " " + browser + " " + tests
var cmd = host + " tests/webTestServer.js " + port + " " + browser + " " + tests;
console.log(cmd);
exec(cmd);
}, {async: true});
function getDiffTool() {
var program = process.env['DIFF']
var program = process.env['DIFF'];
if (!program) {
fail("Add the 'DIFF' environment variable to the path of the program you want to use.");
}
@ -827,11 +827,11 @@ task("tests-debug", ["setDebugMode", "tests"]);
// Makes the test results the new baseline
desc("Makes the most recent test results the new baseline, overwriting the old baseline");
task("baseline-accept", function(hardOrSoft) {
if (!hardOrSoft || hardOrSoft == "hard") {
if (!hardOrSoft || hardOrSoft === "hard") {
jake.rmRf(refBaseline);
fs.renameSync(localBaseline, refBaseline);
}
else if (hardOrSoft == "soft") {
else if (hardOrSoft === "soft") {
var files = jake.readdirR(localBaseline);
for (var i in files) {
jake.cpR(files[i], refBaseline);
@ -910,14 +910,14 @@ task("update-sublime", ["local", serverFile], function() {
});
var tslintRuleDir = "scripts/tslint";
var tslintRules = ([
var tslintRules = [
"nextLineRule",
"preferConstRule",
"booleanTriviaRule",
"typeOperatorSpacingRule",
"noInOperatorRule",
"noIncrementDecrementRule"
]);
];
var tslintRulesFiles = tslintRules.map(function(p) {
return path.join(tslintRuleDir, p + ".ts");
});
@ -942,7 +942,7 @@ function getLinterOptions() {
function lintFileContents(options, path, contents) {
var ll = new Linter(path, contents, options);
console.log("Linting '" + path + "'.")
console.log("Linting '" + path + "'.");
return ll.lint();
}

View file

@ -641,6 +641,14 @@ namespace Harness.LanguageService {
startGroup(): void {
}
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any {
return setTimeout(callback, ms, args);
}
clearTimeout(timeoutId: any): void {
clearTimeout(timeoutId);
}
}
export class ServerLanguageServiceAdapter implements LanguageServiceAdapter {

View file

@ -32,7 +32,7 @@ namespace ts.server {
children: ScriptInfo[] = []; // files referenced by this file
defaultProject: Project; // project to use by default for file
fileWatcher: FileWatcher;
formatCodeOptions = ts.clone(CompilerService.defaultFormatCodeOptions);
formatCodeOptions = ts.clone(CompilerService.getDefaultFormatCodeOptions(this.host));
path: Path;
scriptKind: ScriptKind;
@ -533,7 +533,7 @@ namespace ts.server {
// number becomes 0 for a watcher, then we should close it.
directoryWatchersRefCount: ts.Map<number> = {};
hostConfiguration: HostConfiguration;
timerForDetectingProjectFileListChanges: Map<NodeJS.Timer> = {};
timerForDetectingProjectFileListChanges: Map<any> = {};
constructor(public host: ServerHost, public psLogger: Logger, public eventHandler?: ProjectServiceEventHandler) {
// ts.disableIncrementalParsing = true;
@ -542,7 +542,7 @@ namespace ts.server {
addDefaultHostConfiguration() {
this.hostConfiguration = {
formatCodeOptions: ts.clone(CompilerService.defaultFormatCodeOptions),
formatCodeOptions: ts.clone(CompilerService.getDefaultFormatCodeOptions(this.host)),
hostInfo: "Unknown host"
};
}
@ -593,9 +593,9 @@ namespace ts.server {
startTimerForDetectingProjectFileListChanges(project: Project) {
if (this.timerForDetectingProjectFileListChanges[project.projectFilename]) {
clearTimeout(this.timerForDetectingProjectFileListChanges[project.projectFilename]);
this.host.clearTimeout(this.timerForDetectingProjectFileListChanges[project.projectFilename]);
}
this.timerForDetectingProjectFileListChanges[project.projectFilename] = setTimeout(
this.timerForDetectingProjectFileListChanges[project.projectFilename] = this.host.setTimeout(
() => this.handleProjectFileListChanges(project),
250
);
@ -1382,23 +1382,25 @@ namespace ts.server {
return ts.isExternalModule(sourceFile);
}
static defaultFormatCodeOptions: ts.FormatCodeOptions = {
IndentSize: 4,
TabSize: 4,
NewLineCharacter: ts.sys ? ts.sys.newLine : "\n",
ConvertTabsToSpaces: true,
IndentStyle: ts.IndentStyle.Smart,
InsertSpaceAfterCommaDelimiter: true,
InsertSpaceAfterSemicolonInForStatements: true,
InsertSpaceBeforeAndAfterBinaryOperators: true,
InsertSpaceAfterKeywordsInControlFlowStatements: true,
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
PlaceOpenBraceOnNewLineForFunctions: false,
PlaceOpenBraceOnNewLineForControlBlocks: false,
};
static getDefaultFormatCodeOptions(host: ServerHost): ts.FormatCodeOptions {
return ts.clone({
IndentSize: 4,
TabSize: 4,
NewLineCharacter: host.newLine || "\n",
ConvertTabsToSpaces: true,
IndentStyle: ts.IndentStyle.Smart,
InsertSpaceAfterCommaDelimiter: true,
InsertSpaceAfterSemicolonInForStatements: true,
InsertSpaceBeforeAndAfterBinaryOperators: true,
InsertSpaceAfterKeywordsInControlFlowStatements: true,
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
PlaceOpenBraceOnNewLineForFunctions: false,
PlaceOpenBraceOnNewLineForControlBlocks: false,
});
}
}
export interface LineCollection {

View file

@ -266,16 +266,21 @@ namespace ts.server {
}
}
const sys = <ServerHost>ts.sys;
// Override sys.write because fs.writeSync is not reliable on Node 4
ts.sys.write = (s: string) => writeMessage(s);
ts.sys.watchFile = (fileName, callback) => {
sys.write = (s: string) => writeMessage(s);
sys.watchFile = (fileName, callback) => {
const watchedFile = pollingWatchedFileSet.addFile(fileName, callback);
return {
close: () => pollingWatchedFileSet.removeFile(watchedFile)
};
};
const ioSession = new IOSession(ts.sys, logger);
sys.setTimeout = setTimeout;
sys.clearTimeout = clearTimeout;
const ioSession = new IOSession(sys, logger);
process.on("uncaughtException", function(err: Error) {
ioSession.logError(err, "unknown");
});

View file

@ -133,6 +133,8 @@ namespace ts.server {
}
export interface ServerHost extends ts.System {
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
clearTimeout(timeoutId: any): void;
}
export class Session {

View file

@ -370,7 +370,7 @@ namespace ts {
if (lookInPreviousChild) {
// actual start of the node is past the position - previous token should be at the end of previous child
let candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i);
return candidate && findRightmostToken(candidate)
return candidate && findRightmostToken(candidate);
}
else {
// candidate should be in this node
@ -490,8 +490,8 @@ namespace ts {
return forEach(commentRanges, jsDocPrefix);
function jsDocPrefix(c: CommentRange): boolean {
var text = sourceFile.text;
return text.length >= c.pos + 3 && text[c.pos] === '/' && text[c.pos + 1] === '*' && text[c.pos + 2] === '*';
const text = sourceFile.text;
return text.length >= c.pos + 3 && text[c.pos] === "/" && text[c.pos + 1] === "*" && text[c.pos + 2] === "*";
}
}
@ -546,7 +546,7 @@ namespace ts {
if (flags & NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier);
if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier);
return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none;
return result.length > 0 ? result.join(",") : ScriptElementKindModifier.none;
}
export function getTypeArgumentOrTypeParameterList(node: Node): NodeArray<Node> {
@ -629,7 +629,7 @@ namespace ts {
// [a,b,c] from:
// [a, b, c] = someExpression;
if (node.parent.kind === SyntaxKind.BinaryExpression &&
(<BinaryExpression>node.parent).left === node &&
(<BinaryExpression>node.parent).left === node &&
(<BinaryExpression>node.parent).operatorToken.kind === SyntaxKind.EqualsToken) {
return true;
}
@ -711,7 +711,7 @@ namespace ts {
}
function resetWriter() {
displayParts = []
displayParts = [];
lineStart = true;
indent = 0;
}
@ -768,7 +768,7 @@ namespace ts {
}
export function textOrKeywordPart(text: string) {
var kind = stringToToken(text);
const kind = stringToToken(text);
return kind === undefined
? textPart(text)
: keywordPart(kind);

View file

@ -1,12 +1,12 @@
/// <reference path="..\..\..\src\harness\harness.ts" />
module ts {
namespace ts {
interface File {
name: string;
content: string;
}
function createDefaultServerHost(fileMap: Map<File>): server.ServerHost {
function createDefaultServerHost(fileMap: Map<File>): server.ServerHost {
let existingDirectories: Map<boolean> = {};
forEachValue(fileMap, v => {
let dir = getDirectoryPath(v.name);
@ -54,13 +54,15 @@ module ts {
watchFile: (path, callback) => {
return {
close: () => { }
}
};
},
watchDirectory: (path, callback, recursive?) => {
return {
close: () => { }
}
}
};
},
setTimeout,
clearTimeout
};
}
@ -79,8 +81,8 @@ module ts {
let projectService = new server.ProjectService(serverHost, logger);
let rootScriptInfo = projectService.openFile(rootFile, /* openedByClient */true);
let project = projectService.createInferredProject(rootScriptInfo);
project.setProjectOptions( {files: [rootScriptInfo.fileName], compilerOptions: {module: ts.ModuleKind.AMD} } );
return {
project.setProjectOptions({ files: [rootScriptInfo.fileName], compilerOptions: { module: ts.ModuleKind.AMD } });
return {
project,
rootScriptInfo
};
@ -97,22 +99,22 @@ module ts {
name: "c:/f1.ts",
content: `foo()`
};
let serverHost = createDefaultServerHost({ [root.name]: root, [imported.name]: imported });
let { project, rootScriptInfo } = createProject(root.name, serverHost);
// ensure that imported file was found
let diags = project.compilerService.languageService.getSemanticDiagnostics(imported.name);
assert.equal(diags.length, 1);
let originalFileExists = serverHost.fileExists;
{
// patch fileExists to make sure that disk is not touched
serverHost.fileExists = (fileName): boolean => {
assert.isTrue(false, "fileExists should not be called");
assert.isTrue(false, "fileExists should not be called");
return false;
};
let newContent = `import {x} from "f1"
var x: string = 1;`;
rootScriptInfo.editContent(0, rootScriptInfo.content.length, newContent);
@ -128,21 +130,20 @@ module ts {
return false;
}
fileExistsIsCalled = true;
assert.isTrue(fileName.indexOf('/f2.') !== -1);
assert.isTrue(fileName.indexOf("/f2.") !== -1);
return originalFileExists.call(serverHost, fileName);
};
let newContent = `import {x} from "f2"`;
rootScriptInfo.editContent(0, rootScriptInfo.content.length, newContent);
try {
// trigger synchronization to make sure that LSHost will try to find 'f2' module on disk
project.compilerService.languageService.getSemanticDiagnostics(imported.name);
assert.isTrue(false, `should not find file '${imported.name}'`)
assert.isTrue(false, `should not find file '${imported.name}'`);
}
catch(e) {
catch (e) {
assert.isTrue(e.message.indexOf(`Could not find file: '${imported.name}'.`) === 0);
}
assert.isTrue(fileExistsIsCalled);
}
{
@ -150,45 +151,45 @@ module ts {
serverHost.fileExists = (fileName): boolean => {
if (fileName === "lib.d.ts") {
return false;
}
}
fileExistsCalled = true;
assert.isTrue(fileName.indexOf('/f1.') !== -1);
assert.isTrue(fileName.indexOf("/f1.") !== -1);
return originalFileExists.call(serverHost, fileName);
};
let newContent = `import {x} from "f1"`;
rootScriptInfo.editContent(0, rootScriptInfo.content.length, newContent);
project.compilerService.languageService.getSemanticDiagnostics(imported.name);
assert.isTrue(fileExistsCalled);
// setting compiler options discards module resolution cache
fileExistsCalled = false;
let opts = ts.clone(project.projectOptions);
opts.compilerOptions = ts.clone(opts.compilerOptions);
opts.compilerOptions.target = ts.ScriptTarget.ES5;
project.setProjectOptions(opts);
project.compilerService.languageService.getSemanticDiagnostics(imported.name);
assert.isTrue(fileExistsCalled);
}
});
it("loads missing files from disk", () => {
let root: File = {
name: 'c:/foo.ts',
name: `c:/foo.ts`,
content: `import {x} from "bar"`
};
let imported: File = {
name: 'c:/bar.d.ts',
name: `c:/bar.d.ts`,
content: `export var y = 1`
};
};
let fileMap: Map<File> = { [root.name]: root };
let serverHost = createDefaultServerHost(fileMap);
let originalFileExists = serverHost.fileExists;
let fileExistsCalledForBar = false;
serverHost.fileExists = fileName => {
if (fileName === "lib.d.ts") {
@ -197,25 +198,25 @@ module ts {
if (!fileExistsCalledForBar) {
fileExistsCalledForBar = fileName.indexOf("/bar.") !== -1;
}
return originalFileExists.call(serverHost, fileName);
};
let { project, rootScriptInfo } = createProject(root.name, serverHost);
let diags = project.compilerService.languageService.getSemanticDiagnostics(root.name);
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called");
assert.isTrue(diags.length === 1, "one diagnostic expected");
assert.isTrue(typeof diags[0].messageText === "string" && ((<string>diags[0].messageText).indexOf("Cannot find module") === 0), "should be 'cannot find module' message");
// assert that import will success once file appear on disk
fileMap[imported.name] = imported;
fileExistsCalledForBar = false;
rootScriptInfo.editContent(0, rootScriptInfo.content.length, `import {y} from "bar"`)
rootScriptInfo.editContent(0, rootScriptInfo.content.length, `import {y} from "bar"`);
diags = project.compilerService.languageService.getSemanticDiagnostics(root.name);
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called");
assert.isTrue(diags.length === 0);
})
});
});
}

View file

@ -18,7 +18,9 @@ namespace ts.server {
getExecutingFilePath(): string { return void 0; },
getCurrentDirectory(): string { return void 0; },
readDirectory(): string[] { return []; },
exit(): void {}
exit(): void { },
setTimeout(callback, ms, ...args) { return 0; },
clearTimeout(timeoutId) { }
};
const mockLogger: Logger = {
close(): void {},

View file

@ -1,13 +1,13 @@
/// <reference path="..\..\..\src\harness\harness.ts" />
/// <reference path="..\..\..\src\server\editorServices.ts" />
module ts {
namespace ts {
function editFlat(position: number, deletedLength: number, newText: string, source: string) {
return source.substring(0, position) + newText + source.substring(position + deletedLength, source.length);
}
function lineColToPosition(lineIndex: server.LineIndex, line: number, col: number) {
var lineInfo = lineIndex.lineNumberToInfo(line);
const lineInfo = lineIndex.lineNumberToInfo(line);
return (lineInfo.offset + col - 1);
}
@ -19,9 +19,9 @@ module ts {
assert.equal(editedText, checkText);
}
describe('VersionCache TS code', () => {
describe(`VersionCache TS code`, () => {
let validateEditAtLineCharIndex: (line: number, char: number, deleteLength: number, insertString: string) => void;
before(() => {
let testContent = `/// <reference path="z.ts" />
var x = 10;
@ -32,9 +32,9 @@ class Point {
}
k=y;
var p:Point=new Point();
var q:Point=<Point>p;`
var q:Point=<Point>p;`;
let {lines, lineMap} = server.LineIndex.linesFromText(testContent);
let { lines } = server.LineIndex.linesFromText(testContent);
assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line");
let lineIndex = new server.LineIndex();
@ -48,34 +48,34 @@ var q:Point=<Point>p;`
after(() => {
validateEditAtLineCharIndex = undefined;
})
});
it('change 9 1 0 1 {"y"}', () => {
it(`change 9 1 0 1 {"y"}`, () => {
validateEditAtLineCharIndex(9, 1, 0, "y");
});
it('change 9 2 0 1 {"."}', () => {
it(`change 9 2 0 1 {"."}`, () => {
validateEditAtLineCharIndex(9, 2, 0, ".");
});
it('change 9 3 0 1 {"\\n"}', () => {
it(`change 9 3 0 1 {"\\n"}`, () => {
validateEditAtLineCharIndex(9, 3, 0, "\n");
});
it('change 10 1 0 10 {"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"}', () => {
it(`change 10 1 0 10 {"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"}`, () => {
validateEditAtLineCharIndex(10, 1, 0, "\n\n\n\n\n\n\n\n\n\n");
});
it('change 19 1 1 0', () => {
it(`change 19 1 1 0`, () => {
validateEditAtLineCharIndex(19, 1, 1, "");
});
it('change 18 1 1 0', () => {
it(`change 18 1 1 0`, () => {
validateEditAtLineCharIndex(18, 1, 1, "");
});
});
describe('VersionCache simple text', () => {
describe(`VersionCache simple text`, () => {
let validateEditAtPosition: (position: number, deleteLength: number, insertString: string) => void;
let testContent: string;
let lines: string[];
@ -88,7 +88,7 @@ that ate the grass
that was purple at the tips
and grew 1cm per day`;
({lines, lineMap} = server.LineIndex.linesFromText(testContent));
({ lines, lineMap } = server.LineIndex.linesFromText(testContent));
assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line");
let lineIndex = new server.LineIndex();
@ -96,90 +96,90 @@ and grew 1cm per day`;
validateEditAtPosition = (position: number, deleteLength: number, insertString: string) => {
validateEdit(lineIndex, testContent, position, deleteLength, insertString);
}
};
});
after(() => {
validateEditAtPosition = undefined;
testContent = undefined;
lines = undefined;
lineMap = undefined;
validateEditAtPosition = undefined;
testContent = undefined;
lines = undefined;
lineMap = undefined;
});
it('Insert at end of file', () => {
it(`Insert at end of file`, () => {
validateEditAtPosition(testContent.length, 0, "hmmmm...\r\n");
});
it('Unusual line endings merge', () => {
it(`Unusual line endings merge`, () => {
validateEditAtPosition(lines[0].length - 1, lines[1].length, "");
});
it('Delete whole line and nothing but line (last line)', () => {
it(`Delete whole line and nothing but line (last line)`, () => {
validateEditAtPosition(lineMap[lineMap.length - 2], lines[lines.length - 1].length, "");
});
it('Delete whole line and nothing but line (first line)', () => {
it(`Delete whole line and nothing but line (first line)`, () => {
validateEditAtPosition(0, lines[0].length, "");
});
it('Delete whole line (first line) and insert with no line breaks', () => {
it(`Delete whole line (first line) and insert with no line breaks`, () => {
validateEditAtPosition(0, lines[0].length, "moo, moo, moo! ");
});
it('Delete whole line (first line) and insert with multiple line breaks', () => {
it(`Delete whole line (first line) and insert with multiple line breaks`, () => {
validateEditAtPosition(0, lines[0].length, "moo, \r\nmoo, \r\nmoo! ");
});
it('Delete multiple lines and nothing but lines (first and second lines)', () => {
it(`Delete multiple lines and nothing but lines (first and second lines)`, () => {
validateEditAtPosition(0, lines[0].length + lines[1].length, "");
});
it('Delete multiple lines and nothing but lines (second and third lines)', () => {
it(`Delete multiple lines and nothing but lines (second and third lines)`, () => {
validateEditAtPosition(lines[0].length, lines[1].length + lines[2].length, "");
});
it('Insert multiple line breaks', () => {
it(`Insert multiple line breaks`, () => {
validateEditAtPosition(21, 1, "cr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr...\r\ncr");
});
it('Insert multiple line breaks', () => {
it(`Insert multiple line breaks`, () => {
validateEditAtPosition(21, 1, "cr...\r\ncr...\r\ncr");
});
it('Insert multiple line breaks with leading \\n', () => {
it(`Insert multiple line breaks with leading \\n`, () => {
validateEditAtPosition(21, 1, "\ncr...\r\ncr...\r\ncr");
});
it('Single line no line breaks deleted or inserted, delete 1 char', () => {
it(`Single line no line breaks deleted or inserted, delete 1 char`, () => {
validateEditAtPosition(21, 1, "");
});
it('Single line no line breaks deleted or inserted, insert 1 char', () => {
it(`Single line no line breaks deleted or inserted, insert 1 char`, () => {
validateEditAtPosition(21, 0, "b");
});
it('Single line no line breaks deleted or inserted, delete 1, insert 2 chars', () => {
it(`Single line no line breaks deleted or inserted, delete 1, insert 2 chars`, () => {
validateEditAtPosition(21, 1, "cr");
});
it('Delete across line break (just the line break)', () => {
it(`Delete across line break (just the line break)`, () => {
validateEditAtPosition(21, 22, "");
});
it('Delete across line break', () => {
it(`Delete across line break`, () => {
validateEditAtPosition(21, 32, "");
});
it('Delete across multiple line breaks and insert no line breaks', () => {
it(`Delete across multiple line breaks and insert no line breaks`, () => {
validateEditAtPosition(21, 42, "");
});
it('Delete across multiple line breaks and insert text', () => {
it(`Delete across multiple line breaks and insert text`, () => {
validateEditAtPosition(21, 42, "slithery ");
});
});
describe('VersionCache stress test', () => {
describe(`VersionCache stress test`, () => {
let rsa: number[] = [];
let la: number[] = [];
let las: number[] = [];
@ -187,7 +187,7 @@ and grew 1cm per day`;
let ersa: number[] = [];
let ela: number[] = [];
const iterationCount = 20;
//const iterationCount = 20000; // uncomment for testing
// const iterationCount = 20000; // uncomment for testing
let lines: string[];
let lineMap: number[];
let lineIndex: server.LineIndex;
@ -200,7 +200,7 @@ and grew 1cm per day`;
let totalChars = testContent.length;
assert.isTrue(totalChars > 0, "Failed to read test file.");
({lines, lineMap} = server.LineIndex.linesFromText(testContent));
({ lines, lineMap } = server.LineIndex.linesFromText(testContent));
assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line");
lineIndex = new server.LineIndex();
@ -271,7 +271,7 @@ and grew 1cm per day`;
});
it("Edit ScriptVersionCache ", () => {
let svc = server.ScriptVersionCache.fromString(ts.sys, testContent);
let svc = server.ScriptVersionCache.fromString(<server.ServerHost>ts.sys, testContent);
let checkText = testContent;
for (let i = 0; i < iterationCount; i++) {
@ -316,4 +316,4 @@ and grew 1cm per day`;
}
});
});
}
}