From 733dbd9a42e9703589f1814f1163582505ef7848 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 14 Feb 2017 14:15:12 -0800 Subject: [PATCH] Update LKG --- lib/cancellationToken.js | 52 +++++++-- lib/lib.d.ts | 12 +- lib/lib.es5.d.ts | 12 +- lib/lib.es6.d.ts | 12 +- lib/protocol.d.ts | 11 ++ lib/tsserver.js | 234 ++++++++++++++++++++++++++++++-------- lib/tsserverlibrary.d.ts | 30 ++++- lib/tsserverlibrary.js | 230 +++++++++++++++++++++++++++++-------- lib/typescript.js | 62 +++++++--- lib/typescriptServices.js | 62 +++++++--- 10 files changed, 544 insertions(+), 173 deletions(-) diff --git a/lib/cancellationToken.js b/lib/cancellationToken.js index 003999d2e8a..378255a37ee 100644 --- a/lib/cancellationToken.js +++ b/lib/cancellationToken.js @@ -15,6 +15,15 @@ and limitations under the License. "use strict"; var fs = require("fs"); +function pipeExists(name) { + try { + fs.statSync(name); + return true; + } + catch (e) { + return false; + } +} function createCancellationToken(args) { var cancellationPipeName; for (var i = 0; i < args.length - 1; i++) { @@ -24,18 +33,39 @@ function createCancellationToken(args) { } } if (!cancellationPipeName) { - return { isCancellationRequested: function () { return false; } }; + return { + isCancellationRequested: function () { return false; }, + setRequest: function (_requestId) { return void 0; }, + resetRequest: function (_requestId) { return void 0; } + }; } - return { - isCancellationRequested: function () { - try { - fs.statSync(cancellationPipeName); - return true; - } - catch (e) { - return false; - } + if (cancellationPipeName.charAt(cancellationPipeName.length - 1) === "*") { + var namePrefix_1 = cancellationPipeName.slice(0, -1); + if (namePrefix_1.length === 0 || namePrefix_1.indexOf("*") >= 0) { + throw new Error("Invalid name for template cancellation pipe: it should have length greater than 2 characters and contain only one '*'."); } - }; + var perRequestPipeName_1; + var currentRequestId_1; + return { + isCancellationRequested: function () { return perRequestPipeName_1 !== undefined && pipeExists(perRequestPipeName_1); }, + setRequest: function (requestId) { + currentRequestId_1 = currentRequestId_1; + perRequestPipeName_1 = namePrefix_1 + requestId; + }, + resetRequest: function (requestId) { + if (currentRequestId_1 !== requestId) { + throw new Error("Mismatched request id, expected " + currentRequestId_1 + ", actual " + requestId); + } + perRequestPipeName_1 = undefined; + } + }; + } + else { + return { + isCancellationRequested: function () { return pipeExists(cancellationPipeName); }, + setRequest: function (_requestId) { return void 0; }, + resetRequest: function (_requestId) { return void 0; } + }; + } } module.exports = createCancellationToken; diff --git a/lib/lib.d.ts b/lib/lib.d.ts index c9254b57839..a65a0100e6c 100644 --- a/lib/lib.d.ts +++ b/lib/lib.d.ts @@ -157,16 +157,10 @@ interface ObjectConstructor { getOwnPropertyNames(o: any): string[]; /** - * Creates an object that has null prototype. - * @param o Object to use as a prototype. May be null + * Creates an object that has the specified prototype or that has null prototype. + * @param o Object to use as a prototype. May be null. */ - create(o: null): any; - - /** - * Creates an object that has the specified prototype, and that optionally contains specified properties. - * @param o Object to use as a prototype. May be null - */ - create(o: T): T; + create(o: T | null): T | object; /** * Creates an object that has the specified prototype, and that optionally contains specified properties. diff --git a/lib/lib.es5.d.ts b/lib/lib.es5.d.ts index 764daf82a6b..496dd2102d5 100644 --- a/lib/lib.es5.d.ts +++ b/lib/lib.es5.d.ts @@ -157,16 +157,10 @@ interface ObjectConstructor { getOwnPropertyNames(o: any): string[]; /** - * Creates an object that has null prototype. - * @param o Object to use as a prototype. May be null + * Creates an object that has the specified prototype or that has null prototype. + * @param o Object to use as a prototype. May be null. */ - create(o: null): any; - - /** - * Creates an object that has the specified prototype, and that optionally contains specified properties. - * @param o Object to use as a prototype. May be null - */ - create(o: T): T; + create(o: T | null): T | object; /** * Creates an object that has the specified prototype, and that optionally contains specified properties. diff --git a/lib/lib.es6.d.ts b/lib/lib.es6.d.ts index 2207f1a4e81..0265e696e0d 100644 --- a/lib/lib.es6.d.ts +++ b/lib/lib.es6.d.ts @@ -157,16 +157,10 @@ interface ObjectConstructor { getOwnPropertyNames(o: any): string[]; /** - * Creates an object that has null prototype. - * @param o Object to use as a prototype. May be null + * Creates an object that has the specified prototype or that has null prototype. + * @param o Object to use as a prototype. May be null. */ - create(o: null): any; - - /** - * Creates an object that has the specified prototype, and that optionally contains specified properties. - * @param o Object to use as a prototype. May be null - */ - create(o: T): T; + create(o: T | null): T | object; /** * Creates an object that has the specified prototype, and that optionally contains specified properties. diff --git a/lib/protocol.d.ts b/lib/protocol.d.ts index b33005cf2f8..fc9a35893fe 100644 --- a/lib/protocol.d.ts +++ b/lib/protocol.d.ts @@ -1356,6 +1356,17 @@ declare namespace ts.server.protocol { command: CommandTypes.Geterr; arguments: GeterrRequestArgs; } + type RequestCompletedEventName = "requestCompleted"; + /** + * Event that is sent when server have finished processing request with specified id. + */ + interface RequestCompletedEvent extends Event { + event: RequestCompletedEventName; + body: RequestCompletedEventBody; + } + interface RequestCompletedEventBody { + request_seq: number; + } /** * Item of diagnostic information found in a DiagnosticEvent message. */ diff --git a/lib/tsserver.js b/lib/tsserver.js index ccdbf835237..53fd42a0434 100644 --- a/lib/tsserver.js +++ b/lib/tsserver.js @@ -56330,13 +56330,25 @@ var ts; } } else if (sourceFile.languageVariant === 1) { - if (kind === 26) { - isRightOfOpenTag = true; - location = contextToken; - } - else if (kind === 40 && contextToken.parent.kind === 251) { - isStartingCloseTag = true; - location = contextToken; + switch (contextToken.parent.kind) { + case 251: + if (kind === 40) { + isStartingCloseTag = true; + location = contextToken; + } + break; + case 193: + if (!(contextToken.parent.left.flags & 32768)) { + break; + } + case 249: + case 248: + case 250: + if (kind === 26) { + isRightOfOpenTag = true; + location = contextToken; + } + break; } } } @@ -57797,21 +57809,23 @@ var ts; } function getAllReferencesForKeyword(sourceFiles, keywordKind, cancellationToken) { var name = ts.tokenToString(keywordKind); - var definition = { - containerKind: "", - containerName: "", - fileName: "", - kind: ts.ScriptElementKind.keyword, - name: name, - textSpan: ts.createTextSpan(0, 1), - displayParts: [{ text: name, kind: ts.ScriptElementKind.keyword }] - }; var references = []; for (var _i = 0, sourceFiles_6 = sourceFiles; _i < sourceFiles_6.length; _i++) { var sourceFile = sourceFiles_6[_i]; cancellationToken.throwIfCancellationRequested(); addReferencesForKeywordInFile(sourceFile, keywordKind, name, cancellationToken, references); } + if (!references.length) + return undefined; + var definition = { + containerKind: "", + containerName: "", + fileName: references[0].fileName, + kind: ts.ScriptElementKind.keyword, + name: name, + textSpan: references[0].textSpan, + displayParts: [{ text: name, kind: ts.ScriptElementKind.keyword }] + }; return [{ definition: definition, references: references }]; } function addReferencesForKeywordInFile(sourceFile, kind, searchText, cancellationToken, references) { @@ -64466,7 +64480,17 @@ var ts; return importDecl; } function createCodeFixToRemoveNode(node) { - return createCodeFix("", node.getStart(), node.getWidth()); + var end = node.getEnd(); + var endCharCode = sourceFile.text.charCodeAt(end); + var afterEndCharCode = sourceFile.text.charCodeAt(end + 1); + if (ts.isLineBreak(endCharCode)) { + end += 1; + } + if (ts.isLineBreak(afterEndCharCode) && endCharCode !== afterEndCharCode) { + end += 1; + } + var start = node.getStart(); + return createCodeFix("", start, end - start); } function findFirstNonSpaceCharPosStarting(start) { while (ts.isWhiteSpace(sourceFile.text.charCodeAt(start))) { @@ -68333,7 +68357,7 @@ var ts; this.compilerOptions.allowNonTsExtensions = true; this.compilerOptions.allowJs = true; } - else if (hasExplicitListOfFiles) { + else if (hasExplicitListOfFiles || this.compilerOptions.allowJs) { this.compilerOptions.allowNonTsExtensions = true; } this.setInternalCompilerOptionsForEmittingJsFiles(); @@ -70126,6 +70150,11 @@ var ts; (function (ts) { var server; (function (server) { + server.nullCancellationToken = { + isCancellationRequested: function () { return false; }, + setRequest: function () { return void 0; }, + resetRequest: function () { return void 0; } + }; function hrTimeToMilliseconds(time) { var seconds = time[0]; var nanoseconds = time[1]; @@ -70265,10 +70294,93 @@ var ts; return "Content-Length: " + (1 + len) + "\r\n\r\n" + json + newLine; } server.formatMessage = formatMessage; + var MultistepOperation = (function () { + function MultistepOperation(operationHost) { + var _this = this; + this.operationHost = operationHost; + this.completed = true; + this.next = { + immediate: function (action) { return _this.immediate(action); }, + delay: function (ms, action) { return _this.delay(ms, action); } + }; + } + MultistepOperation.prototype.startNew = function (action) { + this.complete(); + this.requestId = this.operationHost.getCurrentRequestId(); + this.completed = false; + this.executeAction(action); + }; + MultistepOperation.prototype.complete = function () { + if (!this.completed) { + if (this.requestId) { + this.operationHost.sendRequestCompletedEvent(this.requestId); + } + this.completed = true; + } + this.setTimerHandle(undefined); + this.setImmediateId(undefined); + }; + MultistepOperation.prototype.immediate = function (action) { + var _this = this; + var requestId = this.requestId; + ts.Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "immediate: incorrect request id"); + this.setImmediateId(this.operationHost.getServerHost().setImmediate(function () { + _this.immediateId = undefined; + _this.operationHost.executeWithRequestId(requestId, function () { return _this.executeAction(action); }); + })); + }; + MultistepOperation.prototype.delay = function (ms, action) { + var _this = this; + var requestId = this.requestId; + ts.Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "delay: incorrect request id"); + this.setTimerHandle(this.operationHost.getServerHost().setTimeout(function () { + _this.timerHandle = undefined; + _this.operationHost.executeWithRequestId(requestId, function () { return _this.executeAction(action); }); + }, ms)); + }; + MultistepOperation.prototype.executeAction = function (action) { + var stop = false; + try { + if (this.operationHost.isCancellationRequested()) { + stop = true; + } + else { + action(this.next); + } + } + catch (e) { + stop = true; + if (!(e instanceof ts.OperationCanceledException)) { + this.operationHost.logError(e, "delayed processing of request " + this.requestId); + } + } + if (stop || !this.hasPendingWork()) { + this.complete(); + } + }; + MultistepOperation.prototype.setTimerHandle = function (timerHandle) { + ; + if (this.timerHandle !== undefined) { + this.operationHost.getServerHost().clearTimeout(this.timerHandle); + } + this.timerHandle = timerHandle; + }; + MultistepOperation.prototype.setImmediateId = function (immediateId) { + if (this.immediateId !== undefined) { + this.operationHost.getServerHost().clearImmediate(this.immediateId); + } + this.immediateId = immediateId; + }; + MultistepOperation.prototype.hasPendingWork = function () { + return !!this.timerHandle || !!this.immediateId; + }; + return MultistepOperation; + }()); var Session = (function () { function Session(host, cancellationToken, useSingleInferredProject, typingsInstaller, byteLength, hrtime, logger, canUseEvents, eventHandler) { var _this = this; this.host = host; + this.cancellationToken = cancellationToken; this.typingsInstaller = typingsInstaller; this.byteLength = byteLength; this.hrtime = hrtime; @@ -70429,12 +70541,12 @@ var ts; return _this.requiredResponse(_this.getSyntacticDiagnosticsSync(request.arguments)); }, _a[CommandNames.Geterr] = function (request) { - var geterrArgs = request.arguments; - return { response: _this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false }; + _this.errorCheck.startNew(function (next) { return _this.getDiagnostics(next, request.arguments.delay, request.arguments.files); }); + return _this.notRequired(); }, _a[CommandNames.GeterrForProject] = function (request) { - var _a = request.arguments, file = _a.file, delay = _a.delay; - return { response: _this.getDiagnosticsForProject(delay, file), responseRequired: false }; + _this.errorCheck.startNew(function (next) { return _this.getDiagnosticsForProject(next, request.arguments.delay, request.arguments.file); }); + return _this.notRequired(); }, _a[CommandNames.Change] = function (request) { _this.change(request.arguments); @@ -70516,17 +70628,35 @@ var ts; this.eventHander = canUseEvents ? eventHandler || (function (event) { return _this.defaultEventHandler(event); }) : undefined; + var multistepOperationHost = { + executeWithRequestId: function (requestId, action) { return _this.executeWithRequestId(requestId, action); }, + getCurrentRequestId: function () { return _this.currentRequestId; }, + getServerHost: function () { return _this.host; }, + logError: function (err, cmd) { return _this.logError(err, cmd); }, + sendRequestCompletedEvent: function (requestId) { return _this.sendRequestCompletedEvent(requestId); }, + isCancellationRequested: function () { return cancellationToken.isCancellationRequested(); } + }; + this.errorCheck = new MultistepOperation(multistepOperationHost); this.projectService = new server.ProjectService(host, logger, cancellationToken, useSingleInferredProject, typingsInstaller, this.eventHander); this.gcTimer = new server.GcTimer(host, 7000, logger); var _a; } + Session.prototype.sendRequestCompletedEvent = function (requestId) { + var event = { + seq: 0, + type: "event", + event: "requestCompleted", + body: { request_seq: requestId } + }; + this.send(event); + }; Session.prototype.defaultEventHandler = function (event) { var _this = this; switch (event.eventName) { case server.ContextEvent: - var _a = event.data, project = _a.project, fileName = _a.fileName; - this.projectService.logger.info("got context event, updating diagnostics for " + fileName); - this.updateErrorCheck([{ fileName: fileName, project: project }], this.changeSeq, function (n) { return n === _this.changeSeq; }, 100); + var _a = event.data, project_1 = _a.project, fileName_1 = _a.fileName; + this.projectService.logger.info("got context event, updating diagnostics for " + fileName_1); + this.errorCheck.startNew(function (next) { return _this.updateErrorCheck(next, [{ fileName: fileName_1, project: project_1 }], _this.changeSeq, function (n) { return n === _this.changeSeq; }, 100); }); break; case server.ConfigFileDiagEvent: var _b = event.data, triggerFile = _b.triggerFile, configFileName = _b.configFileName, diagnostics = _b.diagnostics; @@ -70579,7 +70709,7 @@ var ts; seq: 0, type: "event", event: eventName, - body: info, + body: info }; this.send(ev); }; @@ -70634,7 +70764,7 @@ var ts; } }, ms); }; - Session.prototype.updateErrorCheck = function (checkList, seq, matchSeq, ms, followMs, requireOpen) { + Session.prototype.updateErrorCheck = function (next, checkList, seq, matchSeq, ms, followMs, requireOpen) { var _this = this; if (ms === void 0) { ms = 1500; } if (followMs === void 0) { followMs = 200; } @@ -70642,13 +70772,6 @@ var ts; if (followMs > ms) { followMs = ms; } - if (this.errorTimer) { - this.host.clearTimeout(this.errorTimer); - } - if (this.immediateId) { - this.host.clearImmediate(this.immediateId); - this.immediateId = undefined; - } var index = 0; var checkOne = function () { if (matchSeq(seq)) { @@ -70656,21 +70779,17 @@ var ts; index++; if (checkSpec_1.project.containsFile(checkSpec_1.fileName, requireOpen)) { _this.syntacticCheck(checkSpec_1.fileName, checkSpec_1.project); - _this.immediateId = _this.host.setImmediate(function () { + next.immediate(function () { _this.semanticCheck(checkSpec_1.fileName, checkSpec_1.project); - _this.immediateId = undefined; if (checkList.length > index) { - _this.errorTimer = _this.host.setTimeout(checkOne, followMs); - } - else { - _this.errorTimer = undefined; + next.delay(followMs, checkOne); } }); } } }; if ((checkList.length > index) && (matchSeq(seq))) { - this.errorTimer = this.host.setTimeout(checkOne, ms); + next.delay(ms, checkOne); } }; Session.prototype.cleanProjects = function (caption, projects) { @@ -71270,7 +71389,7 @@ var ts; return helpItems; } }; - Session.prototype.getDiagnostics = function (delay, fileNames) { + Session.prototype.getDiagnostics = function (next, delay, fileNames) { var _this = this; var checkList = fileNames.reduce(function (accum, uncheckedFileName) { var fileName = server.toNormalizedPath(uncheckedFileName); @@ -71281,7 +71400,7 @@ var ts; return accum; }, []); if (checkList.length > 0) { - this.updateErrorCheck(checkList, this.changeSeq, function (n) { return n === _this.changeSeq; }, delay); + this.updateErrorCheck(next, checkList, this.changeSeq, function (n) { return n === _this.changeSeq; }, delay); } }; Session.prototype.change = function (args) { @@ -71488,7 +71607,7 @@ var ts; ? spans.map(function (span) { return _this.decorateSpan(span, scriptInfo); }) : spans; }; - Session.prototype.getDiagnosticsForProject = function (delay, fileName) { + Session.prototype.getDiagnosticsForProject = function (next, delay, fileName) { var _this = this; var _a = this.getProjectInfoWorker(fileName, undefined, true), fileNames = _a.fileNames, languageServiceDisabled = _a.languageServiceDisabled; if (languageServiceDisabled) { @@ -71520,7 +71639,7 @@ var ts; fileNamesInProject = highPriorityFiles.concat(mediumPriorityFiles).concat(lowPriorityFiles).concat(veryLowPriorityFiles); if (fileNamesInProject.length > 0) { var checkList = fileNamesInProject.map(function (fileName) { return ({ fileName: fileName, project: project }); }); - this.updateErrorCheck(checkList, this.changeSeq, function (n) { return n == _this.changeSeq; }, delay, 200, false); + this.updateErrorCheck(next, checkList, this.changeSeq, function (n) { return n == _this.changeSeq; }, delay, 200, false); } }; Session.prototype.getCanonicalFileName = function (fileName) { @@ -71541,10 +71660,29 @@ var ts; } this.handlers.set(command, handler); }; + Session.prototype.setCurrentRequest = function (requestId) { + ts.Debug.assert(this.currentRequestId === undefined); + this.currentRequestId = requestId; + this.cancellationToken.setRequest(requestId); + }; + Session.prototype.resetCurrentRequest = function (requestId) { + ts.Debug.assert(this.currentRequestId === requestId); + this.currentRequestId = undefined; + this.cancellationToken.resetRequest(requestId); + }; + Session.prototype.executeWithRequestId = function (requestId, f) { + try { + this.setCurrentRequest(requestId); + return f(); + } + finally { + this.resetCurrentRequest(requestId); + } + }; Session.prototype.executeCommand = function (request) { var handler = this.handlers.get(request.command); if (handler) { - return handler(request); + return this.executeWithRequestId(request.seq, function () { return handler(request); }); } else { this.logger.msg("Unrecognized JSON command: " + JSON.stringify(request), server.Msg.Err); @@ -72879,9 +73017,7 @@ var ts; cancellationToken = factory(sys.args); } catch (e) { - cancellationToken = { - isCancellationRequested: function () { return false; } - }; + cancellationToken = server.nullCancellationToken; } ; var eventPort; diff --git a/lib/tsserverlibrary.d.ts b/lib/tsserverlibrary.d.ts index 6462f7940a0..ab8d2e141e3 100644 --- a/lib/tsserverlibrary.d.ts +++ b/lib/tsserverlibrary.d.ts @@ -3886,6 +3886,14 @@ declare namespace ts.server.protocol { command: CommandTypes.Geterr; arguments: GeterrRequestArgs; } + type RequestCompletedEventName = "requestCompleted"; + interface RequestCompletedEvent extends Event { + event: RequestCompletedEventName; + body: RequestCompletedEventBody; + } + interface RequestCompletedEventBody { + request_seq: number; + } interface Diagnostic { start: Location; end: Location; @@ -4162,6 +4170,11 @@ declare namespace ts.server.protocol { type ScriptTarget = ScriptTarget.ES3 | ScriptTarget.ES5 | ScriptTarget.ES6 | ScriptTarget.ES2015; } declare namespace ts.server { + interface ServerCancellationToken extends HostCancellationToken { + setRequest(requestId: number): void; + resetRequest(requestId: number): void; + } + const nullCancellationToken: ServerCancellationToken; interface PendingErrorCheck { fileName: NormalizedPath; project: Project; @@ -4218,6 +4231,7 @@ declare namespace ts.server { function formatMessage(msg: T, logger: server.Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string; class Session implements EventSender { private host; + private readonly cancellationToken; protected readonly typingsInstaller: ITypingsInstaller; private byteLength; private hrtime; @@ -4225,11 +4239,12 @@ declare namespace ts.server { protected readonly canUseEvents: boolean; private readonly gcTimer; protected projectService: ProjectService; - private errorTimer; - private immediateId; private changeSeq; + private currentRequestId; + private errorCheck; private eventHander; - constructor(host: ServerHost, cancellationToken: HostCancellationToken, useSingleInferredProject: boolean, typingsInstaller: ITypingsInstaller, byteLength: (buf: string, encoding?: string) => number, hrtime: (start?: number[]) => number[], logger: Logger, canUseEvents: boolean, eventHandler?: ProjectServiceEventHandler); + constructor(host: ServerHost, cancellationToken: ServerCancellationToken, useSingleInferredProject: boolean, typingsInstaller: ITypingsInstaller, byteLength: (buf: string, encoding?: string) => number, hrtime: (start?: number[]) => number[], logger: Logger, canUseEvents: boolean, eventHandler?: ProjectServiceEventHandler); + private sendRequestCompletedEvent(requestId); private defaultEventHandler(event); logError(err: Error, cmd: string): void; send(msg: protocol.Message): void; @@ -4239,7 +4254,7 @@ declare namespace ts.server { private semanticCheck(file, project); private syntacticCheck(file, project); private updateProjectStructure(seq, matchSeq, ms?); - private updateErrorCheck(checkList, seq, matchSeq, ms?, followMs?, requireOpen?); + private updateErrorCheck(next, checkList, seq, matchSeq, ms?, followMs?, requireOpen?); private cleanProjects(caption, projects); private cleanup(); private getEncodedSemanticClassifications(args); @@ -4284,7 +4299,7 @@ declare namespace ts.server { private getCompileOnSaveAffectedFileList(args); private emitFile(args); private getSignatureHelpItems(args, simplifiedResult); - private getDiagnostics(delay, fileNames); + private getDiagnostics(next, delay, fileNames); private change(args); private reload(args, reqSeq); private saveToTmp(fileName, tempFileName); @@ -4300,7 +4315,7 @@ declare namespace ts.server { private mapCodeAction(codeAction, scriptInfo); private convertTextChangeToCodeEdit(change, scriptInfo); private getBraceMatching(args, simplifiedResult); - getDiagnosticsForProject(delay: number, fileName: string): void; + private getDiagnosticsForProject(next, delay, fileName); getCanonicalFileName(fileName: string): string; exit(): void; private notRequired(); @@ -4310,6 +4325,9 @@ declare namespace ts.server { response?: any; responseRequired: boolean; }): void; + private setCurrentRequest(requestId); + private resetCurrentRequest(requestId); + executeWithRequestId(requestId: number, f: () => T): T; executeCommand(request: protocol.Request): { response?: any; responseRequired?: boolean; diff --git a/lib/tsserverlibrary.js b/lib/tsserverlibrary.js index 5444b2ce142..26499261e02 100644 --- a/lib/tsserverlibrary.js +++ b/lib/tsserverlibrary.js @@ -56330,13 +56330,25 @@ var ts; } } else if (sourceFile.languageVariant === 1) { - if (kind === 26) { - isRightOfOpenTag = true; - location = contextToken; - } - else if (kind === 40 && contextToken.parent.kind === 251) { - isStartingCloseTag = true; - location = contextToken; + switch (contextToken.parent.kind) { + case 251: + if (kind === 40) { + isStartingCloseTag = true; + location = contextToken; + } + break; + case 193: + if (!(contextToken.parent.left.flags & 32768)) { + break; + } + case 249: + case 248: + case 250: + if (kind === 26) { + isRightOfOpenTag = true; + location = contextToken; + } + break; } } } @@ -57797,21 +57809,23 @@ var ts; } function getAllReferencesForKeyword(sourceFiles, keywordKind, cancellationToken) { var name = ts.tokenToString(keywordKind); - var definition = { - containerKind: "", - containerName: "", - fileName: "", - kind: ts.ScriptElementKind.keyword, - name: name, - textSpan: ts.createTextSpan(0, 1), - displayParts: [{ text: name, kind: ts.ScriptElementKind.keyword }] - }; var references = []; for (var _i = 0, sourceFiles_6 = sourceFiles; _i < sourceFiles_6.length; _i++) { var sourceFile = sourceFiles_6[_i]; cancellationToken.throwIfCancellationRequested(); addReferencesForKeywordInFile(sourceFile, keywordKind, name, cancellationToken, references); } + if (!references.length) + return undefined; + var definition = { + containerKind: "", + containerName: "", + fileName: references[0].fileName, + kind: ts.ScriptElementKind.keyword, + name: name, + textSpan: references[0].textSpan, + displayParts: [{ text: name, kind: ts.ScriptElementKind.keyword }] + }; return [{ definition: definition, references: references }]; } function addReferencesForKeywordInFile(sourceFile, kind, searchText, cancellationToken, references) { @@ -64466,7 +64480,17 @@ var ts; return importDecl; } function createCodeFixToRemoveNode(node) { - return createCodeFix("", node.getStart(), node.getWidth()); + var end = node.getEnd(); + var endCharCode = sourceFile.text.charCodeAt(end); + var afterEndCharCode = sourceFile.text.charCodeAt(end + 1); + if (ts.isLineBreak(endCharCode)) { + end += 1; + } + if (ts.isLineBreak(afterEndCharCode) && endCharCode !== afterEndCharCode) { + end += 1; + } + var start = node.getStart(); + return createCodeFix("", start, end - start); } function findFirstNonSpaceCharPosStarting(start) { while (ts.isWhiteSpace(sourceFile.text.charCodeAt(start))) { @@ -66663,6 +66687,11 @@ var ts; (function (ts) { var server; (function (server) { + server.nullCancellationToken = { + isCancellationRequested: function () { return false; }, + setRequest: function () { return void 0; }, + resetRequest: function () { return void 0; } + }; function hrTimeToMilliseconds(time) { var seconds = time[0]; var nanoseconds = time[1]; @@ -66802,10 +66831,93 @@ var ts; return "Content-Length: " + (1 + len) + "\r\n\r\n" + json + newLine; } server.formatMessage = formatMessage; + var MultistepOperation = (function () { + function MultistepOperation(operationHost) { + var _this = this; + this.operationHost = operationHost; + this.completed = true; + this.next = { + immediate: function (action) { return _this.immediate(action); }, + delay: function (ms, action) { return _this.delay(ms, action); } + }; + } + MultistepOperation.prototype.startNew = function (action) { + this.complete(); + this.requestId = this.operationHost.getCurrentRequestId(); + this.completed = false; + this.executeAction(action); + }; + MultistepOperation.prototype.complete = function () { + if (!this.completed) { + if (this.requestId) { + this.operationHost.sendRequestCompletedEvent(this.requestId); + } + this.completed = true; + } + this.setTimerHandle(undefined); + this.setImmediateId(undefined); + }; + MultistepOperation.prototype.immediate = function (action) { + var _this = this; + var requestId = this.requestId; + ts.Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "immediate: incorrect request id"); + this.setImmediateId(this.operationHost.getServerHost().setImmediate(function () { + _this.immediateId = undefined; + _this.operationHost.executeWithRequestId(requestId, function () { return _this.executeAction(action); }); + })); + }; + MultistepOperation.prototype.delay = function (ms, action) { + var _this = this; + var requestId = this.requestId; + ts.Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "delay: incorrect request id"); + this.setTimerHandle(this.operationHost.getServerHost().setTimeout(function () { + _this.timerHandle = undefined; + _this.operationHost.executeWithRequestId(requestId, function () { return _this.executeAction(action); }); + }, ms)); + }; + MultistepOperation.prototype.executeAction = function (action) { + var stop = false; + try { + if (this.operationHost.isCancellationRequested()) { + stop = true; + } + else { + action(this.next); + } + } + catch (e) { + stop = true; + if (!(e instanceof ts.OperationCanceledException)) { + this.operationHost.logError(e, "delayed processing of request " + this.requestId); + } + } + if (stop || !this.hasPendingWork()) { + this.complete(); + } + }; + MultistepOperation.prototype.setTimerHandle = function (timerHandle) { + ; + if (this.timerHandle !== undefined) { + this.operationHost.getServerHost().clearTimeout(this.timerHandle); + } + this.timerHandle = timerHandle; + }; + MultistepOperation.prototype.setImmediateId = function (immediateId) { + if (this.immediateId !== undefined) { + this.operationHost.getServerHost().clearImmediate(this.immediateId); + } + this.immediateId = immediateId; + }; + MultistepOperation.prototype.hasPendingWork = function () { + return !!this.timerHandle || !!this.immediateId; + }; + return MultistepOperation; + }()); var Session = (function () { function Session(host, cancellationToken, useSingleInferredProject, typingsInstaller, byteLength, hrtime, logger, canUseEvents, eventHandler) { var _this = this; this.host = host; + this.cancellationToken = cancellationToken; this.typingsInstaller = typingsInstaller; this.byteLength = byteLength; this.hrtime = hrtime; @@ -66966,12 +67078,12 @@ var ts; return _this.requiredResponse(_this.getSyntacticDiagnosticsSync(request.arguments)); }, _a[CommandNames.Geterr] = function (request) { - var geterrArgs = request.arguments; - return { response: _this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false }; + _this.errorCheck.startNew(function (next) { return _this.getDiagnostics(next, request.arguments.delay, request.arguments.files); }); + return _this.notRequired(); }, _a[CommandNames.GeterrForProject] = function (request) { - var _a = request.arguments, file = _a.file, delay = _a.delay; - return { response: _this.getDiagnosticsForProject(delay, file), responseRequired: false }; + _this.errorCheck.startNew(function (next) { return _this.getDiagnosticsForProject(next, request.arguments.delay, request.arguments.file); }); + return _this.notRequired(); }, _a[CommandNames.Change] = function (request) { _this.change(request.arguments); @@ -67053,17 +67165,35 @@ var ts; this.eventHander = canUseEvents ? eventHandler || (function (event) { return _this.defaultEventHandler(event); }) : undefined; + var multistepOperationHost = { + executeWithRequestId: function (requestId, action) { return _this.executeWithRequestId(requestId, action); }, + getCurrentRequestId: function () { return _this.currentRequestId; }, + getServerHost: function () { return _this.host; }, + logError: function (err, cmd) { return _this.logError(err, cmd); }, + sendRequestCompletedEvent: function (requestId) { return _this.sendRequestCompletedEvent(requestId); }, + isCancellationRequested: function () { return cancellationToken.isCancellationRequested(); } + }; + this.errorCheck = new MultistepOperation(multistepOperationHost); this.projectService = new server.ProjectService(host, logger, cancellationToken, useSingleInferredProject, typingsInstaller, this.eventHander); this.gcTimer = new server.GcTimer(host, 7000, logger); var _a; } + Session.prototype.sendRequestCompletedEvent = function (requestId) { + var event = { + seq: 0, + type: "event", + event: "requestCompleted", + body: { request_seq: requestId } + }; + this.send(event); + }; Session.prototype.defaultEventHandler = function (event) { var _this = this; switch (event.eventName) { case server.ContextEvent: - var _a = event.data, project = _a.project, fileName = _a.fileName; - this.projectService.logger.info("got context event, updating diagnostics for " + fileName); - this.updateErrorCheck([{ fileName: fileName, project: project }], this.changeSeq, function (n) { return n === _this.changeSeq; }, 100); + var _a = event.data, project_1 = _a.project, fileName_1 = _a.fileName; + this.projectService.logger.info("got context event, updating diagnostics for " + fileName_1); + this.errorCheck.startNew(function (next) { return _this.updateErrorCheck(next, [{ fileName: fileName_1, project: project_1 }], _this.changeSeq, function (n) { return n === _this.changeSeq; }, 100); }); break; case server.ConfigFileDiagEvent: var _b = event.data, triggerFile = _b.triggerFile, configFileName = _b.configFileName, diagnostics = _b.diagnostics; @@ -67116,7 +67246,7 @@ var ts; seq: 0, type: "event", event: eventName, - body: info, + body: info }; this.send(ev); }; @@ -67171,7 +67301,7 @@ var ts; } }, ms); }; - Session.prototype.updateErrorCheck = function (checkList, seq, matchSeq, ms, followMs, requireOpen) { + Session.prototype.updateErrorCheck = function (next, checkList, seq, matchSeq, ms, followMs, requireOpen) { var _this = this; if (ms === void 0) { ms = 1500; } if (followMs === void 0) { followMs = 200; } @@ -67179,13 +67309,6 @@ var ts; if (followMs > ms) { followMs = ms; } - if (this.errorTimer) { - this.host.clearTimeout(this.errorTimer); - } - if (this.immediateId) { - this.host.clearImmediate(this.immediateId); - this.immediateId = undefined; - } var index = 0; var checkOne = function () { if (matchSeq(seq)) { @@ -67193,21 +67316,17 @@ var ts; index++; if (checkSpec_1.project.containsFile(checkSpec_1.fileName, requireOpen)) { _this.syntacticCheck(checkSpec_1.fileName, checkSpec_1.project); - _this.immediateId = _this.host.setImmediate(function () { + next.immediate(function () { _this.semanticCheck(checkSpec_1.fileName, checkSpec_1.project); - _this.immediateId = undefined; if (checkList.length > index) { - _this.errorTimer = _this.host.setTimeout(checkOne, followMs); - } - else { - _this.errorTimer = undefined; + next.delay(followMs, checkOne); } }); } } }; if ((checkList.length > index) && (matchSeq(seq))) { - this.errorTimer = this.host.setTimeout(checkOne, ms); + next.delay(ms, checkOne); } }; Session.prototype.cleanProjects = function (caption, projects) { @@ -67807,7 +67926,7 @@ var ts; return helpItems; } }; - Session.prototype.getDiagnostics = function (delay, fileNames) { + Session.prototype.getDiagnostics = function (next, delay, fileNames) { var _this = this; var checkList = fileNames.reduce(function (accum, uncheckedFileName) { var fileName = server.toNormalizedPath(uncheckedFileName); @@ -67818,7 +67937,7 @@ var ts; return accum; }, []); if (checkList.length > 0) { - this.updateErrorCheck(checkList, this.changeSeq, function (n) { return n === _this.changeSeq; }, delay); + this.updateErrorCheck(next, checkList, this.changeSeq, function (n) { return n === _this.changeSeq; }, delay); } }; Session.prototype.change = function (args) { @@ -68025,7 +68144,7 @@ var ts; ? spans.map(function (span) { return _this.decorateSpan(span, scriptInfo); }) : spans; }; - Session.prototype.getDiagnosticsForProject = function (delay, fileName) { + Session.prototype.getDiagnosticsForProject = function (next, delay, fileName) { var _this = this; var _a = this.getProjectInfoWorker(fileName, undefined, true), fileNames = _a.fileNames, languageServiceDisabled = _a.languageServiceDisabled; if (languageServiceDisabled) { @@ -68057,7 +68176,7 @@ var ts; fileNamesInProject = highPriorityFiles.concat(mediumPriorityFiles).concat(lowPriorityFiles).concat(veryLowPriorityFiles); if (fileNamesInProject.length > 0) { var checkList = fileNamesInProject.map(function (fileName) { return ({ fileName: fileName, project: project }); }); - this.updateErrorCheck(checkList, this.changeSeq, function (n) { return n == _this.changeSeq; }, delay, 200, false); + this.updateErrorCheck(next, checkList, this.changeSeq, function (n) { return n == _this.changeSeq; }, delay, 200, false); } }; Session.prototype.getCanonicalFileName = function (fileName) { @@ -68078,10 +68197,29 @@ var ts; } this.handlers.set(command, handler); }; + Session.prototype.setCurrentRequest = function (requestId) { + ts.Debug.assert(this.currentRequestId === undefined); + this.currentRequestId = requestId; + this.cancellationToken.setRequest(requestId); + }; + Session.prototype.resetCurrentRequest = function (requestId) { + ts.Debug.assert(this.currentRequestId === requestId); + this.currentRequestId = undefined; + this.cancellationToken.resetRequest(requestId); + }; + Session.prototype.executeWithRequestId = function (requestId, f) { + try { + this.setCurrentRequest(requestId); + return f(); + } + finally { + this.resetCurrentRequest(requestId); + } + }; Session.prototype.executeCommand = function (request) { var handler = this.handlers.get(request.command); if (handler) { - return handler(request); + return this.executeWithRequestId(request.seq, function () { return handler(request); }); } else { this.logger.msg("Unrecognized JSON command: " + JSON.stringify(request), server.Msg.Err); @@ -69959,7 +70097,7 @@ var ts; this.compilerOptions.allowNonTsExtensions = true; this.compilerOptions.allowJs = true; } - else if (hasExplicitListOfFiles) { + else if (hasExplicitListOfFiles || this.compilerOptions.allowJs) { this.compilerOptions.allowNonTsExtensions = true; } this.setInternalCompilerOptionsForEmittingJsFiles(); diff --git a/lib/typescript.js b/lib/typescript.js index 81a8016c416..2637569891b 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -69700,13 +69700,27 @@ var ts; } } else if (sourceFile.languageVariant === 1 /* JSX */) { - if (kind === 26 /* LessThanToken */) { - isRightOfOpenTag = true; - location = contextToken; - } - else if (kind === 40 /* SlashToken */ && contextToken.parent.kind === 251 /* JsxClosingElement */) { - isStartingCloseTag = true; - location = contextToken; + switch (contextToken.parent.kind) { + case 251 /* JsxClosingElement */: + if (kind === 40 /* SlashToken */) { + isStartingCloseTag = true; + location = contextToken; + } + break; + case 193 /* BinaryExpression */: + if (!(contextToken.parent.left.flags & 32768 /* ThisNodeHasError */)) { + // It has a left-hand side, so we're not in an opening JSX tag. + break; + } + // fall through + case 249 /* JsxSelfClosingElement */: + case 248 /* JsxElement */: + case 250 /* JsxOpeningElement */: + if (kind === 26 /* LessThanToken */) { + isRightOfOpenTag = true; + location = contextToken; + } + break; } } } @@ -71441,21 +71455,23 @@ var ts; } function getAllReferencesForKeyword(sourceFiles, keywordKind, cancellationToken) { var name = ts.tokenToString(keywordKind); - var definition = { - containerKind: "", - containerName: "", - fileName: "", - kind: ts.ScriptElementKind.keyword, - name: name, - textSpan: ts.createTextSpan(0, 1), - displayParts: [{ text: name, kind: ts.ScriptElementKind.keyword }] - }; var references = []; for (var _i = 0, sourceFiles_6 = sourceFiles; _i < sourceFiles_6.length; _i++) { var sourceFile = sourceFiles_6[_i]; cancellationToken.throwIfCancellationRequested(); addReferencesForKeywordInFile(sourceFile, keywordKind, name, cancellationToken, references); } + if (!references.length) + return undefined; + var definition = { + containerKind: "", + containerName: "", + fileName: references[0].fileName, + kind: ts.ScriptElementKind.keyword, + name: name, + textSpan: references[0].textSpan, + displayParts: [{ text: name, kind: ts.ScriptElementKind.keyword }] + }; return [{ definition: definition, references: references }]; } function addReferencesForKeywordInFile(sourceFile, kind, searchText, cancellationToken, references) { @@ -79471,7 +79487,19 @@ var ts; return importDecl; } function createCodeFixToRemoveNode(node) { - return createCodeFix("", node.getStart(), node.getWidth()); + var end = node.getEnd(); + var endCharCode = sourceFile.text.charCodeAt(end); + var afterEndCharCode = sourceFile.text.charCodeAt(end + 1); + if (ts.isLineBreak(endCharCode)) { + end += 1; + } + // in the case of CR LF, you could have two consecutive new line characters for one new line. + // this needs to be differenciated from two LF LF chars that actually mean two new lines. + if (ts.isLineBreak(afterEndCharCode) && endCharCode !== afterEndCharCode) { + end += 1; + } + var start = node.getStart(); + return createCodeFix("", start, end - start); } function findFirstNonSpaceCharPosStarting(start) { while (ts.isWhiteSpace(sourceFile.text.charCodeAt(start))) { diff --git a/lib/typescriptServices.js b/lib/typescriptServices.js index 81a8016c416..2637569891b 100644 --- a/lib/typescriptServices.js +++ b/lib/typescriptServices.js @@ -69700,13 +69700,27 @@ var ts; } } else if (sourceFile.languageVariant === 1 /* JSX */) { - if (kind === 26 /* LessThanToken */) { - isRightOfOpenTag = true; - location = contextToken; - } - else if (kind === 40 /* SlashToken */ && contextToken.parent.kind === 251 /* JsxClosingElement */) { - isStartingCloseTag = true; - location = contextToken; + switch (contextToken.parent.kind) { + case 251 /* JsxClosingElement */: + if (kind === 40 /* SlashToken */) { + isStartingCloseTag = true; + location = contextToken; + } + break; + case 193 /* BinaryExpression */: + if (!(contextToken.parent.left.flags & 32768 /* ThisNodeHasError */)) { + // It has a left-hand side, so we're not in an opening JSX tag. + break; + } + // fall through + case 249 /* JsxSelfClosingElement */: + case 248 /* JsxElement */: + case 250 /* JsxOpeningElement */: + if (kind === 26 /* LessThanToken */) { + isRightOfOpenTag = true; + location = contextToken; + } + break; } } } @@ -71441,21 +71455,23 @@ var ts; } function getAllReferencesForKeyword(sourceFiles, keywordKind, cancellationToken) { var name = ts.tokenToString(keywordKind); - var definition = { - containerKind: "", - containerName: "", - fileName: "", - kind: ts.ScriptElementKind.keyword, - name: name, - textSpan: ts.createTextSpan(0, 1), - displayParts: [{ text: name, kind: ts.ScriptElementKind.keyword }] - }; var references = []; for (var _i = 0, sourceFiles_6 = sourceFiles; _i < sourceFiles_6.length; _i++) { var sourceFile = sourceFiles_6[_i]; cancellationToken.throwIfCancellationRequested(); addReferencesForKeywordInFile(sourceFile, keywordKind, name, cancellationToken, references); } + if (!references.length) + return undefined; + var definition = { + containerKind: "", + containerName: "", + fileName: references[0].fileName, + kind: ts.ScriptElementKind.keyword, + name: name, + textSpan: references[0].textSpan, + displayParts: [{ text: name, kind: ts.ScriptElementKind.keyword }] + }; return [{ definition: definition, references: references }]; } function addReferencesForKeywordInFile(sourceFile, kind, searchText, cancellationToken, references) { @@ -79471,7 +79487,19 @@ var ts; return importDecl; } function createCodeFixToRemoveNode(node) { - return createCodeFix("", node.getStart(), node.getWidth()); + var end = node.getEnd(); + var endCharCode = sourceFile.text.charCodeAt(end); + var afterEndCharCode = sourceFile.text.charCodeAt(end + 1); + if (ts.isLineBreak(endCharCode)) { + end += 1; + } + // in the case of CR LF, you could have two consecutive new line characters for one new line. + // this needs to be differenciated from two LF LF chars that actually mean two new lines. + if (ts.isLineBreak(afterEndCharCode) && endCharCode !== afterEndCharCode) { + end += 1; + } + var start = node.getStart(); + return createCodeFix("", start, end - start); } function findFirstNonSpaceCharPosStarting(start) { while (ts.isWhiteSpace(sourceFile.text.charCodeAt(start))) {