From 5d5187fbac04d91ce489883a3bd3cc03d3940f37 Mon Sep 17 00:00:00 2001 From: Basarat Syed Date: Fri, 24 Apr 2015 15:33:51 +1000 Subject: [PATCH] feat(typescript) bring in typescript source --- Gruntfile.js | 2 +- dist/globals.js | 2 - dist/linter.js | 3 + dist/main/atom/typescriptGrammar.js | 1 - dist/main/atomts.js | 2 + dist/main/lang/core/languageServiceHost2.js | 1 - dist/main/lang/core/project.js | 1 - dist/main/lang/fixmyts/addClassMember.js | 4 +- dist/main/lang/fixmyts/astUtils.js | 1 - dist/main/lang/modules/astToText.js | 1 - dist/main/lang/modules/building.js | 1 - dist/main/lang/modules/getExternalModules.js | 4 +- dist/main/lang/modules/programDependencies.js | 1 - dist/main/lang/projectService.js | 1 - dist/main/tsconfig/tsconfig.js | 1 - dist/typescript/compiler/binder.js | 519 + dist/typescript/compiler/checker.js | 10413 ++++++++++++ dist/typescript/compiler/commandLineParser.js | 361 + dist/typescript/compiler/core.js | 652 + .../typescript/compiler/declarationEmitter.js | 1300 ++ .../diagnosticInformationMap.generated.js | 541 + dist/typescript/compiler/emitter.js | 4184 +++++ dist/typescript/compiler/parser.js | 3733 +++++ dist/typescript/compiler/program.js | 488 + dist/typescript/compiler/scanner.js | 1245 ++ dist/typescript/compiler/sys.js | 252 + dist/typescript/compiler/tsc.js | 365 + dist/typescript/compiler/types.js | 596 + dist/typescript/compiler/utilities.js | 1523 ++ dist/typescript/makeTypeScriptGlobal.js | 50 + dist/typescript/readme.js | 0 dist/typescript/services/breakpoints.js | 364 + .../services/formatting/formatting.js | 747 + .../services/formatting/formattingContext.js | 79 + .../formatting/formattingRequestKind.js | 15 + .../services/formatting/formattingScanner.js | 184 + .../services/formatting/references.js | 12 + dist/typescript/services/formatting/rule.js | 22 + .../services/formatting/ruleAction.js | 14 + .../services/formatting/ruleDescriptor.js | 31 + .../services/formatting/ruleFlag.js | 12 + .../services/formatting/ruleOperation.js | 28 + .../formatting/ruleOperationContext.js | 34 + dist/typescript/services/formatting/rules.js | 378 + .../services/formatting/rulesMap.js | 137 + .../services/formatting/rulesProvider.js | 86 + .../services/formatting/smartIndenter.js | 307 + .../services/formatting/tokenRange.js | 115 + dist/typescript/services/navigateTo.js | 147 + dist/typescript/services/navigationBar.js | 370 + .../services/outliningElementsCollector.js | 151 + dist/typescript/services/patternMatcher.js | 451 + dist/typescript/services/services.js | 4804 ++++++ dist/typescript/services/shims.js | 563 + dist/typescript/services/signatureHelp.js | 315 + dist/typescript/services/utilities.js | 569 + dist/worker/child.js | 2 + lib/globals.ts | 2 - lib/linter.ts | 3 + lib/main/atom/autoCompleteProvider.ts | 1 - lib/main/atom/commands/commands.ts | 1 - lib/main/atom/debugAtomTs.ts | 1 - lib/main/atom/tooltipManager.ts | 1 - lib/main/atom/typescriptGrammar.ts | 1 - lib/main/atom/views/astView.ts | 1 - lib/main/atom/views/dependencyView.ts | 1 - lib/main/atom/views/fileSymbolsView.ts | 1 - lib/main/atom/views/projectSymbolsView.ts | 1 - lib/main/atomts.ts | 5 +- lib/main/lang/core/languageServiceHost2.ts | 1 - lib/main/lang/core/project.ts | 1 - lib/main/lang/fixmyts/addClassMember.ts | 4 +- lib/main/lang/fixmyts/astUtils.ts | 1 - lib/main/lang/fixmyts/equalsToEquals.ts | 11 +- lib/main/lang/fixmyts/quickFix.ts | 1 - lib/main/lang/fixmyts/quoteToTemplate.ts | 4 +- lib/main/lang/fixmyts/quotesToQuotes.ts | 4 +- lib/main/lang/modules/astToText.ts | 3 - lib/main/lang/modules/building.ts | 1 - lib/main/lang/modules/getExternalModules.ts | 12 +- lib/main/lang/modules/programDependencies.ts | 1 - lib/main/lang/projectService.ts | 3 +- lib/main/tsconfig/formatting.ts | 1 - lib/main/tsconfig/tsconfig.ts | 1 - lib/tsconfig.json | 41 +- lib/typescript/compiler/binder.ts | 618 + lib/typescript/compiler/checker.ts | 13164 ++++++++++++++++ lib/typescript/compiler/commandLineParser.ts | 388 + lib/typescript/compiler/core.ts | 740 + lib/typescript/compiler/declarationEmitter.ts | 1590 ++ .../diagnosticInformationMap.generated.ts | 542 + .../compiler/diagnosticMessages.json | 2146 +++ lib/typescript/compiler/emitter.ts | 5274 +++++++ lib/typescript/compiler/parser.ts | 5420 +++++++ lib/typescript/compiler/program.ts | 608 + lib/typescript/compiler/scanner.ts | 1505 ++ lib/typescript/compiler/sys.ts | 318 + lib/typescript/compiler/types.ts | 1898 +++ lib/typescript/compiler/utilities.ts | 1915 +++ lib/typescript/makeTypeScriptGlobal.ts | 61 + lib/typescript/readme.md | 22 + lib/typescript/services/breakpoints.ts | 529 + .../services/formatting/formatting.ts | 1114 ++ .../services/formatting/formattingContext.ts | 101 + .../formatting/formattingRequestKind.ts | 12 + .../services/formatting/formattingScanner.ts | 243 + .../services/formatting/references.ts | 12 + lib/typescript/services/formatting/rule.ts | 18 + .../services/formatting/ruleAction.ts | 11 + .../services/formatting/ruleDescriptor.ts | 30 + .../services/formatting/ruleFlag.ts | 10 + .../services/formatting/ruleOperation.ts | 30 + .../formatting/ruleOperationContext.ts | 33 + lib/typescript/services/formatting/rules.ts | 717 + .../services/formatting/rulesMap.ts | 175 + .../services/formatting/rulesProvider.ts | 103 + .../services/formatting/smartIndenter.ts | 404 + .../services/formatting/tokenRange.ts | 126 + lib/typescript/services/navigateTo.ts | 194 + lib/typescript/services/navigationBar.ts | 537 + .../services/outliningElementsCollector.ts | 180 + lib/typescript/services/patternMatcher.ts | 810 + lib/typescript/services/services.ts | 6904 ++++++++ lib/typescript/services/shims.ts | 918 ++ lib/typescript/services/signatureHelp.ts | 637 + lib/typescript/services/utilities.ts | 659 + lib/worker/child.ts | 4 + 127 files changed, 86947 insertions(+), 67 deletions(-) create mode 100644 dist/typescript/compiler/binder.js create mode 100644 dist/typescript/compiler/checker.js create mode 100644 dist/typescript/compiler/commandLineParser.js create mode 100644 dist/typescript/compiler/core.js create mode 100644 dist/typescript/compiler/declarationEmitter.js create mode 100644 dist/typescript/compiler/diagnosticInformationMap.generated.js create mode 100644 dist/typescript/compiler/emitter.js create mode 100644 dist/typescript/compiler/parser.js create mode 100644 dist/typescript/compiler/program.js create mode 100644 dist/typescript/compiler/scanner.js create mode 100644 dist/typescript/compiler/sys.js create mode 100644 dist/typescript/compiler/tsc.js create mode 100644 dist/typescript/compiler/types.js create mode 100644 dist/typescript/compiler/utilities.js create mode 100644 dist/typescript/makeTypeScriptGlobal.js create mode 100644 dist/typescript/readme.js create mode 100644 dist/typescript/services/breakpoints.js create mode 100644 dist/typescript/services/formatting/formatting.js create mode 100644 dist/typescript/services/formatting/formattingContext.js create mode 100644 dist/typescript/services/formatting/formattingRequestKind.js create mode 100644 dist/typescript/services/formatting/formattingScanner.js create mode 100644 dist/typescript/services/formatting/references.js create mode 100644 dist/typescript/services/formatting/rule.js create mode 100644 dist/typescript/services/formatting/ruleAction.js create mode 100644 dist/typescript/services/formatting/ruleDescriptor.js create mode 100644 dist/typescript/services/formatting/ruleFlag.js create mode 100644 dist/typescript/services/formatting/ruleOperation.js create mode 100644 dist/typescript/services/formatting/ruleOperationContext.js create mode 100644 dist/typescript/services/formatting/rules.js create mode 100644 dist/typescript/services/formatting/rulesMap.js create mode 100644 dist/typescript/services/formatting/rulesProvider.js create mode 100644 dist/typescript/services/formatting/smartIndenter.js create mode 100644 dist/typescript/services/formatting/tokenRange.js create mode 100644 dist/typescript/services/navigateTo.js create mode 100644 dist/typescript/services/navigationBar.js create mode 100644 dist/typescript/services/outliningElementsCollector.js create mode 100644 dist/typescript/services/patternMatcher.js create mode 100644 dist/typescript/services/services.js create mode 100644 dist/typescript/services/shims.js create mode 100644 dist/typescript/services/signatureHelp.js create mode 100644 dist/typescript/services/utilities.js create mode 100644 lib/typescript/compiler/binder.ts create mode 100644 lib/typescript/compiler/checker.ts create mode 100644 lib/typescript/compiler/commandLineParser.ts create mode 100644 lib/typescript/compiler/core.ts create mode 100644 lib/typescript/compiler/declarationEmitter.ts create mode 100644 lib/typescript/compiler/diagnosticInformationMap.generated.ts create mode 100644 lib/typescript/compiler/diagnosticMessages.json create mode 100644 lib/typescript/compiler/emitter.ts create mode 100644 lib/typescript/compiler/parser.ts create mode 100644 lib/typescript/compiler/program.ts create mode 100644 lib/typescript/compiler/scanner.ts create mode 100644 lib/typescript/compiler/sys.ts create mode 100644 lib/typescript/compiler/types.ts create mode 100644 lib/typescript/compiler/utilities.ts create mode 100644 lib/typescript/makeTypeScriptGlobal.ts create mode 100644 lib/typescript/readme.md create mode 100644 lib/typescript/services/breakpoints.ts create mode 100644 lib/typescript/services/formatting/formatting.ts create mode 100644 lib/typescript/services/formatting/formattingContext.ts create mode 100644 lib/typescript/services/formatting/formattingRequestKind.ts create mode 100644 lib/typescript/services/formatting/formattingScanner.ts create mode 100644 lib/typescript/services/formatting/references.ts create mode 100644 lib/typescript/services/formatting/rule.ts create mode 100644 lib/typescript/services/formatting/ruleAction.ts create mode 100644 lib/typescript/services/formatting/ruleDescriptor.ts create mode 100644 lib/typescript/services/formatting/ruleFlag.ts create mode 100644 lib/typescript/services/formatting/ruleOperation.ts create mode 100644 lib/typescript/services/formatting/ruleOperationContext.ts create mode 100644 lib/typescript/services/formatting/rules.ts create mode 100644 lib/typescript/services/formatting/rulesMap.ts create mode 100644 lib/typescript/services/formatting/rulesProvider.ts create mode 100644 lib/typescript/services/formatting/smartIndenter.ts create mode 100644 lib/typescript/services/formatting/tokenRange.ts create mode 100644 lib/typescript/services/navigateTo.ts create mode 100644 lib/typescript/services/navigationBar.ts create mode 100644 lib/typescript/services/outliningElementsCollector.ts create mode 100644 lib/typescript/services/patternMatcher.ts create mode 100644 lib/typescript/services/services.ts create mode 100644 lib/typescript/services/shims.ts create mode 100644 lib/typescript/services/signatureHelp.ts create mode 100644 lib/typescript/services/utilities.ts diff --git a/Gruntfile.js b/Gruntfile.js index 72307c001..7070a514d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -9,7 +9,7 @@ module.exports = function (grunt) { target: 'es5', module: 'commonjs', sourceMap: false, - preserveConstEnums: false, + preserveConstEnums: true, compiler: './node_modules/typescript/bin/tsc' }, dev: { diff --git a/dist/globals.js b/dist/globals.js index d3812f64a..8e7b82c4a 100644 --- a/dist/globals.js +++ b/dist/globals.js @@ -1,6 +1,4 @@ /// -/// -/// /// /// /// diff --git a/dist/linter.js b/dist/linter.js index 638b20e8c..f09c2441c 100644 --- a/dist/linter.js +++ b/dist/linter.js @@ -1,5 +1,8 @@ // This file is only called from linter // See : https://github.com/AtomLinter/Linter/issues/337 +/// ///ts:ref:generated +var makeTypeScriptGlobal_1 = require("./typescript/makeTypeScriptGlobal"); +makeTypeScriptGlobal_1.makeTsGlobal(); var parent = require('./worker/parent'); var fs = require('fs'); var linterPath = atom.packages.getLoadedPackage("linter").path; diff --git a/dist/main/atom/typescriptGrammar.js b/dist/main/atom/typescriptGrammar.js index 92495a9a4..f1b6e4dc2 100644 --- a/dist/main/atom/typescriptGrammar.js +++ b/dist/main/atom/typescriptGrammar.js @@ -6,7 +6,6 @@ var __extends = this.__extends || function (d, b) { __.prototype = b.prototype; d.prototype = new __(); }; -var ts = require('typescript'); var TokenClass = ts.TokenClass; global.AtomTSBaseGrammar = require(atom.config.resourcePath + "/node_modules/first-mate/lib/grammar.js"); var TypeScriptSemanticGrammar = (function (_super) { diff --git a/dist/main/atomts.js b/dist/main/atomts.js index 3aa894d5d..8451176e3 100644 --- a/dist/main/atomts.js +++ b/dist/main/atomts.js @@ -1,5 +1,7 @@ ///ts:ref=globals /// ///ts:ref:generated +var makeTypeScriptGlobal_1 = require("../typescript/makeTypeScriptGlobal"); +makeTypeScriptGlobal_1.makeTsGlobal(); var path = require('path'); var fs = require('fs'); var apd = require('atom-package-dependencies'); diff --git a/dist/main/lang/core/languageServiceHost2.js b/dist/main/lang/core/languageServiceHost2.js index 73e65a01a..41b8f6a59 100644 --- a/dist/main/lang/core/languageServiceHost2.js +++ b/dist/main/lang/core/languageServiceHost2.js @@ -1,4 +1,3 @@ -var ts = require('typescript'); var path = require('path'); var fs = require('fs'); var textBuffer = require('basarat-text-buffer'); diff --git a/dist/main/lang/core/project.js b/dist/main/lang/core/project.js index ba85ac2f8..fd0ee7481 100644 --- a/dist/main/lang/core/project.js +++ b/dist/main/lang/core/project.js @@ -1,6 +1,5 @@ ///ts:ref=globals /// ///ts:ref:generated -var ts = require('typescript'); exports.languageServiceHost = require('./languageServiceHost2'); var Project = (function () { function Project(projectFile) { diff --git a/dist/main/lang/fixmyts/addClassMember.js b/dist/main/lang/fixmyts/addClassMember.js index 870ae7cbf..cb71e203d 100644 --- a/dist/main/lang/fixmyts/addClassMember.js +++ b/dist/main/lang/fixmyts/addClassMember.js @@ -1,7 +1,5 @@ -var ts = require("typescript"); var ast = require("./astUtils"); var os_1 = require("os"); -var typescript_1 = require("typescript"); function getIdentifierAndClassNames(error) { var errorText = error.messageText; if (typeof errorText !== 'string') { @@ -42,7 +40,7 @@ var AddClassMember = (function () { && parentOfParent.operatorToken.getText().trim() == '=') { var binaryExpression = parentOfParent; var type = info.typeChecker.getTypeAtLocation(binaryExpression.right); - typeString = typescript_1.displayPartsToString(typescript_1.typeToDisplayParts(info.typeChecker, type)).replace(/\s+/g, ' '); + typeString = ts.displayPartsToString(ts.typeToDisplayParts(info.typeChecker, type)).replace(/\s+/g, ' '); } var memberTarget = ast.getNodeByKindAndName(info.program, 201, className); if (!memberTarget) { diff --git a/dist/main/lang/fixmyts/astUtils.js b/dist/main/lang/fixmyts/astUtils.js index e5888780f..06866d9eb 100644 --- a/dist/main/lang/fixmyts/astUtils.js +++ b/dist/main/lang/fixmyts/astUtils.js @@ -1,4 +1,3 @@ -var ts = require("typescript"); exports.forEachChild = ts.forEachChild; function forEachChildRecursive(node, cbNode, depth) { if (depth === void 0) { depth = 0; } diff --git a/dist/main/lang/modules/astToText.js b/dist/main/lang/modules/astToText.js index 54e436d17..b563bfe30 100644 --- a/dist/main/lang/modules/astToText.js +++ b/dist/main/lang/modules/astToText.js @@ -4,7 +4,6 @@ */ // Inspired by `ts.forEachChild`: // https://github.com/Microsoft/TypeScript/blob/65cbd91667acf890f21a3527b3647c7bc994ca32/src/compiler/parser.ts#L43-L320 -var ts = require("typescript"); function astToText(srcFile) { //// A useful function for debugging // aggregate(srcFile, 0); diff --git a/dist/main/lang/modules/building.js b/dist/main/lang/modules/building.js index 97010e478..79a32c62f 100644 --- a/dist/main/lang/modules/building.js +++ b/dist/main/lang/modules/building.js @@ -1,4 +1,3 @@ -var ts = require('typescript'); var mkdirp = require('mkdirp'); var path = require('path'); var fs = require('fs'); diff --git a/dist/main/lang/modules/getExternalModules.js b/dist/main/lang/modules/getExternalModules.js index e319c1fca..9559ade06 100644 --- a/dist/main/lang/modules/getExternalModules.js +++ b/dist/main/lang/modules/getExternalModules.js @@ -1,8 +1,8 @@ -var typescript_1 = require("typescript"); +// From https://github.com/Microsoft/TypeScript/pull/2173/files function getExternalModuleNames(program) { var entries = []; program.getSourceFiles().forEach(function (sourceFile) { - typescript_1.forEachChild(sourceFile, function (child) { + ts.forEachChild(sourceFile, function (child) { if (child.kind === 205 && child.name.kind === 8) { entries.push(child.name.text); } diff --git a/dist/main/lang/modules/programDependencies.js b/dist/main/lang/modules/programDependencies.js index 3288ca4a7..2ca1dd72a 100644 --- a/dist/main/lang/modules/programDependencies.js +++ b/dist/main/lang/modules/programDependencies.js @@ -1,5 +1,4 @@ var tsconfig_1 = require("../../tsconfig/tsconfig"); -var ts = require("typescript"); var path = require("path"); var fs = require("fs"); function getDependencies(projectFile, program) { diff --git a/dist/main/lang/projectService.js b/dist/main/lang/projectService.js index 1a8c7ce19..6b09c4656 100644 --- a/dist/main/lang/projectService.js +++ b/dist/main/lang/projectService.js @@ -2,7 +2,6 @@ /// ///ts:ref:generated var fs = require('fs'); var path = require('path'); -var ts = require('typescript'); var fuzzaldrin = require('fuzzaldrin'); var tsconfig = require('../tsconfig/tsconfig'); var utils = require('./utils'); diff --git a/dist/main/tsconfig/tsconfig.js b/dist/main/tsconfig/tsconfig.js index f915fe920..cb04182d4 100644 --- a/dist/main/tsconfig/tsconfig.js +++ b/dist/main/tsconfig/tsconfig.js @@ -49,7 +49,6 @@ function errorWithDetails(error, details) { var fs = require('fs'); var path = require('path'); var expand = require('glob-expand'); -var ts = require('typescript'); var os = require('os'); var formatting = require('./formatting'); var projectFileName = 'tsconfig.json'; diff --git a/dist/typescript/compiler/binder.js b/dist/typescript/compiler/binder.js new file mode 100644 index 000000000..37c48f5ba --- /dev/null +++ b/dist/typescript/compiler/binder.js @@ -0,0 +1,519 @@ +/// +var ts; +(function (ts) { + ts.bindTime = 0; + (function (ModuleInstanceState) { + ModuleInstanceState[ModuleInstanceState["NonInstantiated"] = 0] = "NonInstantiated"; + ModuleInstanceState[ModuleInstanceState["Instantiated"] = 1] = "Instantiated"; + ModuleInstanceState[ModuleInstanceState["ConstEnumOnly"] = 2] = "ConstEnumOnly"; + })(ts.ModuleInstanceState || (ts.ModuleInstanceState = {})); + var ModuleInstanceState = ts.ModuleInstanceState; + function getModuleInstanceState(node) { + if (node.kind === 202 || node.kind === 203) { + return 0; + } + else if (ts.isConstEnumDeclaration(node)) { + return 2; + } + else if ((node.kind === 209 || node.kind === 208) && !(node.flags & 1)) { + return 0; + } + else if (node.kind === 206) { + var state = 0; + ts.forEachChild(node, function (n) { + switch (getModuleInstanceState(n)) { + case 0: + return false; + case 2: + state = 2; + return false; + case 1: + state = 1; + return true; + } + }); + return state; + } + else if (node.kind === 205) { + return getModuleInstanceState(node.body); + } + else { + return 1; + } + } + ts.getModuleInstanceState = getModuleInstanceState; + function bindSourceFile(file) { + var start = new Date().getTime(); + bindSourceFileWorker(file); + ts.bindTime += new Date().getTime() - start; + } + ts.bindSourceFile = bindSourceFile; + function bindSourceFileWorker(file) { + var parent; + var container; + var blockScopeContainer; + var lastContainer; + var symbolCount = 0; + var Symbol = ts.objectAllocator.getSymbolConstructor(); + if (!file.locals) { + file.locals = {}; + container = file; + setBlockScopeContainer(file, false); + bind(file); + file.symbolCount = symbolCount; + } + function createSymbol(flags, name) { + symbolCount++; + return new Symbol(flags, name); + } + function setBlockScopeContainer(node, cleanLocals) { + blockScopeContainer = node; + if (cleanLocals) { + blockScopeContainer.locals = undefined; + } + } + function addDeclarationToSymbol(symbol, node, symbolKind) { + symbol.flags |= symbolKind; + if (!symbol.declarations) + symbol.declarations = []; + symbol.declarations.push(node); + if (symbolKind & 1952 && !symbol.exports) + symbol.exports = {}; + if (symbolKind & 6240 && !symbol.members) + symbol.members = {}; + node.symbol = symbol; + if (symbolKind & 107455 && !symbol.valueDeclaration) + symbol.valueDeclaration = node; + } + function getDeclarationName(node) { + if (node.name) { + if (node.kind === 205 && node.name.kind === 8) { + return '"' + node.name.text + '"'; + } + if (node.name.kind === 127) { + var nameExpression = node.name.expression; + ts.Debug.assert(ts.isWellKnownSymbolSyntactically(nameExpression)); + return ts.getPropertyNameForKnownSymbolName(nameExpression.name.text); + } + return node.name.text; + } + switch (node.kind) { + case 143: + case 135: + return "__constructor"; + case 142: + case 138: + return "__call"; + case 139: + return "__new"; + case 140: + return "__index"; + case 215: + return "__export"; + case 214: + return node.isExportEquals ? "export=" : "default"; + case 200: + case 201: + return node.flags & 256 ? "default" : undefined; + } + } + function getDisplayName(node) { + return node.name ? ts.declarationNameToString(node.name) : getDeclarationName(node); + } + function declareSymbol(symbols, parent, node, includes, excludes) { + ts.Debug.assert(!ts.hasDynamicName(node)); + var name = node.flags & 256 && parent ? "default" : getDeclarationName(node); + var symbol; + if (name !== undefined) { + symbol = ts.hasProperty(symbols, name) ? symbols[name] : (symbols[name] = createSymbol(0, name)); + if (symbol.flags & excludes) { + if (node.name) { + node.name.parent = node; + } + var message = symbol.flags & 2 + ? ts.Diagnostics.Cannot_redeclare_block_scoped_variable_0 + : ts.Diagnostics.Duplicate_identifier_0; + ts.forEach(symbol.declarations, function (declaration) { + file.bindDiagnostics.push(ts.createDiagnosticForNode(declaration.name || declaration, message, getDisplayName(declaration))); + }); + file.bindDiagnostics.push(ts.createDiagnosticForNode(node.name || node, message, getDisplayName(node))); + symbol = createSymbol(0, name); + } + } + else { + symbol = createSymbol(0, "__missing"); + } + addDeclarationToSymbol(symbol, node, includes); + symbol.parent = parent; + if ((node.kind === 201 || node.kind === 174) && symbol.exports) { + var prototypeSymbol = createSymbol(4 | 134217728, "prototype"); + if (ts.hasProperty(symbol.exports, prototypeSymbol.name)) { + if (node.name) { + node.name.parent = node; + } + file.bindDiagnostics.push(ts.createDiagnosticForNode(symbol.exports[prototypeSymbol.name].declarations[0], ts.Diagnostics.Duplicate_identifier_0, prototypeSymbol.name)); + } + symbol.exports[prototypeSymbol.name] = prototypeSymbol; + prototypeSymbol.parent = symbol; + } + return symbol; + } + function declareModuleMember(node, symbolKind, symbolExcludes) { + var hasExportModifier = ts.getCombinedNodeFlags(node) & 1; + if (symbolKind & 8388608) { + if (node.kind === 217 || (node.kind === 208 && hasExportModifier)) { + declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes); + } + else { + declareSymbol(container.locals, undefined, node, symbolKind, symbolExcludes); + } + } + else { + if (hasExportModifier || container.flags & 32768) { + var exportKind = (symbolKind & 107455 ? 1048576 : 0) | + (symbolKind & 793056 ? 2097152 : 0) | + (symbolKind & 1536 ? 4194304 : 0); + var local = declareSymbol(container.locals, undefined, node, exportKind, symbolExcludes); + local.exportSymbol = declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes); + node.localSymbol = local; + } + else { + declareSymbol(container.locals, undefined, node, symbolKind, symbolExcludes); + } + } + } + function bindChildren(node, symbolKind, isBlockScopeContainer) { + if (symbolKind & 255504) { + node.locals = {}; + } + var saveParent = parent; + var saveContainer = container; + var savedBlockScopeContainer = blockScopeContainer; + parent = node; + if (symbolKind & 262128) { + container = node; + addToContainerChain(container); + } + if (isBlockScopeContainer) { + setBlockScopeContainer(node, (symbolKind & 255504) === 0 && node.kind !== 227); + } + ts.forEachChild(node, bind); + container = saveContainer; + parent = saveParent; + blockScopeContainer = savedBlockScopeContainer; + } + function addToContainerChain(node) { + if (lastContainer) { + lastContainer.nextContainer = node; + } + lastContainer = node; + } + function bindDeclaration(node, symbolKind, symbolExcludes, isBlockScopeContainer) { + switch (container.kind) { + case 205: + declareModuleMember(node, symbolKind, symbolExcludes); + break; + case 227: + if (ts.isExternalModule(container)) { + declareModuleMember(node, symbolKind, symbolExcludes); + break; + } + case 142: + case 143: + case 138: + case 139: + case 140: + case 134: + case 133: + case 135: + case 136: + case 137: + case 200: + case 162: + case 163: + declareSymbol(container.locals, undefined, node, symbolKind, symbolExcludes); + break; + case 174: + case 201: + if (node.flags & 128) { + declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes); + break; + } + case 145: + case 154: + case 202: + declareSymbol(container.symbol.members, container.symbol, node, symbolKind, symbolExcludes); + break; + case 204: + declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes); + break; + } + bindChildren(node, symbolKind, isBlockScopeContainer); + } + function isAmbientContext(node) { + while (node) { + if (node.flags & 2) + return true; + node = node.parent; + } + return false; + } + function hasExportDeclarations(node) { + var body = node.kind === 227 ? node : node.body; + if (body.kind === 227 || body.kind === 206) { + for (var _i = 0, _a = body.statements; _i < _a.length; _i++) { + var stat = _a[_i]; + if (stat.kind === 215 || stat.kind === 214) { + return true; + } + } + } + return false; + } + function setExportContextFlag(node) { + if (isAmbientContext(node) && !hasExportDeclarations(node)) { + node.flags |= 32768; + } + else { + node.flags &= ~32768; + } + } + function bindModuleDeclaration(node) { + setExportContextFlag(node); + if (node.name.kind === 8) { + bindDeclaration(node, 512, 106639, true); + } + else { + var state = getModuleInstanceState(node); + if (state === 0) { + bindDeclaration(node, 1024, 0, true); + } + else { + bindDeclaration(node, 512, 106639, true); + var currentModuleIsConstEnumOnly = state === 2; + if (node.symbol.constEnumOnlyModule === undefined) { + node.symbol.constEnumOnlyModule = currentModuleIsConstEnumOnly; + } + else { + node.symbol.constEnumOnlyModule = node.symbol.constEnumOnlyModule && currentModuleIsConstEnumOnly; + } + } + } + } + function bindFunctionOrConstructorType(node) { + // For a given function symbol "<...>(...) => T" we want to generate a symbol identical + // to the one we would get for: { <...>(...): T } + // + // We do that by making an anonymous type literal symbol, and then setting the function + // symbol as its sole member. To the rest of the system, this symbol will be indistinguishable + // from an actual type literal symbol you would have gotten had you used the long form. + var symbol = createSymbol(131072, getDeclarationName(node)); + addDeclarationToSymbol(symbol, node, 131072); + bindChildren(node, 131072, false); + var typeLiteralSymbol = createSymbol(2048, "__type"); + addDeclarationToSymbol(typeLiteralSymbol, node, 2048); + typeLiteralSymbol.members = {}; + typeLiteralSymbol.members[node.kind === 142 ? "__call" : "__new"] = symbol; + } + function bindAnonymousDeclaration(node, symbolKind, name, isBlockScopeContainer) { + var symbol = createSymbol(symbolKind, name); + addDeclarationToSymbol(symbol, node, symbolKind); + bindChildren(node, symbolKind, isBlockScopeContainer); + } + function bindCatchVariableDeclaration(node) { + bindChildren(node, 0, true); + } + function bindBlockScopedDeclaration(node, symbolKind, symbolExcludes) { + switch (blockScopeContainer.kind) { + case 205: + declareModuleMember(node, symbolKind, symbolExcludes); + break; + case 227: + if (ts.isExternalModule(container)) { + declareModuleMember(node, symbolKind, symbolExcludes); + break; + } + default: + if (!blockScopeContainer.locals) { + blockScopeContainer.locals = {}; + addToContainerChain(blockScopeContainer); + } + declareSymbol(blockScopeContainer.locals, undefined, node, symbolKind, symbolExcludes); + } + bindChildren(node, symbolKind, false); + } + function bindBlockScopedVariableDeclaration(node) { + bindBlockScopedDeclaration(node, 2, 107455); + } + function getDestructuringParameterName(node) { + return "__" + ts.indexOf(node.parent.parameters, node); + } + function bind(node) { + node.parent = parent; + switch (node.kind) { + case 128: + bindDeclaration(node, 262144, 530912, false); + break; + case 129: + bindParameter(node); + break; + case 198: + case 152: + if (ts.isBindingPattern(node.name)) { + bindChildren(node, 0, false); + } + else if (ts.isBlockOrCatchScoped(node)) { + bindBlockScopedVariableDeclaration(node); + } + else { + bindDeclaration(node, 1, 107454, false); + } + break; + case 132: + case 131: + bindPropertyOrMethodOrAccessor(node, 4 | (node.questionToken ? 536870912 : 0), 107455, false); + break; + case 224: + case 225: + bindPropertyOrMethodOrAccessor(node, 4, 107455, false); + break; + case 226: + bindPropertyOrMethodOrAccessor(node, 8, 107455, false); + break; + case 138: + case 139: + case 140: + bindDeclaration(node, 131072, 0, false); + break; + case 134: + case 133: + bindPropertyOrMethodOrAccessor(node, 8192 | (node.questionToken ? 536870912 : 0), ts.isObjectLiteralMethod(node) ? 107455 : 99263, true); + break; + case 200: + bindDeclaration(node, 16, 106927, true); + break; + case 135: + bindDeclaration(node, 16384, 0, true); + break; + case 136: + bindPropertyOrMethodOrAccessor(node, 32768, 41919, true); + break; + case 137: + bindPropertyOrMethodOrAccessor(node, 65536, 74687, true); + break; + case 142: + case 143: + bindFunctionOrConstructorType(node); + break; + case 145: + bindAnonymousDeclaration(node, 2048, "__type", false); + break; + case 154: + bindAnonymousDeclaration(node, 4096, "__object", false); + break; + case 162: + case 163: + bindAnonymousDeclaration(node, 16, "__function", true); + break; + case 174: + bindAnonymousDeclaration(node, 32, "__class", false); + break; + case 223: + bindCatchVariableDeclaration(node); + break; + case 201: + bindBlockScopedDeclaration(node, 32, 899583); + break; + case 202: + bindDeclaration(node, 64, 792992, false); + break; + case 203: + bindDeclaration(node, 524288, 793056, false); + break; + case 204: + if (ts.isConst(node)) { + bindDeclaration(node, 128, 899967, false); + } + else { + bindDeclaration(node, 256, 899327, false); + } + break; + case 205: + bindModuleDeclaration(node); + break; + case 208: + case 211: + case 213: + case 217: + bindDeclaration(node, 8388608, 8388608, false); + break; + case 210: + if (node.name) { + bindDeclaration(node, 8388608, 8388608, false); + } + else { + bindChildren(node, 0, false); + } + break; + case 215: + if (!node.exportClause) { + declareSymbol(container.symbol.exports, container.symbol, node, 1073741824, 0); + } + bindChildren(node, 0, false); + break; + case 214: + if (node.expression.kind === 65) { + declareSymbol(container.symbol.exports, container.symbol, node, 8388608, 107455 | 8388608); + } + else { + declareSymbol(container.symbol.exports, container.symbol, node, 4, 107455 | 8388608); + } + bindChildren(node, 0, false); + break; + case 227: + setExportContextFlag(node); + if (ts.isExternalModule(node)) { + bindAnonymousDeclaration(node, 512, '"' + ts.removeFileExtension(node.fileName) + '"', true); + break; + } + case 179: + bindChildren(node, 0, !ts.isFunctionLike(node.parent)); + break; + case 223: + case 186: + case 187: + case 188: + case 207: + bindChildren(node, 0, true); + break; + default: + var saveParent = parent; + parent = node; + ts.forEachChild(node, bind); + parent = saveParent; + } + } + function bindParameter(node) { + if (ts.isBindingPattern(node.name)) { + bindAnonymousDeclaration(node, 1, getDestructuringParameterName(node), false); + } + else { + bindDeclaration(node, 1, 107455, false); + } + if (node.flags & 112 && + node.parent.kind === 135 && + (node.parent.parent.kind === 201 || node.parent.parent.kind === 174)) { + var classDeclaration = node.parent.parent; + declareSymbol(classDeclaration.symbol.members, classDeclaration.symbol, node, 4, 107455); + } + } + function bindPropertyOrMethodOrAccessor(node, symbolKind, symbolExcludes, isBlockScopeContainer) { + if (ts.hasDynamicName(node)) { + bindAnonymousDeclaration(node, symbolKind, "__computed", isBlockScopeContainer); + } + else { + bindDeclaration(node, symbolKind, symbolExcludes, isBlockScopeContainer); + } + } + } +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/checker.js b/dist/typescript/compiler/checker.js new file mode 100644 index 000000000..258cbe234 --- /dev/null +++ b/dist/typescript/compiler/checker.js @@ -0,0 +1,10413 @@ +/// +var ts; +(function (ts) { + var nextSymbolId = 1; + var nextNodeId = 1; + var nextMergeId = 1; + function getNodeId(node) { + if (!node.id) + node.id = nextNodeId++; + return node.id; + } + ts.getNodeId = getNodeId; + ts.checkTime = 0; + function getSymbolId(symbol) { + if (!symbol.id) { + symbol.id = nextSymbolId++; + } + return symbol.id; + } + ts.getSymbolId = getSymbolId; + function createTypeChecker(host, produceDiagnostics) { + var Symbol = ts.objectAllocator.getSymbolConstructor(); + var Type = ts.objectAllocator.getTypeConstructor(); + var Signature = ts.objectAllocator.getSignatureConstructor(); + var typeCount = 0; + var emptyArray = []; + var emptySymbols = {}; + var compilerOptions = host.getCompilerOptions(); + var languageVersion = compilerOptions.target || 0; + var emitResolver = createResolver(); + var undefinedSymbol = createSymbol(4 | 67108864, "undefined"); + var argumentsSymbol = createSymbol(4 | 67108864, "arguments"); + var checker = { + getNodeCount: function () { return ts.sum(host.getSourceFiles(), "nodeCount"); }, + getIdentifierCount: function () { return ts.sum(host.getSourceFiles(), "identifierCount"); }, + getSymbolCount: function () { return ts.sum(host.getSourceFiles(), "symbolCount"); }, + getTypeCount: function () { return typeCount; }, + isUndefinedSymbol: function (symbol) { return symbol === undefinedSymbol; }, + isArgumentsSymbol: function (symbol) { return symbol === argumentsSymbol; }, + getDiagnostics: getDiagnostics, + getGlobalDiagnostics: getGlobalDiagnostics, + getTypeOfSymbolAtLocation: getTypeOfSymbolAtLocation, + getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol, + getPropertiesOfType: getPropertiesOfType, + getPropertyOfType: getPropertyOfType, + getSignaturesOfType: getSignaturesOfType, + getIndexTypeOfType: getIndexTypeOfType, + getReturnTypeOfSignature: getReturnTypeOfSignature, + getSymbolsInScope: getSymbolsInScope, + getSymbolAtLocation: getSymbolAtLocation, + getShorthandAssignmentValueSymbol: getShorthandAssignmentValueSymbol, + getTypeAtLocation: getTypeAtLocation, + typeToString: typeToString, + getSymbolDisplayBuilder: getSymbolDisplayBuilder, + symbolToString: symbolToString, + getAugmentedPropertiesOfType: getAugmentedPropertiesOfType, + getRootSymbols: getRootSymbols, + getContextualType: getContextualType, + getFullyQualifiedName: getFullyQualifiedName, + getResolvedSignature: getResolvedSignature, + getConstantValue: getConstantValue, + isValidPropertyAccess: isValidPropertyAccess, + getSignatureFromDeclaration: getSignatureFromDeclaration, + isImplementationOfOverload: isImplementationOfOverload, + getAliasedSymbol: resolveAlias, + getEmitResolver: getEmitResolver, + getExportsOfModule: getExportsOfModuleAsArray, + }; + var unknownSymbol = createSymbol(4 | 67108864, "unknown"); + var resolvingSymbol = createSymbol(67108864, "__resolving__"); + var anyType = createIntrinsicType(1, "any"); + var stringType = createIntrinsicType(2, "string"); + var numberType = createIntrinsicType(4, "number"); + var booleanType = createIntrinsicType(8, "boolean"); + var esSymbolType = createIntrinsicType(1048576, "symbol"); + var voidType = createIntrinsicType(16, "void"); + var undefinedType = createIntrinsicType(32 | 262144, "undefined"); + var nullType = createIntrinsicType(64 | 262144, "null"); + var unknownType = createIntrinsicType(1, "unknown"); + var resolvingType = createIntrinsicType(1, "__resolving__"); + var emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + var anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + var noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + var anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, false, false); + var unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, false, false); + var globals = {}; + var globalArraySymbol; + var globalESSymbolConstructorSymbol; + var globalObjectType; + var globalFunctionType; + var globalArrayType; + var globalStringType; + var globalNumberType; + var globalBooleanType; + var globalRegExpType; + var globalTemplateStringsArrayType; + var globalESSymbolType; + var globalIterableType; + var anyArrayType; + var getGlobalClassDecoratorType; + var getGlobalParameterDecoratorType; + var getGlobalPropertyDecoratorType; + var getGlobalMethodDecoratorType; + var tupleTypes = {}; + var unionTypes = {}; + var stringLiteralTypes = {}; + var emitExtends = false; + var emitDecorate = false; + var emitParam = false; + var mergedSymbols = []; + var symbolLinks = []; + var nodeLinks = []; + var potentialThisCollisions = []; + var diagnostics = ts.createDiagnosticCollection(); + var primitiveTypeInfo = { + "string": { + type: stringType, + flags: 258 + }, + "number": { + type: numberType, + flags: 132 + }, + "boolean": { + type: booleanType, + flags: 8 + }, + "symbol": { + type: esSymbolType, + flags: 1048576 + } + }; + function getEmitResolver(sourceFile) { + getDiagnostics(sourceFile); + return emitResolver; + } + function error(location, message, arg0, arg1, arg2) { + var diagnostic = location + ? ts.createDiagnosticForNode(location, message, arg0, arg1, arg2) + : ts.createCompilerDiagnostic(message, arg0, arg1, arg2); + diagnostics.add(diagnostic); + } + function createSymbol(flags, name) { + return new Symbol(flags, name); + } + function getExcludedSymbolFlags(flags) { + var result = 0; + if (flags & 2) + result |= 107455; + if (flags & 1) + result |= 107454; + if (flags & 4) + result |= 107455; + if (flags & 8) + result |= 107455; + if (flags & 16) + result |= 106927; + if (flags & 32) + result |= 899583; + if (flags & 64) + result |= 792992; + if (flags & 256) + result |= 899327; + if (flags & 128) + result |= 899967; + if (flags & 512) + result |= 106639; + if (flags & 8192) + result |= 99263; + if (flags & 32768) + result |= 41919; + if (flags & 65536) + result |= 74687; + if (flags & 262144) + result |= 530912; + if (flags & 524288) + result |= 793056; + if (flags & 8388608) + result |= 8388608; + return result; + } + function recordMergedSymbol(target, source) { + if (!source.mergeId) + source.mergeId = nextMergeId++; + mergedSymbols[source.mergeId] = target; + } + function cloneSymbol(symbol) { + var result = createSymbol(symbol.flags | 33554432, symbol.name); + result.declarations = symbol.declarations.slice(0); + result.parent = symbol.parent; + if (symbol.valueDeclaration) + result.valueDeclaration = symbol.valueDeclaration; + if (symbol.constEnumOnlyModule) + result.constEnumOnlyModule = true; + if (symbol.members) + result.members = cloneSymbolTable(symbol.members); + if (symbol.exports) + result.exports = cloneSymbolTable(symbol.exports); + recordMergedSymbol(result, symbol); + return result; + } + function mergeSymbol(target, source) { + if (!(target.flags & getExcludedSymbolFlags(source.flags))) { + if (source.flags & 512 && target.flags & 512 && target.constEnumOnlyModule && !source.constEnumOnlyModule) { + target.constEnumOnlyModule = false; + } + target.flags |= source.flags; + if (!target.valueDeclaration && source.valueDeclaration) + target.valueDeclaration = source.valueDeclaration; + ts.forEach(source.declarations, function (node) { + target.declarations.push(node); + }); + if (source.members) { + if (!target.members) + target.members = {}; + mergeSymbolTable(target.members, source.members); + } + if (source.exports) { + if (!target.exports) + target.exports = {}; + mergeSymbolTable(target.exports, source.exports); + } + recordMergedSymbol(target, source); + } + else { + var message = target.flags & 2 || source.flags & 2 + ? ts.Diagnostics.Cannot_redeclare_block_scoped_variable_0 : ts.Diagnostics.Duplicate_identifier_0; + ts.forEach(source.declarations, function (node) { + error(node.name ? node.name : node, message, symbolToString(source)); + }); + ts.forEach(target.declarations, function (node) { + error(node.name ? node.name : node, message, symbolToString(source)); + }); + } + } + function cloneSymbolTable(symbolTable) { + var result = {}; + for (var id in symbolTable) { + if (ts.hasProperty(symbolTable, id)) { + result[id] = symbolTable[id]; + } + } + return result; + } + function mergeSymbolTable(target, source) { + for (var id in source) { + if (ts.hasProperty(source, id)) { + if (!ts.hasProperty(target, id)) { + target[id] = source[id]; + } + else { + var symbol = target[id]; + if (!(symbol.flags & 33554432)) { + target[id] = symbol = cloneSymbol(symbol); + } + mergeSymbol(symbol, source[id]); + } + } + } + } + function getSymbolLinks(symbol) { + if (symbol.flags & 67108864) + return symbol; + var id = getSymbolId(symbol); + return symbolLinks[id] || (symbolLinks[id] = {}); + } + function getNodeLinks(node) { + var nodeId = getNodeId(node); + return nodeLinks[nodeId] || (nodeLinks[nodeId] = {}); + } + function getSourceFile(node) { + return ts.getAncestor(node, 227); + } + function isGlobalSourceFile(node) { + return node.kind === 227 && !ts.isExternalModule(node); + } + function getSymbol(symbols, name, meaning) { + if (meaning && ts.hasProperty(symbols, name)) { + var symbol = symbols[name]; + ts.Debug.assert((symbol.flags & 16777216) === 0, "Should never get an instantiated symbol here."); + if (symbol.flags & meaning) { + return symbol; + } + if (symbol.flags & 8388608) { + var target = resolveAlias(symbol); + if (target === unknownSymbol || target.flags & meaning) { + return symbol; + } + } + } + } + function isDefinedBefore(node1, node2) { + var file1 = ts.getSourceFileOfNode(node1); + var file2 = ts.getSourceFileOfNode(node2); + if (file1 === file2) { + return node1.pos <= node2.pos; + } + if (!compilerOptions.out) { + return true; + } + var sourceFiles = host.getSourceFiles(); + return sourceFiles.indexOf(file1) <= sourceFiles.indexOf(file2); + } + function resolveName(location, name, meaning, nameNotFoundMessage, nameArg) { + var result; + var lastLocation; + var propertyWithInvalidInitializer; + var errorLocation = location; + var grandparent; + loop: while (location) { + if (location.locals && !isGlobalSourceFile(location)) { + if (result = getSymbol(location.locals, name, meaning)) { + break loop; + } + } + switch (location.kind) { + case 227: + if (!ts.isExternalModule(location)) + break; + case 205: + if (result = getSymbol(getSymbolOfNode(location).exports, name, meaning & 8914931)) { + if (result.flags & meaning || !(result.flags & 8388608 && getDeclarationOfAliasSymbol(result).kind === 217)) { + break loop; + } + result = undefined; + } + else if (location.kind === 227 || + (location.kind === 205 && location.name.kind === 8)) { + result = getSymbol(getSymbolOfNode(location).exports, "default", meaning & 8914931); + var localSymbol = ts.getLocalSymbolForExportDefault(result); + if (result && (result.flags & meaning) && localSymbol && localSymbol.name === name) { + break loop; + } + result = undefined; + } + break; + case 204: + if (result = getSymbol(getSymbolOfNode(location).exports, name, meaning & 8)) { + break loop; + } + break; + case 132: + case 131: + if (location.parent.kind === 201 && !(location.flags & 128)) { + var ctor = findConstructorDeclaration(location.parent); + if (ctor && ctor.locals) { + if (getSymbol(ctor.locals, name, meaning & 107455)) { + propertyWithInvalidInitializer = location; + } + } + } + break; + case 201: + case 202: + if (result = getSymbol(getSymbolOfNode(location).members, name, meaning & 793056)) { + if (lastLocation && lastLocation.flags & 128) { + error(errorLocation, ts.Diagnostics.Static_members_cannot_reference_class_type_parameters); + return undefined; + } + break loop; + } + break; + case 127: + grandparent = location.parent.parent; + if (grandparent.kind === 201 || grandparent.kind === 202) { + if (result = getSymbol(getSymbolOfNode(grandparent).members, name, meaning & 793056)) { + error(errorLocation, ts.Diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type); + return undefined; + } + } + break; + case 134: + case 133: + case 135: + case 136: + case 137: + case 200: + case 163: + if (name === "arguments") { + result = argumentsSymbol; + break loop; + } + break; + case 162: + if (name === "arguments") { + result = argumentsSymbol; + break loop; + } + var functionName = location.name; + if (functionName && name === functionName.text) { + result = location.symbol; + break loop; + } + break; + case 174: + var className = location.name; + if (className && name === className.text) { + result = location.symbol; + break loop; + } + break; + case 130: + if (location.parent && location.parent.kind === 129) { + location = location.parent; + } + if (location.parent && ts.isClassElement(location.parent)) { + location = location.parent; + } + break; + } + lastLocation = location; + location = location.parent; + } + if (!result) { + result = getSymbol(globals, name, meaning); + } + if (!result) { + if (nameNotFoundMessage) { + error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : ts.declarationNameToString(nameArg)); + } + return undefined; + } + if (nameNotFoundMessage) { + if (propertyWithInvalidInitializer) { + var propertyName = propertyWithInvalidInitializer.name; + error(errorLocation, ts.Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor, ts.declarationNameToString(propertyName), typeof nameArg === "string" ? nameArg : ts.declarationNameToString(nameArg)); + return undefined; + } + if (result.flags & 2) { + checkResolvedBlockScopedVariable(result, errorLocation); + } + } + return result; + } + function checkResolvedBlockScopedVariable(result, errorLocation) { + ts.Debug.assert((result.flags & 2) !== 0); + var declaration = ts.forEach(result.declarations, function (d) { return ts.isBlockOrCatchScoped(d) ? d : undefined; }); + ts.Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined"); + var isUsedBeforeDeclaration = !isDefinedBefore(declaration, errorLocation); + if (!isUsedBeforeDeclaration) { + var variableDeclaration = ts.getAncestor(declaration, 198); + var container = ts.getEnclosingBlockScopeContainer(variableDeclaration); + if (variableDeclaration.parent.parent.kind === 180 || + variableDeclaration.parent.parent.kind === 186) { + isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, variableDeclaration, container); + } + else if (variableDeclaration.parent.parent.kind === 188 || + variableDeclaration.parent.parent.kind === 187) { + var expression = variableDeclaration.parent.parent.expression; + isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, expression, container); + } + } + if (isUsedBeforeDeclaration) { + error(errorLocation, ts.Diagnostics.Block_scoped_variable_0_used_before_its_declaration, ts.declarationNameToString(declaration.name)); + } + } + function isSameScopeDescendentOf(initial, parent, stopAt) { + if (!parent) { + return false; + } + for (var current = initial; current && current !== stopAt && !ts.isFunctionLike(current); current = current.parent) { + if (current === parent) { + return true; + } + } + return false; + } + function getAnyImportSyntax(node) { + if (ts.isAliasSymbolDeclaration(node)) { + if (node.kind === 208) { + return node; + } + while (node && node.kind !== 209) { + node = node.parent; + } + return node; + } + } + function getDeclarationOfAliasSymbol(symbol) { + return ts.forEach(symbol.declarations, function (d) { return ts.isAliasSymbolDeclaration(d) ? d : undefined; }); + } + function getTargetOfImportEqualsDeclaration(node) { + if (node.moduleReference.kind === 219) { + return resolveExternalModuleSymbol(resolveExternalModuleName(node, ts.getExternalModuleImportEqualsDeclarationExpression(node))); + } + return getSymbolOfPartOfRightHandSideOfImportEquals(node.moduleReference, node); + } + function getTargetOfImportClause(node) { + var moduleSymbol = resolveExternalModuleName(node, node.parent.moduleSpecifier); + if (moduleSymbol) { + var exportDefaultSymbol = resolveSymbol(moduleSymbol.exports["default"]); + if (!exportDefaultSymbol) { + error(node.name, ts.Diagnostics.External_module_0_has_no_default_export, symbolToString(moduleSymbol)); + } + return exportDefaultSymbol; + } + } + function getTargetOfNamespaceImport(node) { + var moduleSpecifier = node.parent.parent.moduleSpecifier; + return resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier); + } + function getMemberOfModuleVariable(moduleSymbol, name) { + if (moduleSymbol.flags & 3) { + var typeAnnotation = moduleSymbol.valueDeclaration.type; + if (typeAnnotation) { + return getPropertyOfType(getTypeFromTypeNode(typeAnnotation), name); + } + } + } + function combineValueAndTypeSymbols(valueSymbol, typeSymbol) { + if (valueSymbol.flags & (793056 | 1536)) { + return valueSymbol; + } + var result = createSymbol(valueSymbol.flags | typeSymbol.flags, valueSymbol.name); + result.declarations = ts.concatenate(valueSymbol.declarations, typeSymbol.declarations); + result.parent = valueSymbol.parent || typeSymbol.parent; + if (valueSymbol.valueDeclaration) + result.valueDeclaration = valueSymbol.valueDeclaration; + if (typeSymbol.members) + result.members = typeSymbol.members; + if (valueSymbol.exports) + result.exports = valueSymbol.exports; + return result; + } + function getExportOfModule(symbol, name) { + if (symbol.flags & 1536) { + var exports_1 = getExportsOfSymbol(symbol); + if (ts.hasProperty(exports_1, name)) { + return resolveSymbol(exports_1[name]); + } + } + } + function getPropertyOfVariable(symbol, name) { + if (symbol.flags & 3) { + var typeAnnotation = symbol.valueDeclaration.type; + if (typeAnnotation) { + return resolveSymbol(getPropertyOfType(getTypeFromTypeNode(typeAnnotation), name)); + } + } + } + function getExternalModuleMember(node, specifier) { + var moduleSymbol = resolveExternalModuleName(node, node.moduleSpecifier); + var targetSymbol = resolveESModuleSymbol(moduleSymbol, node.moduleSpecifier); + if (targetSymbol) { + var name_1 = specifier.propertyName || specifier.name; + if (name_1.text) { + var symbolFromModule = getExportOfModule(targetSymbol, name_1.text); + var symbolFromVariable = getPropertyOfVariable(targetSymbol, name_1.text); + var symbol = symbolFromModule && symbolFromVariable ? + combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) : + symbolFromModule || symbolFromVariable; + if (!symbol) { + error(name_1, ts.Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(moduleSymbol), ts.declarationNameToString(name_1)); + } + return symbol; + } + } + } + function getTargetOfImportSpecifier(node) { + return getExternalModuleMember(node.parent.parent.parent, node); + } + function getTargetOfExportSpecifier(node) { + return node.parent.parent.moduleSpecifier ? + getExternalModuleMember(node.parent.parent, node) : + resolveEntityName(node.propertyName || node.name, 107455 | 793056 | 1536); + } + function getTargetOfExportAssignment(node) { + return resolveEntityName(node.expression, 107455 | 793056 | 1536); + } + function getTargetOfAliasDeclaration(node) { + switch (node.kind) { + case 208: + return getTargetOfImportEqualsDeclaration(node); + case 210: + return getTargetOfImportClause(node); + case 211: + return getTargetOfNamespaceImport(node); + case 213: + return getTargetOfImportSpecifier(node); + case 217: + return getTargetOfExportSpecifier(node); + case 214: + return getTargetOfExportAssignment(node); + } + } + function resolveSymbol(symbol) { + return symbol && symbol.flags & 8388608 && !(symbol.flags & (107455 | 793056 | 1536)) ? resolveAlias(symbol) : symbol; + } + function resolveAlias(symbol) { + ts.Debug.assert((symbol.flags & 8388608) !== 0, "Should only get Alias here."); + var links = getSymbolLinks(symbol); + if (!links.target) { + links.target = resolvingSymbol; + var node = getDeclarationOfAliasSymbol(symbol); + var target = getTargetOfAliasDeclaration(node); + if (links.target === resolvingSymbol) { + links.target = target || unknownSymbol; + } + else { + error(node, ts.Diagnostics.Circular_definition_of_import_alias_0, symbolToString(symbol)); + } + } + else if (links.target === resolvingSymbol) { + links.target = unknownSymbol; + } + return links.target; + } + function markExportAsReferenced(node) { + var symbol = getSymbolOfNode(node); + var target = resolveAlias(symbol); + if (target) { + var markAlias = (target === unknownSymbol && compilerOptions.separateCompilation) || + (target !== unknownSymbol && (target.flags & 107455) && !isConstEnumOrConstEnumOnlyModule(target)); + if (markAlias) { + markAliasSymbolAsReferenced(symbol); + } + } + } + function markAliasSymbolAsReferenced(symbol) { + var links = getSymbolLinks(symbol); + if (!links.referenced) { + links.referenced = true; + var node = getDeclarationOfAliasSymbol(symbol); + if (node.kind === 214) { + checkExpressionCached(node.expression); + } + else if (node.kind === 217) { + checkExpressionCached(node.propertyName || node.name); + } + else if (ts.isInternalModuleImportEqualsDeclaration(node)) { + checkExpressionCached(node.moduleReference); + } + } + } + function getSymbolOfPartOfRightHandSideOfImportEquals(entityName, importDeclaration) { + if (!importDeclaration) { + importDeclaration = ts.getAncestor(entityName, 208); + ts.Debug.assert(importDeclaration !== undefined); + } + if (entityName.kind === 65 && ts.isRightSideOfQualifiedNameOrPropertyAccess(entityName)) { + entityName = entityName.parent; + } + if (entityName.kind === 65 || entityName.parent.kind === 126) { + return resolveEntityName(entityName, 1536); + } + else { + ts.Debug.assert(entityName.parent.kind === 208); + return resolveEntityName(entityName, 107455 | 793056 | 1536); + } + } + function getFullyQualifiedName(symbol) { + return symbol.parent ? getFullyQualifiedName(symbol.parent) + "." + symbolToString(symbol) : symbolToString(symbol); + } + function resolveEntityName(name, meaning) { + if (ts.nodeIsMissing(name)) { + return undefined; + } + var symbol; + if (name.kind === 65) { + symbol = resolveName(name, name.text, meaning, ts.Diagnostics.Cannot_find_name_0, name); + if (!symbol) { + return undefined; + } + } + else if (name.kind === 126 || name.kind === 155) { + var left = name.kind === 126 ? name.left : name.expression; + var right = name.kind === 126 ? name.right : name.name; + var namespace = resolveEntityName(left, 1536); + if (!namespace || namespace === unknownSymbol || ts.nodeIsMissing(right)) { + return undefined; + } + symbol = getSymbol(getExportsOfSymbol(namespace), right.text, meaning); + if (!symbol) { + error(right, ts.Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(namespace), ts.declarationNameToString(right)); + return undefined; + } + } + else { + ts.Debug.fail("Unknown entity name kind."); + } + ts.Debug.assert((symbol.flags & 16777216) === 0, "Should never get an instantiated symbol here."); + return symbol.flags & meaning ? symbol : resolveAlias(symbol); + } + function isExternalModuleNameRelative(moduleName) { + return moduleName.substr(0, 2) === "./" || moduleName.substr(0, 3) === "../" || moduleName.substr(0, 2) === ".\\" || moduleName.substr(0, 3) === "..\\"; + } + function resolveExternalModuleName(location, moduleReferenceExpression) { + if (moduleReferenceExpression.kind !== 8) { + return; + } + var moduleReferenceLiteral = moduleReferenceExpression; + var searchPath = ts.getDirectoryPath(getSourceFile(location).fileName); + var moduleName = ts.escapeIdentifier(moduleReferenceLiteral.text); + if (!moduleName) + return; + var isRelative = isExternalModuleNameRelative(moduleName); + if (!isRelative) { + var symbol = getSymbol(globals, '"' + moduleName + '"', 512); + if (symbol) { + return symbol; + } + } + var sourceFile; + while (true) { + var fileName = ts.normalizePath(ts.combinePaths(searchPath, moduleName)); + sourceFile = host.getSourceFile(fileName + ".ts") || host.getSourceFile(fileName + ".d.ts"); + if (sourceFile || isRelative) { + break; + } + var parentPath = ts.getDirectoryPath(searchPath); + if (parentPath === searchPath) { + break; + } + searchPath = parentPath; + } + if (sourceFile) { + if (sourceFile.symbol) { + return sourceFile.symbol; + } + error(moduleReferenceLiteral, ts.Diagnostics.File_0_is_not_an_external_module, sourceFile.fileName); + return; + } + error(moduleReferenceLiteral, ts.Diagnostics.Cannot_find_external_module_0, moduleName); + } + function resolveExternalModuleSymbol(moduleSymbol) { + return moduleSymbol && resolveSymbol(moduleSymbol.exports["export="]) || moduleSymbol; + } + function resolveESModuleSymbol(moduleSymbol, moduleReferenceExpression) { + var symbol = resolveExternalModuleSymbol(moduleSymbol); + if (symbol && !(symbol.flags & (1536 | 3))) { + error(moduleReferenceExpression, ts.Diagnostics.External_module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct, symbolToString(moduleSymbol)); + symbol = undefined; + } + return symbol; + } + function getExportAssignmentSymbol(moduleSymbol) { + return moduleSymbol.exports["export="]; + } + function getExportsOfModuleAsArray(moduleSymbol) { + return symbolsToArray(getExportsOfModule(moduleSymbol)); + } + function getExportsOfSymbol(symbol) { + return symbol.flags & 1536 ? getExportsOfModule(symbol) : symbol.exports || emptySymbols; + } + function getExportsOfModule(moduleSymbol) { + var links = getSymbolLinks(moduleSymbol); + return links.resolvedExports || (links.resolvedExports = getExportsForModule(moduleSymbol)); + } + function extendExportSymbols(target, source) { + for (var id in source) { + if (id !== "default" && !ts.hasProperty(target, id)) { + target[id] = source[id]; + } + } + } + function getExportsForModule(moduleSymbol) { + var result; + var visitedSymbols = []; + visit(moduleSymbol); + return result || moduleSymbol.exports; + function visit(symbol) { + if (symbol && symbol.flags & 1952 && !ts.contains(visitedSymbols, symbol)) { + visitedSymbols.push(symbol); + if (symbol !== moduleSymbol) { + if (!result) { + result = cloneSymbolTable(moduleSymbol.exports); + } + extendExportSymbols(result, symbol.exports); + } + var exportStars = symbol.exports["__export"]; + if (exportStars) { + for (var _i = 0, _a = exportStars.declarations; _i < _a.length; _i++) { + var node = _a[_i]; + visit(resolveExternalModuleName(node, node.moduleSpecifier)); + } + } + } + } + } + function getMergedSymbol(symbol) { + var merged; + return symbol && symbol.mergeId && (merged = mergedSymbols[symbol.mergeId]) ? merged : symbol; + } + function getSymbolOfNode(node) { + return getMergedSymbol(node.symbol); + } + function getParentOfSymbol(symbol) { + return getMergedSymbol(symbol.parent); + } + function getExportSymbolOfValueSymbolIfExported(symbol) { + return symbol && (symbol.flags & 1048576) !== 0 + ? getMergedSymbol(symbol.exportSymbol) + : symbol; + } + function symbolIsValue(symbol) { + if (symbol.flags & 16777216) { + return symbolIsValue(getSymbolLinks(symbol).target); + } + if (symbol.flags & 107455) { + return true; + } + if (symbol.flags & 8388608) { + return (resolveAlias(symbol).flags & 107455) !== 0; + } + return false; + } + function findConstructorDeclaration(node) { + var members = node.members; + for (var _i = 0; _i < members.length; _i++) { + var member = members[_i]; + if (member.kind === 135 && ts.nodeIsPresent(member.body)) { + return member; + } + } + } + function createType(flags) { + var result = new Type(checker, flags); + result.id = typeCount++; + return result; + } + function createIntrinsicType(kind, intrinsicName) { + var type = createType(kind); + type.intrinsicName = intrinsicName; + return type; + } + function createObjectType(kind, symbol) { + var type = createType(kind); + type.symbol = symbol; + return type; + } + function isReservedMemberName(name) { + return name.charCodeAt(0) === 95 && + name.charCodeAt(1) === 95 && + name.charCodeAt(2) !== 95 && + name.charCodeAt(2) !== 64; + } + function getNamedMembers(members) { + var result; + for (var id in members) { + if (ts.hasProperty(members, id)) { + if (!isReservedMemberName(id)) { + if (!result) + result = []; + var symbol = members[id]; + if (symbolIsValue(symbol)) { + result.push(symbol); + } + } + } + } + return result || emptyArray; + } + function setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType) { + type.members = members; + type.properties = getNamedMembers(members); + type.callSignatures = callSignatures; + type.constructSignatures = constructSignatures; + if (stringIndexType) + type.stringIndexType = stringIndexType; + if (numberIndexType) + type.numberIndexType = numberIndexType; + return type; + } + function createAnonymousType(symbol, members, callSignatures, constructSignatures, stringIndexType, numberIndexType) { + return setObjectTypeMembers(createObjectType(32768, symbol), members, callSignatures, constructSignatures, stringIndexType, numberIndexType); + } + function forEachSymbolTableInScope(enclosingDeclaration, callback) { + var result; + for (var location_1 = enclosingDeclaration; location_1; location_1 = location_1.parent) { + if (location_1.locals && !isGlobalSourceFile(location_1)) { + if (result = callback(location_1.locals)) { + return result; + } + } + switch (location_1.kind) { + case 227: + if (!ts.isExternalModule(location_1)) { + break; + } + case 205: + if (result = callback(getSymbolOfNode(location_1).exports)) { + return result; + } + break; + case 201: + case 202: + if (result = callback(getSymbolOfNode(location_1).members)) { + return result; + } + break; + } + } + return callback(globals); + } + function getQualifiedLeftMeaning(rightMeaning) { + return rightMeaning === 107455 ? 107455 : 1536; + } + function getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, useOnlyExternalAliasing) { + function getAccessibleSymbolChainFromSymbolTable(symbols) { + function canQualifySymbol(symbolFromSymbolTable, meaning) { + if (!needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning)) { + return true; + } + var accessibleParent = getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing); + return !!accessibleParent; + } + function isAccessible(symbolFromSymbolTable, resolvedAliasSymbol) { + if (symbol === (resolvedAliasSymbol || symbolFromSymbolTable)) { + return !ts.forEach(symbolFromSymbolTable.declarations, hasExternalModuleSymbol) && + canQualifySymbol(symbolFromSymbolTable, meaning); + } + } + if (isAccessible(ts.lookUp(symbols, symbol.name))) { + return [symbol]; + } + return ts.forEachValue(symbols, function (symbolFromSymbolTable) { + if (symbolFromSymbolTable.flags & 8388608 && symbolFromSymbolTable.name !== "export=") { + if (!useOnlyExternalAliasing || + ts.forEach(symbolFromSymbolTable.declarations, ts.isExternalModuleImportEqualsDeclaration)) { + var resolvedImportedSymbol = resolveAlias(symbolFromSymbolTable); + if (isAccessible(symbolFromSymbolTable, resolveAlias(symbolFromSymbolTable))) { + return [symbolFromSymbolTable]; + } + var accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTable(resolvedImportedSymbol.exports) : undefined; + if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) { + return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports); + } + } + } + }); + } + if (symbol) { + return forEachSymbolTableInScope(enclosingDeclaration, getAccessibleSymbolChainFromSymbolTable); + } + } + function needsQualification(symbol, enclosingDeclaration, meaning) { + var qualify = false; + forEachSymbolTableInScope(enclosingDeclaration, function (symbolTable) { + if (!ts.hasProperty(symbolTable, symbol.name)) { + return false; + } + var symbolFromSymbolTable = symbolTable[symbol.name]; + if (symbolFromSymbolTable === symbol) { + return true; + } + symbolFromSymbolTable = (symbolFromSymbolTable.flags & 8388608) ? resolveAlias(symbolFromSymbolTable) : symbolFromSymbolTable; + if (symbolFromSymbolTable.flags & meaning) { + qualify = true; + return true; + } + return false; + }); + return qualify; + } + function isSymbolAccessible(symbol, enclosingDeclaration, meaning) { + if (symbol && enclosingDeclaration && !(symbol.flags & 262144)) { + var initialSymbol = symbol; + var meaningToLook = meaning; + while (symbol) { + var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook, false); + if (accessibleSymbolChain) { + var hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0]); + if (!hasAccessibleDeclarations) { + return { + accessibility: 1, + errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), + errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, 1536) : undefined, + }; + } + return hasAccessibleDeclarations; + } + meaningToLook = getQualifiedLeftMeaning(meaning); + symbol = getParentOfSymbol(symbol); + } + var symbolExternalModule = ts.forEach(initialSymbol.declarations, getExternalModuleContainer); + if (symbolExternalModule) { + var enclosingExternalModule = getExternalModuleContainer(enclosingDeclaration); + if (symbolExternalModule !== enclosingExternalModule) { + return { + accessibility: 2, + errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), + errorModuleName: symbolToString(symbolExternalModule) + }; + } + } + return { + accessibility: 1, + errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), + }; + } + return { accessibility: 0 }; + function getExternalModuleContainer(declaration) { + for (; declaration; declaration = declaration.parent) { + if (hasExternalModuleSymbol(declaration)) { + return getSymbolOfNode(declaration); + } + } + } + } + function hasExternalModuleSymbol(declaration) { + return (declaration.kind === 205 && declaration.name.kind === 8) || + (declaration.kind === 227 && ts.isExternalModule(declaration)); + } + function hasVisibleDeclarations(symbol) { + var aliasesToMakeVisible; + if (ts.forEach(symbol.declarations, function (declaration) { return !getIsDeclarationVisible(declaration); })) { + return undefined; + } + return { accessibility: 0, aliasesToMakeVisible: aliasesToMakeVisible }; + function getIsDeclarationVisible(declaration) { + if (!isDeclarationVisible(declaration)) { + var anyImportSyntax = getAnyImportSyntax(declaration); + if (anyImportSyntax && + !(anyImportSyntax.flags & 1) && + isDeclarationVisible(anyImportSyntax.parent)) { + getNodeLinks(declaration).isVisible = true; + if (aliasesToMakeVisible) { + if (!ts.contains(aliasesToMakeVisible, anyImportSyntax)) { + aliasesToMakeVisible.push(anyImportSyntax); + } + } + else { + aliasesToMakeVisible = [anyImportSyntax]; + } + return true; + } + return false; + } + return true; + } + } + function isEntityNameVisible(entityName, enclosingDeclaration) { + var meaning; + if (entityName.parent.kind === 144) { + meaning = 107455 | 1048576; + } + else if (entityName.kind === 126 || entityName.kind === 155 || + entityName.parent.kind === 208) { + meaning = 1536; + } + else { + meaning = 793056; + } + var firstIdentifier = getFirstIdentifier(entityName); + var symbol = resolveName(enclosingDeclaration, firstIdentifier.text, meaning, undefined, undefined); + return (symbol && hasVisibleDeclarations(symbol)) || { + accessibility: 1, + errorSymbolName: ts.getTextOfNode(firstIdentifier), + errorNode: firstIdentifier + }; + } + function writeKeyword(writer, kind) { + writer.writeKeyword(ts.tokenToString(kind)); + } + function writePunctuation(writer, kind) { + writer.writePunctuation(ts.tokenToString(kind)); + } + function writeSpace(writer) { + writer.writeSpace(" "); + } + function symbolToString(symbol, enclosingDeclaration, meaning) { + var writer = ts.getSingleLineStringWriter(); + getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning); + var result = writer.string(); + ts.releaseStringWriter(writer); + return result; + } + function typeToString(type, enclosingDeclaration, flags) { + var writer = ts.getSingleLineStringWriter(); + getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); + var result = writer.string(); + ts.releaseStringWriter(writer); + var maxLength = compilerOptions.noErrorTruncation || flags & 4 ? undefined : 100; + if (maxLength && result.length >= maxLength) { + result = result.substr(0, maxLength - "...".length) + "..."; + } + return result; + } + function getTypeAliasForTypeLiteral(type) { + if (type.symbol && type.symbol.flags & 2048) { + var node = type.symbol.declarations[0].parent; + while (node.kind === 149) { + node = node.parent; + } + if (node.kind === 203) { + return getSymbolOfNode(node); + } + } + return undefined; + } + var _displayBuilder; + function getSymbolDisplayBuilder() { + function appendSymbolNameOnly(symbol, writer) { + if (symbol.declarations && symbol.declarations.length > 0) { + var declaration = symbol.declarations[0]; + if (declaration.name) { + writer.writeSymbol(ts.declarationNameToString(declaration.name), symbol); + return; + } + } + writer.writeSymbol(symbol.name, symbol); + } + function buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning, flags, typeFlags) { + var parentSymbol; + function appendParentTypeArgumentsAndSymbolName(symbol) { + if (parentSymbol) { + if (flags & 1) { + if (symbol.flags & 16777216) { + buildDisplayForTypeArgumentsAndDelimiters(getTypeParametersOfClassOrInterface(parentSymbol), symbol.mapper, writer, enclosingDeclaration); + } + else { + buildTypeParameterDisplayFromSymbol(parentSymbol, writer, enclosingDeclaration); + } + } + writePunctuation(writer, 20); + } + parentSymbol = symbol; + appendSymbolNameOnly(symbol, writer); + } + writer.trackSymbol(symbol, enclosingDeclaration, meaning); + function walkSymbol(symbol, meaning) { + if (symbol) { + var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, !!(flags & 2)); + if (!accessibleSymbolChain || + needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) { + walkSymbol(getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol), getQualifiedLeftMeaning(meaning)); + } + if (accessibleSymbolChain) { + for (var _i = 0; _i < accessibleSymbolChain.length; _i++) { + var accessibleSymbol = accessibleSymbolChain[_i]; + appendParentTypeArgumentsAndSymbolName(accessibleSymbol); + } + } + else { + if (!parentSymbol && ts.forEach(symbol.declarations, hasExternalModuleSymbol)) { + return; + } + if (symbol.flags & 2048 || symbol.flags & 4096) { + return; + } + appendParentTypeArgumentsAndSymbolName(symbol); + } + } + } + var isTypeParameter = symbol.flags & 262144; + var typeFormatFlag = 128 & typeFlags; + if (!isTypeParameter && (enclosingDeclaration || typeFormatFlag)) { + walkSymbol(symbol, meaning); + return; + } + return appendParentTypeArgumentsAndSymbolName(symbol); + } + function buildTypeDisplay(type, writer, enclosingDeclaration, globalFlags, typeStack) { + var globalFlagsToPass = globalFlags & 16; + return writeType(type, globalFlags); + function writeType(type, flags) { + if (type.flags & 1048703) { + writer.writeKeyword(!(globalFlags & 16) && + (type.flags & 1) ? "any" : type.intrinsicName); + } + else if (type.flags & 4096) { + writeTypeReference(type, flags); + } + else if (type.flags & (1024 | 2048 | 128 | 512)) { + buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, 793056, 0, flags); + } + else if (type.flags & 8192) { + writeTupleType(type); + } + else if (type.flags & 16384) { + writeUnionType(type, flags); + } + else if (type.flags & 32768) { + writeAnonymousType(type, flags); + } + else if (type.flags & 256) { + writer.writeStringLiteral(type.text); + } + else { + writePunctuation(writer, 14); + writeSpace(writer); + writePunctuation(writer, 21); + writeSpace(writer); + writePunctuation(writer, 15); + } + } + function writeTypeList(types, union) { + for (var i = 0; i < types.length; i++) { + if (i > 0) { + if (union) { + writeSpace(writer); + } + writePunctuation(writer, union ? 44 : 23); + writeSpace(writer); + } + writeType(types[i], union ? 64 : 0); + } + } + function writeTypeReference(type, flags) { + if (type.target === globalArrayType && !(flags & 1)) { + writeType(type.typeArguments[0], 64); + writePunctuation(writer, 18); + writePunctuation(writer, 19); + } + else { + buildSymbolDisplay(type.target.symbol, writer, enclosingDeclaration, 793056); + writePunctuation(writer, 24); + writeTypeList(type.typeArguments, false); + writePunctuation(writer, 25); + } + } + function writeTupleType(type) { + writePunctuation(writer, 18); + writeTypeList(type.elementTypes, false); + writePunctuation(writer, 19); + } + function writeUnionType(type, flags) { + if (flags & 64) { + writePunctuation(writer, 16); + } + writeTypeList(type.types, true); + if (flags & 64) { + writePunctuation(writer, 17); + } + } + function writeAnonymousType(type, flags) { + if (type.symbol && type.symbol.flags & (32 | 384 | 512)) { + writeTypeofSymbol(type, flags); + } + else if (shouldWriteTypeOfFunctionSymbol()) { + writeTypeofSymbol(type, flags); + } + else if (typeStack && ts.contains(typeStack, type)) { + var typeAlias = getTypeAliasForTypeLiteral(type); + if (typeAlias) { + buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, 793056, 0, flags); + } + else { + writeKeyword(writer, 112); + } + } + else { + if (!typeStack) { + typeStack = []; + } + typeStack.push(type); + writeLiteralType(type, flags); + typeStack.pop(); + } + function shouldWriteTypeOfFunctionSymbol() { + if (type.symbol) { + var isStaticMethodSymbol = !!(type.symbol.flags & 8192 && + ts.forEach(type.symbol.declarations, function (declaration) { return declaration.flags & 128; })); + var isNonLocalFunctionSymbol = !!(type.symbol.flags & 16) && + (type.symbol.parent || + ts.forEach(type.symbol.declarations, function (declaration) { + return declaration.parent.kind === 227 || declaration.parent.kind === 206; + })); + if (isStaticMethodSymbol || isNonLocalFunctionSymbol) { + return !!(flags & 2) || + (typeStack && ts.contains(typeStack, type)); + } + } + } + } + function writeTypeofSymbol(type, typeFormatFlags) { + writeKeyword(writer, 97); + writeSpace(writer); + buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, 107455, 0, typeFormatFlags); + } + function getIndexerParameterName(type, indexKind, fallbackName) { + var declaration = getIndexDeclarationOfSymbol(type.symbol, indexKind); + if (!declaration) { + return fallbackName; + } + ts.Debug.assert(declaration.parameters.length !== 0); + return ts.declarationNameToString(declaration.parameters[0].name); + } + function writeLiteralType(type, flags) { + var resolved = resolveObjectOrUnionTypeMembers(type); + if (!resolved.properties.length && !resolved.stringIndexType && !resolved.numberIndexType) { + if (!resolved.callSignatures.length && !resolved.constructSignatures.length) { + writePunctuation(writer, 14); + writePunctuation(writer, 15); + return; + } + if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { + if (flags & 64) { + writePunctuation(writer, 16); + } + buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | 8, typeStack); + if (flags & 64) { + writePunctuation(writer, 17); + } + return; + } + if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { + if (flags & 64) { + writePunctuation(writer, 16); + } + writeKeyword(writer, 88); + writeSpace(writer); + buildSignatureDisplay(resolved.constructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | 8, typeStack); + if (flags & 64) { + writePunctuation(writer, 17); + } + return; + } + } + writePunctuation(writer, 14); + writer.writeLine(); + writer.increaseIndent(); + for (var _i = 0, _a = resolved.callSignatures; _i < _a.length; _i++) { + var signature = _a[_i]; + buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack); + writePunctuation(writer, 22); + writer.writeLine(); + } + for (var _b = 0, _c = resolved.constructSignatures; _b < _c.length; _b++) { + var signature = _c[_b]; + writeKeyword(writer, 88); + writeSpace(writer); + buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack); + writePunctuation(writer, 22); + writer.writeLine(); + } + if (resolved.stringIndexType) { + writePunctuation(writer, 18); + writer.writeParameter(getIndexerParameterName(resolved, 0, "x")); + writePunctuation(writer, 51); + writeSpace(writer); + writeKeyword(writer, 121); + writePunctuation(writer, 19); + writePunctuation(writer, 51); + writeSpace(writer); + writeType(resolved.stringIndexType, 0); + writePunctuation(writer, 22); + writer.writeLine(); + } + if (resolved.numberIndexType) { + writePunctuation(writer, 18); + writer.writeParameter(getIndexerParameterName(resolved, 1, "x")); + writePunctuation(writer, 51); + writeSpace(writer); + writeKeyword(writer, 119); + writePunctuation(writer, 19); + writePunctuation(writer, 51); + writeSpace(writer); + writeType(resolved.numberIndexType, 0); + writePunctuation(writer, 22); + writer.writeLine(); + } + for (var _d = 0, _e = resolved.properties; _d < _e.length; _d++) { + var p = _e[_d]; + var t = getTypeOfSymbol(p); + if (p.flags & (16 | 8192) && !getPropertiesOfObjectType(t).length) { + var signatures = getSignaturesOfType(t, 0); + for (var _f = 0; _f < signatures.length; _f++) { + var signature = signatures[_f]; + buildSymbolDisplay(p, writer); + if (p.flags & 536870912) { + writePunctuation(writer, 50); + } + buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack); + writePunctuation(writer, 22); + writer.writeLine(); + } + } + else { + buildSymbolDisplay(p, writer); + if (p.flags & 536870912) { + writePunctuation(writer, 50); + } + writePunctuation(writer, 51); + writeSpace(writer); + writeType(t, 0); + writePunctuation(writer, 22); + writer.writeLine(); + } + } + writer.decreaseIndent(); + writePunctuation(writer, 15); + } + } + function buildTypeParameterDisplayFromSymbol(symbol, writer, enclosingDeclaraiton, flags) { + var targetSymbol = getTargetSymbol(symbol); + if (targetSymbol.flags & 32 || targetSymbol.flags & 64) { + buildDisplayForTypeParametersAndDelimiters(getTypeParametersOfClassOrInterface(symbol), writer, enclosingDeclaraiton, flags); + } + } + function buildTypeParameterDisplay(tp, writer, enclosingDeclaration, flags, typeStack) { + appendSymbolNameOnly(tp.symbol, writer); + var constraint = getConstraintOfTypeParameter(tp); + if (constraint) { + writeSpace(writer); + writeKeyword(writer, 79); + writeSpace(writer); + buildTypeDisplay(constraint, writer, enclosingDeclaration, flags, typeStack); + } + } + function buildParameterDisplay(p, writer, enclosingDeclaration, flags, typeStack) { + if (ts.hasDotDotDotToken(p.valueDeclaration)) { + writePunctuation(writer, 21); + } + appendSymbolNameOnly(p, writer); + if (ts.hasQuestionToken(p.valueDeclaration) || p.valueDeclaration.initializer) { + writePunctuation(writer, 50); + } + writePunctuation(writer, 51); + writeSpace(writer); + buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, typeStack); + } + function buildDisplayForTypeParametersAndDelimiters(typeParameters, writer, enclosingDeclaration, flags, typeStack) { + if (typeParameters && typeParameters.length) { + writePunctuation(writer, 24); + for (var i = 0; i < typeParameters.length; i++) { + if (i > 0) { + writePunctuation(writer, 23); + writeSpace(writer); + } + buildTypeParameterDisplay(typeParameters[i], writer, enclosingDeclaration, flags, typeStack); + } + writePunctuation(writer, 25); + } + } + function buildDisplayForTypeArgumentsAndDelimiters(typeParameters, mapper, writer, enclosingDeclaration, flags, typeStack) { + if (typeParameters && typeParameters.length) { + writePunctuation(writer, 24); + for (var i = 0; i < typeParameters.length; i++) { + if (i > 0) { + writePunctuation(writer, 23); + writeSpace(writer); + } + buildTypeDisplay(mapper(typeParameters[i]), writer, enclosingDeclaration, 0); + } + writePunctuation(writer, 25); + } + } + function buildDisplayForParametersAndDelimiters(parameters, writer, enclosingDeclaration, flags, typeStack) { + writePunctuation(writer, 16); + for (var i = 0; i < parameters.length; i++) { + if (i > 0) { + writePunctuation(writer, 23); + writeSpace(writer); + } + buildParameterDisplay(parameters[i], writer, enclosingDeclaration, flags, typeStack); + } + writePunctuation(writer, 17); + } + function buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, typeStack) { + if (flags & 8) { + writeSpace(writer); + writePunctuation(writer, 32); + } + else { + writePunctuation(writer, 51); + } + writeSpace(writer); + buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags, typeStack); + } + function buildSignatureDisplay(signature, writer, enclosingDeclaration, flags, typeStack) { + if (signature.target && (flags & 32)) { + buildDisplayForTypeArgumentsAndDelimiters(signature.target.typeParameters, signature.mapper, writer, enclosingDeclaration); + } + else { + buildDisplayForTypeParametersAndDelimiters(signature.typeParameters, writer, enclosingDeclaration, flags, typeStack); + } + buildDisplayForParametersAndDelimiters(signature.parameters, writer, enclosingDeclaration, flags, typeStack); + buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, typeStack); + } + return _displayBuilder || (_displayBuilder = { + symbolToString: symbolToString, + typeToString: typeToString, + buildSymbolDisplay: buildSymbolDisplay, + buildTypeDisplay: buildTypeDisplay, + buildTypeParameterDisplay: buildTypeParameterDisplay, + buildParameterDisplay: buildParameterDisplay, + buildDisplayForParametersAndDelimiters: buildDisplayForParametersAndDelimiters, + buildDisplayForTypeParametersAndDelimiters: buildDisplayForTypeParametersAndDelimiters, + buildDisplayForTypeArgumentsAndDelimiters: buildDisplayForTypeArgumentsAndDelimiters, + buildTypeParameterDisplayFromSymbol: buildTypeParameterDisplayFromSymbol, + buildSignatureDisplay: buildSignatureDisplay, + buildReturnTypeDisplay: buildReturnTypeDisplay + }); + } + function isDeclarationVisible(node) { + function getContainingExternalModule(node) { + for (; node; node = node.parent) { + if (node.kind === 205) { + if (node.name.kind === 8) { + return node; + } + } + else if (node.kind === 227) { + return ts.isExternalModule(node) ? node : undefined; + } + } + ts.Debug.fail("getContainingModule cant reach here"); + } + function isUsedInExportAssignment(node) { + var externalModule = getContainingExternalModule(node); + var exportAssignmentSymbol; + var resolvedExportSymbol; + if (externalModule) { + var externalModuleSymbol = getSymbolOfNode(externalModule); + exportAssignmentSymbol = getExportAssignmentSymbol(externalModuleSymbol); + var symbolOfNode = getSymbolOfNode(node); + if (isSymbolUsedInExportAssignment(symbolOfNode)) { + return true; + } + if (symbolOfNode.flags & 8388608) { + return isSymbolUsedInExportAssignment(resolveAlias(symbolOfNode)); + } + } + function isSymbolUsedInExportAssignment(symbol) { + if (exportAssignmentSymbol === symbol) { + return true; + } + if (exportAssignmentSymbol && !!(exportAssignmentSymbol.flags & 8388608)) { + resolvedExportSymbol = resolvedExportSymbol || resolveAlias(exportAssignmentSymbol); + if (resolvedExportSymbol === symbol) { + return true; + } + return ts.forEach(resolvedExportSymbol.declarations, function (current) { + while (current) { + if (current === node) { + return true; + } + current = current.parent; + } + }); + } + } + } + function determineIfDeclarationIsVisible() { + switch (node.kind) { + case 152: + return isDeclarationVisible(node.parent.parent); + case 198: + if (ts.isBindingPattern(node.name) && + !node.name.elements.length) { + return false; + } + case 205: + case 201: + case 202: + case 203: + case 200: + case 204: + case 208: + var parent_1 = getDeclarationContainer(node); + if (!(ts.getCombinedNodeFlags(node) & 1) && + !(node.kind !== 208 && parent_1.kind !== 227 && ts.isInAmbientContext(parent_1))) { + return isGlobalSourceFile(parent_1); + } + return isDeclarationVisible(parent_1); + case 132: + case 131: + case 136: + case 137: + case 134: + case 133: + if (node.flags & (32 | 64)) { + return false; + } + case 135: + case 139: + case 138: + case 140: + case 129: + case 206: + case 142: + case 143: + case 145: + case 141: + case 146: + case 147: + case 148: + case 149: + return isDeclarationVisible(node.parent); + case 210: + case 211: + case 213: + return false; + case 128: + case 227: + return true; + case 214: + return false; + default: + ts.Debug.fail("isDeclarationVisible unknown: SyntaxKind: " + node.kind); + } + } + if (node) { + var links = getNodeLinks(node); + if (links.isVisible === undefined) { + links.isVisible = !!determineIfDeclarationIsVisible(); + } + return links.isVisible; + } + } + function collectLinkedAliases(node) { + var exportSymbol; + if (node.parent && node.parent.kind === 214) { + exportSymbol = resolveName(node.parent, node.text, 107455 | 793056 | 1536, ts.Diagnostics.Cannot_find_name_0, node); + } + else if (node.parent.kind === 217) { + exportSymbol = getTargetOfExportSpecifier(node.parent); + } + var result = []; + if (exportSymbol) { + buildVisibleNodeList(exportSymbol.declarations); + } + return result; + function buildVisibleNodeList(declarations) { + ts.forEach(declarations, function (declaration) { + getNodeLinks(declaration).isVisible = true; + var resultNode = getAnyImportSyntax(declaration) || declaration; + if (!ts.contains(result, resultNode)) { + result.push(resultNode); + } + if (ts.isInternalModuleImportEqualsDeclaration(declaration)) { + var internalModuleReference = declaration.moduleReference; + var firstIdentifier = getFirstIdentifier(internalModuleReference); + var importSymbol = resolveName(declaration, firstIdentifier.text, 107455 | 793056 | 1536, ts.Diagnostics.Cannot_find_name_0, firstIdentifier); + buildVisibleNodeList(importSymbol.declarations); + } + }); + } + } + function getRootDeclaration(node) { + while (node.kind === 152) { + node = node.parent.parent; + } + return node; + } + function getDeclarationContainer(node) { + node = getRootDeclaration(node); + return node.kind === 198 ? node.parent.parent.parent : node.parent; + } + function getTypeOfPrototypeProperty(prototype) { + var classType = getDeclaredTypeOfSymbol(prototype.parent); + return classType.typeParameters ? createTypeReference(classType, ts.map(classType.typeParameters, function (_) { return anyType; })) : classType; + } + function getTypeOfPropertyOfType(type, name) { + var prop = getPropertyOfType(type, name); + return prop ? getTypeOfSymbol(prop) : undefined; + } + function getTypeForBindingElement(declaration) { + var pattern = declaration.parent; + var parentType = getTypeForVariableLikeDeclaration(pattern.parent); + if (parentType === unknownType) { + return unknownType; + } + if (!parentType || parentType === anyType) { + if (declaration.initializer) { + return checkExpressionCached(declaration.initializer); + } + return parentType; + } + var type; + if (pattern.kind === 150) { + var name_2 = declaration.propertyName || declaration.name; + type = getTypeOfPropertyOfType(parentType, name_2.text) || + isNumericLiteralName(name_2.text) && getIndexTypeOfType(parentType, 1) || + getIndexTypeOfType(parentType, 0); + if (!type) { + error(name_2, ts.Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), ts.declarationNameToString(name_2)); + return unknownType; + } + } + else { + var elementType = checkIteratedTypeOrElementType(parentType, pattern, false); + if (!declaration.dotDotDotToken) { + if (elementType.flags & 1) { + return elementType; + } + var propName = "" + ts.indexOf(pattern.elements, declaration); + type = isTupleLikeType(parentType) + ? getTypeOfPropertyOfType(parentType, propName) + : elementType; + if (!type) { + if (isTupleType(parentType)) { + error(declaration, ts.Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(parentType), parentType.elementTypes.length, pattern.elements.length); + } + else { + error(declaration, ts.Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName); + } + return unknownType; + } + } + else { + type = createArrayType(elementType); + } + } + return type; + } + function getTypeForVariableLikeDeclaration(declaration) { + if (declaration.parent.parent.kind === 187) { + return anyType; + } + if (declaration.parent.parent.kind === 188) { + return checkRightHandSideOfForOf(declaration.parent.parent.expression) || anyType; + } + if (ts.isBindingPattern(declaration.parent)) { + return getTypeForBindingElement(declaration); + } + if (declaration.type) { + return getTypeFromTypeNode(declaration.type); + } + if (declaration.kind === 129) { + var func = declaration.parent; + if (func.kind === 137 && !ts.hasDynamicName(func)) { + var getter = ts.getDeclarationOfKind(declaration.parent.symbol, 136); + if (getter) { + return getReturnTypeOfSignature(getSignatureFromDeclaration(getter)); + } + } + var type = getContextuallyTypedParameterType(declaration); + if (type) { + return type; + } + } + if (declaration.initializer) { + return checkExpressionCached(declaration.initializer); + } + if (declaration.kind === 225) { + return checkIdentifier(declaration.name); + } + return undefined; + } + function getTypeFromBindingElement(element) { + if (element.initializer) { + return getWidenedType(checkExpressionCached(element.initializer)); + } + if (ts.isBindingPattern(element.name)) { + return getTypeFromBindingPattern(element.name); + } + return anyType; + } + function getTypeFromObjectBindingPattern(pattern) { + var members = {}; + ts.forEach(pattern.elements, function (e) { + var flags = 4 | 67108864 | (e.initializer ? 536870912 : 0); + var name = e.propertyName || e.name; + var symbol = createSymbol(flags, name.text); + symbol.type = getTypeFromBindingElement(e); + members[symbol.name] = symbol; + }); + return createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined); + } + function getTypeFromArrayBindingPattern(pattern) { + var hasSpreadElement = false; + var elementTypes = []; + ts.forEach(pattern.elements, function (e) { + elementTypes.push(e.kind === 175 || e.dotDotDotToken ? anyType : getTypeFromBindingElement(e)); + if (e.dotDotDotToken) { + hasSpreadElement = true; + } + }); + if (!elementTypes.length) { + return languageVersion >= 2 ? createIterableType(anyType) : anyArrayType; + } + else if (hasSpreadElement) { + var unionOfElements = getUnionType(elementTypes); + return languageVersion >= 2 ? createIterableType(unionOfElements) : createArrayType(unionOfElements); + } + return createTupleType(elementTypes); + } + function getTypeFromBindingPattern(pattern) { + return pattern.kind === 150 + ? getTypeFromObjectBindingPattern(pattern) + : getTypeFromArrayBindingPattern(pattern); + } + function getWidenedTypeForVariableLikeDeclaration(declaration, reportErrors) { + var type = getTypeForVariableLikeDeclaration(declaration); + if (type) { + if (reportErrors) { + reportErrorsFromWidening(declaration, type); + } + return declaration.kind !== 224 ? getWidenedType(type) : type; + } + if (ts.isBindingPattern(declaration.name)) { + return getTypeFromBindingPattern(declaration.name); + } + type = declaration.dotDotDotToken ? anyArrayType : anyType; + if (reportErrors && compilerOptions.noImplicitAny) { + var root = getRootDeclaration(declaration); + if (!isPrivateWithinAmbient(root) && !(root.kind === 129 && isPrivateWithinAmbient(root.parent))) { + reportImplicitAnyError(declaration, type); + } + } + return type; + } + function getTypeOfVariableOrParameterOrProperty(symbol) { + var links = getSymbolLinks(symbol); + if (!links.type) { + if (symbol.flags & 134217728) { + return links.type = getTypeOfPrototypeProperty(symbol); + } + var declaration = symbol.valueDeclaration; + if (declaration.parent.kind === 223) { + return links.type = anyType; + } + if (declaration.kind === 214) { + return links.type = checkExpression(declaration.expression); + } + links.type = resolvingType; + var type = getWidenedTypeForVariableLikeDeclaration(declaration, true); + if (links.type === resolvingType) { + links.type = type; + } + } + else if (links.type === resolvingType) { + links.type = anyType; + if (compilerOptions.noImplicitAny) { + var diagnostic = symbol.valueDeclaration.type ? + ts.Diagnostics._0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation : + ts.Diagnostics._0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer; + error(symbol.valueDeclaration, diagnostic, symbolToString(symbol)); + } + } + return links.type; + } + function getSetAccessorTypeAnnotationNode(accessor) { + return accessor && accessor.parameters.length > 0 && accessor.parameters[0].type; + } + function getAnnotatedAccessorType(accessor) { + if (accessor) { + if (accessor.kind === 136) { + return accessor.type && getTypeFromTypeNode(accessor.type); + } + else { + var setterTypeAnnotation = getSetAccessorTypeAnnotationNode(accessor); + return setterTypeAnnotation && getTypeFromTypeNode(setterTypeAnnotation); + } + } + return undefined; + } + function getTypeOfAccessors(symbol) { + var links = getSymbolLinks(symbol); + checkAndStoreTypeOfAccessors(symbol, links); + return links.type; + } + function checkAndStoreTypeOfAccessors(symbol, links) { + links = links || getSymbolLinks(symbol); + if (!links.type) { + links.type = resolvingType; + var getter = ts.getDeclarationOfKind(symbol, 136); + var setter = ts.getDeclarationOfKind(symbol, 137); + var type; + var getterReturnType = getAnnotatedAccessorType(getter); + if (getterReturnType) { + type = getterReturnType; + } + else { + var setterParameterType = getAnnotatedAccessorType(setter); + if (setterParameterType) { + type = setterParameterType; + } + else { + if (getter && getter.body) { + type = getReturnTypeFromBody(getter); + } + else { + if (compilerOptions.noImplicitAny) { + error(setter, ts.Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbolToString(symbol)); + } + type = anyType; + } + } + } + if (links.type === resolvingType) { + links.type = type; + } + } + else if (links.type === resolvingType) { + links.type = anyType; + if (compilerOptions.noImplicitAny) { + var getter = ts.getDeclarationOfKind(symbol, 136); + error(getter, ts.Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol)); + } + } + } + function getTypeOfFuncClassEnumModule(symbol) { + var links = getSymbolLinks(symbol); + if (!links.type) { + links.type = createObjectType(32768, symbol); + } + return links.type; + } + function getTypeOfEnumMember(symbol) { + var links = getSymbolLinks(symbol); + if (!links.type) { + links.type = getDeclaredTypeOfEnum(getParentOfSymbol(symbol)); + } + return links.type; + } + function getTypeOfAlias(symbol) { + var links = getSymbolLinks(symbol); + if (!links.type) { + links.type = getTypeOfSymbol(resolveAlias(symbol)); + } + return links.type; + } + function getTypeOfInstantiatedSymbol(symbol) { + var links = getSymbolLinks(symbol); + if (!links.type) { + links.type = instantiateType(getTypeOfSymbol(links.target), links.mapper); + } + return links.type; + } + function getTypeOfSymbol(symbol) { + if (symbol.flags & 16777216) { + return getTypeOfInstantiatedSymbol(symbol); + } + if (symbol.flags & (3 | 4)) { + return getTypeOfVariableOrParameterOrProperty(symbol); + } + if (symbol.flags & (16 | 8192 | 32 | 384 | 512)) { + return getTypeOfFuncClassEnumModule(symbol); + } + if (symbol.flags & 8) { + return getTypeOfEnumMember(symbol); + } + if (symbol.flags & 98304) { + return getTypeOfAccessors(symbol); + } + if (symbol.flags & 8388608) { + return getTypeOfAlias(symbol); + } + return unknownType; + } + function getTargetType(type) { + return type.flags & 4096 ? type.target : type; + } + function hasBaseType(type, checkBase) { + return check(type); + function check(type) { + var target = getTargetType(type); + return target === checkBase || ts.forEach(getBaseTypes(target), check); + } + } + function getTypeParametersOfClassOrInterface(symbol) { + var result; + ts.forEach(symbol.declarations, function (node) { + if (node.kind === 202 || node.kind === 201) { + var declaration = node; + if (declaration.typeParameters && declaration.typeParameters.length) { + ts.forEach(declaration.typeParameters, function (node) { + var tp = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node)); + if (!result) { + result = [tp]; + } + else if (!ts.contains(result, tp)) { + result.push(tp); + } + }); + } + } + }); + return result; + } + function getBaseTypes(type) { + var typeWithBaseTypes = type; + if (!typeWithBaseTypes.baseTypes) { + if (type.symbol.flags & 32) { + resolveBaseTypesOfClass(typeWithBaseTypes); + } + else if (type.symbol.flags & 64) { + resolveBaseTypesOfInterface(typeWithBaseTypes); + } + else { + ts.Debug.fail("type must be class or interface"); + } + } + return typeWithBaseTypes.baseTypes; + } + function resolveBaseTypesOfClass(type) { + type.baseTypes = []; + var declaration = ts.getDeclarationOfKind(type.symbol, 201); + var baseTypeNode = ts.getClassExtendsHeritageClauseElement(declaration); + if (baseTypeNode) { + var baseType = getTypeFromHeritageClauseElement(baseTypeNode); + if (baseType !== unknownType) { + if (getTargetType(baseType).flags & 1024) { + if (type !== baseType && !hasBaseType(baseType, type)) { + type.baseTypes.push(baseType); + } + else { + error(declaration, ts.Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, undefined, 1)); + } + } + else { + error(baseTypeNode, ts.Diagnostics.A_class_may_only_extend_another_class); + } + } + } + } + function resolveBaseTypesOfInterface(type) { + type.baseTypes = []; + for (var _i = 0, _a = type.symbol.declarations; _i < _a.length; _i++) { + var declaration = _a[_i]; + if (declaration.kind === 202 && ts.getInterfaceBaseTypeNodes(declaration)) { + for (var _b = 0, _c = ts.getInterfaceBaseTypeNodes(declaration); _b < _c.length; _b++) { + var node = _c[_b]; + var baseType = getTypeFromHeritageClauseElement(node); + if (baseType !== unknownType) { + if (getTargetType(baseType).flags & (1024 | 2048)) { + if (type !== baseType && !hasBaseType(baseType, type)) { + type.baseTypes.push(baseType); + } + else { + error(declaration, ts.Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, undefined, 1)); + } + } + else { + error(node, ts.Diagnostics.An_interface_may_only_extend_a_class_or_another_interface); + } + } + } + } + } + } + function getDeclaredTypeOfClassOrInterface(symbol) { + var links = getSymbolLinks(symbol); + if (!links.declaredType) { + var kind = symbol.flags & 32 ? 1024 : 2048; + var type = links.declaredType = createObjectType(kind, symbol); + var typeParameters = getTypeParametersOfClassOrInterface(symbol); + if (typeParameters) { + type.flags |= 4096; + type.typeParameters = typeParameters; + type.instantiations = {}; + type.instantiations[getTypeListId(type.typeParameters)] = type; + type.target = type; + type.typeArguments = type.typeParameters; + } + } + return links.declaredType; + } + function getDeclaredTypeOfTypeAlias(symbol) { + var links = getSymbolLinks(symbol); + if (!links.declaredType) { + links.declaredType = resolvingType; + var declaration = ts.getDeclarationOfKind(symbol, 203); + var type = getTypeFromTypeNode(declaration.type); + if (links.declaredType === resolvingType) { + links.declaredType = type; + } + } + else if (links.declaredType === resolvingType) { + links.declaredType = unknownType; + var declaration = ts.getDeclarationOfKind(symbol, 203); + error(declaration.name, ts.Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); + } + return links.declaredType; + } + function getDeclaredTypeOfEnum(symbol) { + var links = getSymbolLinks(symbol); + if (!links.declaredType) { + var type = createType(128); + type.symbol = symbol; + links.declaredType = type; + } + return links.declaredType; + } + function getDeclaredTypeOfTypeParameter(symbol) { + var links = getSymbolLinks(symbol); + if (!links.declaredType) { + var type = createType(512); + type.symbol = symbol; + if (!ts.getDeclarationOfKind(symbol, 128).constraint) { + type.constraint = noConstraintType; + } + links.declaredType = type; + } + return links.declaredType; + } + function getDeclaredTypeOfAlias(symbol) { + var links = getSymbolLinks(symbol); + if (!links.declaredType) { + links.declaredType = getDeclaredTypeOfSymbol(resolveAlias(symbol)); + } + return links.declaredType; + } + function getDeclaredTypeOfSymbol(symbol) { + ts.Debug.assert((symbol.flags & 16777216) === 0); + if (symbol.flags & (32 | 64)) { + return getDeclaredTypeOfClassOrInterface(symbol); + } + if (symbol.flags & 524288) { + return getDeclaredTypeOfTypeAlias(symbol); + } + if (symbol.flags & 384) { + return getDeclaredTypeOfEnum(symbol); + } + if (symbol.flags & 262144) { + return getDeclaredTypeOfTypeParameter(symbol); + } + if (symbol.flags & 8388608) { + return getDeclaredTypeOfAlias(symbol); + } + return unknownType; + } + function createSymbolTable(symbols) { + var result = {}; + for (var _i = 0; _i < symbols.length; _i++) { + var symbol = symbols[_i]; + result[symbol.name] = symbol; + } + return result; + } + function createInstantiatedSymbolTable(symbols, mapper) { + var result = {}; + for (var _i = 0; _i < symbols.length; _i++) { + var symbol = symbols[_i]; + result[symbol.name] = instantiateSymbol(symbol, mapper); + } + return result; + } + function addInheritedMembers(symbols, baseSymbols) { + for (var _i = 0; _i < baseSymbols.length; _i++) { + var s = baseSymbols[_i]; + if (!ts.hasProperty(symbols, s.name)) { + symbols[s.name] = s; + } + } + } + function addInheritedSignatures(signatures, baseSignatures) { + if (baseSignatures) { + for (var _i = 0; _i < baseSignatures.length; _i++) { + var signature = baseSignatures[_i]; + signatures.push(signature); + } + } + } + function resolveDeclaredMembers(type) { + if (!type.declaredProperties) { + var symbol = type.symbol; + type.declaredProperties = getNamedMembers(symbol.members); + type.declaredCallSignatures = getSignaturesOfSymbol(symbol.members["__call"]); + type.declaredConstructSignatures = getSignaturesOfSymbol(symbol.members["__new"]); + type.declaredStringIndexType = getIndexTypeOfSymbol(symbol, 0); + type.declaredNumberIndexType = getIndexTypeOfSymbol(symbol, 1); + } + return type; + } + function resolveClassOrInterfaceMembers(type) { + var target = resolveDeclaredMembers(type); + var members = target.symbol.members; + var callSignatures = target.declaredCallSignatures; + var constructSignatures = target.declaredConstructSignatures; + var stringIndexType = target.declaredStringIndexType; + var numberIndexType = target.declaredNumberIndexType; + var baseTypes = getBaseTypes(target); + if (baseTypes.length) { + members = createSymbolTable(target.declaredProperties); + for (var _i = 0; _i < baseTypes.length; _i++) { + var baseType = baseTypes[_i]; + addInheritedMembers(members, getPropertiesOfObjectType(baseType)); + callSignatures = ts.concatenate(callSignatures, getSignaturesOfType(baseType, 0)); + constructSignatures = ts.concatenate(constructSignatures, getSignaturesOfType(baseType, 1)); + stringIndexType = stringIndexType || getIndexTypeOfType(baseType, 0); + numberIndexType = numberIndexType || getIndexTypeOfType(baseType, 1); + } + } + setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType); + } + function resolveTypeReferenceMembers(type) { + var target = resolveDeclaredMembers(type.target); + var mapper = createTypeMapper(target.typeParameters, type.typeArguments); + var members = createInstantiatedSymbolTable(target.declaredProperties, mapper); + var callSignatures = instantiateList(target.declaredCallSignatures, mapper, instantiateSignature); + var constructSignatures = instantiateList(target.declaredConstructSignatures, mapper, instantiateSignature); + var stringIndexType = target.declaredStringIndexType ? instantiateType(target.declaredStringIndexType, mapper) : undefined; + var numberIndexType = target.declaredNumberIndexType ? instantiateType(target.declaredNumberIndexType, mapper) : undefined; + ts.forEach(getBaseTypes(target), function (baseType) { + var instantiatedBaseType = instantiateType(baseType, mapper); + addInheritedMembers(members, getPropertiesOfObjectType(instantiatedBaseType)); + callSignatures = ts.concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, 0)); + constructSignatures = ts.concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, 1)); + stringIndexType = stringIndexType || getIndexTypeOfType(instantiatedBaseType, 0); + numberIndexType = numberIndexType || getIndexTypeOfType(instantiatedBaseType, 1); + }); + setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType); + } + function createSignature(declaration, typeParameters, parameters, resolvedReturnType, minArgumentCount, hasRestParameter, hasStringLiterals) { + var sig = new Signature(checker); + sig.declaration = declaration; + sig.typeParameters = typeParameters; + sig.parameters = parameters; + sig.resolvedReturnType = resolvedReturnType; + sig.minArgumentCount = minArgumentCount; + sig.hasRestParameter = hasRestParameter; + sig.hasStringLiterals = hasStringLiterals; + return sig; + } + function cloneSignature(sig) { + return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType, sig.minArgumentCount, sig.hasRestParameter, sig.hasStringLiterals); + } + function getDefaultConstructSignatures(classType) { + var baseTypes = getBaseTypes(classType); + if (baseTypes.length) { + var baseType = baseTypes[0]; + var baseSignatures = getSignaturesOfType(getTypeOfSymbol(baseType.symbol), 1); + return ts.map(baseSignatures, function (baseSignature) { + var signature = baseType.flags & 4096 ? + getSignatureInstantiation(baseSignature, baseType.typeArguments) : cloneSignature(baseSignature); + signature.typeParameters = classType.typeParameters; + signature.resolvedReturnType = classType; + return signature; + }); + } + return [createSignature(undefined, classType.typeParameters, emptyArray, classType, 0, false, false)]; + } + function createTupleTypeMemberSymbols(memberTypes) { + var members = {}; + for (var i = 0; i < memberTypes.length; i++) { + var symbol = createSymbol(4 | 67108864, "" + i); + symbol.type = memberTypes[i]; + members[i] = symbol; + } + return members; + } + function resolveTupleTypeMembers(type) { + var arrayType = resolveObjectOrUnionTypeMembers(createArrayType(getUnionType(type.elementTypes))); + var members = createTupleTypeMemberSymbols(type.elementTypes); + addInheritedMembers(members, arrayType.properties); + setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexType, arrayType.numberIndexType); + } + function signatureListsIdentical(s, t) { + if (s.length !== t.length) { + return false; + } + for (var i = 0; i < s.length; i++) { + if (!compareSignatures(s[i], t[i], false, compareTypes)) { + return false; + } + } + return true; + } + function getUnionSignatures(types, kind) { + var signatureLists = ts.map(types, function (t) { return getSignaturesOfType(t, kind); }); + var signatures = signatureLists[0]; + for (var _i = 0; _i < signatures.length; _i++) { + var signature = signatures[_i]; + if (signature.typeParameters) { + return emptyArray; + } + } + for (var i_1 = 1; i_1 < signatureLists.length; i_1++) { + if (!signatureListsIdentical(signatures, signatureLists[i_1])) { + return emptyArray; + } + } + var result = ts.map(signatures, cloneSignature); + for (var i = 0; i < result.length; i++) { + var s = result[i]; + s.resolvedReturnType = undefined; + s.unionSignatures = ts.map(signatureLists, function (signatures) { return signatures[i]; }); + } + return result; + } + function getUnionIndexType(types, kind) { + var indexTypes = []; + for (var _i = 0; _i < types.length; _i++) { + var type = types[_i]; + var indexType = getIndexTypeOfType(type, kind); + if (!indexType) { + return undefined; + } + indexTypes.push(indexType); + } + return getUnionType(indexTypes); + } + function resolveUnionTypeMembers(type) { + var callSignatures = getUnionSignatures(type.types, 0); + var constructSignatures = getUnionSignatures(type.types, 1); + var stringIndexType = getUnionIndexType(type.types, 0); + var numberIndexType = getUnionIndexType(type.types, 1); + setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexType, numberIndexType); + } + function resolveAnonymousTypeMembers(type) { + var symbol = type.symbol; + var members; + var callSignatures; + var constructSignatures; + var stringIndexType; + var numberIndexType; + if (symbol.flags & 2048) { + members = symbol.members; + callSignatures = getSignaturesOfSymbol(members["__call"]); + constructSignatures = getSignaturesOfSymbol(members["__new"]); + stringIndexType = getIndexTypeOfSymbol(symbol, 0); + numberIndexType = getIndexTypeOfSymbol(symbol, 1); + } + else { + members = emptySymbols; + callSignatures = emptyArray; + constructSignatures = emptyArray; + if (symbol.flags & 1952) { + members = getExportsOfSymbol(symbol); + } + if (symbol.flags & (16 | 8192)) { + callSignatures = getSignaturesOfSymbol(symbol); + } + if (symbol.flags & 32) { + var classType = getDeclaredTypeOfClassOrInterface(symbol); + constructSignatures = getSignaturesOfSymbol(symbol.members["__constructor"]); + if (!constructSignatures.length) { + constructSignatures = getDefaultConstructSignatures(classType); + } + var baseTypes = getBaseTypes(classType); + if (baseTypes.length) { + members = createSymbolTable(getNamedMembers(members)); + addInheritedMembers(members, getPropertiesOfObjectType(getTypeOfSymbol(baseTypes[0].symbol))); + } + } + stringIndexType = undefined; + numberIndexType = (symbol.flags & 384) ? stringType : undefined; + } + setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType); + } + function resolveObjectOrUnionTypeMembers(type) { + if (!type.members) { + if (type.flags & (1024 | 2048)) { + resolveClassOrInterfaceMembers(type); + } + else if (type.flags & 32768) { + resolveAnonymousTypeMembers(type); + } + else if (type.flags & 8192) { + resolveTupleTypeMembers(type); + } + else if (type.flags & 16384) { + resolveUnionTypeMembers(type); + } + else { + resolveTypeReferenceMembers(type); + } + } + return type; + } + function getPropertiesOfObjectType(type) { + if (type.flags & 48128) { + return resolveObjectOrUnionTypeMembers(type).properties; + } + return emptyArray; + } + function getPropertyOfObjectType(type, name) { + if (type.flags & 48128) { + var resolved = resolveObjectOrUnionTypeMembers(type); + if (ts.hasProperty(resolved.members, name)) { + var symbol = resolved.members[name]; + if (symbolIsValue(symbol)) { + return symbol; + } + } + } + } + function getPropertiesOfUnionType(type) { + var result = []; + ts.forEach(getPropertiesOfType(type.types[0]), function (prop) { + var unionProp = getPropertyOfUnionType(type, prop.name); + if (unionProp) { + result.push(unionProp); + } + }); + return result; + } + function getPropertiesOfType(type) { + type = getApparentType(type); + return type.flags & 16384 ? getPropertiesOfUnionType(type) : getPropertiesOfObjectType(type); + } + function getApparentType(type) { + if (type.flags & 16384) { + type = getReducedTypeOfUnionType(type); + } + if (type.flags & 512) { + do { + type = getConstraintOfTypeParameter(type); + } while (type && type.flags & 512); + if (!type) { + type = emptyObjectType; + } + } + if (type.flags & 258) { + type = globalStringType; + } + else if (type.flags & 132) { + type = globalNumberType; + } + else if (type.flags & 8) { + type = globalBooleanType; + } + else if (type.flags & 1048576) { + type = globalESSymbolType; + } + return type; + } + function createUnionProperty(unionType, name) { + var types = unionType.types; + var props; + for (var _i = 0; _i < types.length; _i++) { + var current = types[_i]; + var type = getApparentType(current); + if (type !== unknownType) { + var prop = getPropertyOfType(type, name); + if (!prop || getDeclarationFlagsFromSymbol(prop) & (32 | 64)) { + return undefined; + } + if (!props) { + props = [prop]; + } + else { + props.push(prop); + } + } + } + var propTypes = []; + var declarations = []; + for (var _a = 0; _a < props.length; _a++) { + var prop = props[_a]; + if (prop.declarations) { + declarations.push.apply(declarations, prop.declarations); + } + propTypes.push(getTypeOfSymbol(prop)); + } + var result = createSymbol(4 | 67108864 | 268435456, name); + result.unionType = unionType; + result.declarations = declarations; + result.type = getUnionType(propTypes); + return result; + } + function getPropertyOfUnionType(type, name) { + var properties = type.resolvedProperties || (type.resolvedProperties = {}); + if (ts.hasProperty(properties, name)) { + return properties[name]; + } + var property = createUnionProperty(type, name); + if (property) { + properties[name] = property; + } + return property; + } + function getPropertyOfType(type, name) { + type = getApparentType(type); + if (type.flags & 48128) { + var resolved = resolveObjectOrUnionTypeMembers(type); + if (ts.hasProperty(resolved.members, name)) { + var symbol = resolved.members[name]; + if (symbolIsValue(symbol)) { + return symbol; + } + } + if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) { + var symbol = getPropertyOfObjectType(globalFunctionType, name); + if (symbol) { + return symbol; + } + } + return getPropertyOfObjectType(globalObjectType, name); + } + if (type.flags & 16384) { + return getPropertyOfUnionType(type, name); + } + return undefined; + } + function getSignaturesOfObjectOrUnionType(type, kind) { + if (type.flags & (48128 | 16384)) { + var resolved = resolveObjectOrUnionTypeMembers(type); + return kind === 0 ? resolved.callSignatures : resolved.constructSignatures; + } + return emptyArray; + } + function getSignaturesOfType(type, kind) { + return getSignaturesOfObjectOrUnionType(getApparentType(type), kind); + } + function typeHasCallOrConstructSignatures(type) { + var apparentType = getApparentType(type); + if (apparentType.flags & (48128 | 16384)) { + var resolved = resolveObjectOrUnionTypeMembers(type); + return resolved.callSignatures.length > 0 + || resolved.constructSignatures.length > 0; + } + return false; + } + function getIndexTypeOfObjectOrUnionType(type, kind) { + if (type.flags & (48128 | 16384)) { + var resolved = resolveObjectOrUnionTypeMembers(type); + return kind === 0 ? resolved.stringIndexType : resolved.numberIndexType; + } + } + function getIndexTypeOfType(type, kind) { + return getIndexTypeOfObjectOrUnionType(getApparentType(type), kind); + } + function getTypeParametersFromDeclaration(typeParameterDeclarations) { + var result = []; + ts.forEach(typeParameterDeclarations, function (node) { + var tp = getDeclaredTypeOfTypeParameter(node.symbol); + if (!ts.contains(result, tp)) { + result.push(tp); + } + }); + return result; + } + function symbolsToArray(symbols) { + var result = []; + for (var id in symbols) { + if (!isReservedMemberName(id)) { + result.push(symbols[id]); + } + } + return result; + } + function getSignatureFromDeclaration(declaration) { + var links = getNodeLinks(declaration); + if (!links.resolvedSignature) { + var classType = declaration.kind === 135 ? getDeclaredTypeOfClassOrInterface(declaration.parent.symbol) : undefined; + var typeParameters = classType ? classType.typeParameters : + declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) : undefined; + var parameters = []; + var hasStringLiterals = false; + var minArgumentCount = -1; + for (var i = 0, n = declaration.parameters.length; i < n; i++) { + var param = declaration.parameters[i]; + parameters.push(param.symbol); + if (param.type && param.type.kind === 8) { + hasStringLiterals = true; + } + if (minArgumentCount < 0) { + if (param.initializer || param.questionToken || param.dotDotDotToken) { + minArgumentCount = i; + } + } + } + if (minArgumentCount < 0) { + minArgumentCount = declaration.parameters.length; + } + var returnType; + if (classType) { + returnType = classType; + } + else if (declaration.type) { + returnType = getTypeFromTypeNode(declaration.type); + } + else { + if (declaration.kind === 136 && !ts.hasDynamicName(declaration)) { + var setter = ts.getDeclarationOfKind(declaration.symbol, 137); + returnType = getAnnotatedAccessorType(setter); + } + if (!returnType && ts.nodeIsMissing(declaration.body)) { + returnType = anyType; + } + } + links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, minArgumentCount, ts.hasRestParameters(declaration), hasStringLiterals); + } + return links.resolvedSignature; + } + function getSignaturesOfSymbol(symbol) { + if (!symbol) + return emptyArray; + var result = []; + for (var i = 0, len = symbol.declarations.length; i < len; i++) { + var node = symbol.declarations[i]; + switch (node.kind) { + case 142: + case 143: + case 200: + case 134: + case 133: + case 135: + case 138: + case 139: + case 140: + case 136: + case 137: + case 162: + case 163: + if (i > 0 && node.body) { + var previous = symbol.declarations[i - 1]; + if (node.parent === previous.parent && node.kind === previous.kind && node.pos === previous.end) { + break; + } + } + result.push(getSignatureFromDeclaration(node)); + } + } + return result; + } + function getReturnTypeOfSignature(signature) { + if (!signature.resolvedReturnType) { + signature.resolvedReturnType = resolvingType; + var type; + if (signature.target) { + type = instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper); + } + else if (signature.unionSignatures) { + type = getUnionType(ts.map(signature.unionSignatures, getReturnTypeOfSignature)); + } + else { + type = getReturnTypeFromBody(signature.declaration); + } + if (signature.resolvedReturnType === resolvingType) { + signature.resolvedReturnType = type; + } + } + else if (signature.resolvedReturnType === resolvingType) { + signature.resolvedReturnType = anyType; + if (compilerOptions.noImplicitAny) { + var declaration = signature.declaration; + if (declaration.name) { + error(declaration.name, ts.Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, ts.declarationNameToString(declaration.name)); + } + else { + error(declaration, ts.Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions); + } + } + } + return signature.resolvedReturnType; + } + function getRestTypeOfSignature(signature) { + if (signature.hasRestParameter) { + var type = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); + if (type.flags & 4096 && type.target === globalArrayType) { + return type.typeArguments[0]; + } + } + return anyType; + } + function getSignatureInstantiation(signature, typeArguments) { + return instantiateSignature(signature, createTypeMapper(signature.typeParameters, typeArguments), true); + } + function getErasedSignature(signature) { + if (!signature.typeParameters) + return signature; + if (!signature.erasedSignatureCache) { + if (signature.target) { + signature.erasedSignatureCache = instantiateSignature(getErasedSignature(signature.target), signature.mapper); + } + else { + signature.erasedSignatureCache = instantiateSignature(signature, createTypeEraser(signature.typeParameters), true); + } + } + return signature.erasedSignatureCache; + } + function getOrCreateTypeFromSignature(signature) { + if (!signature.isolatedSignatureType) { + var isConstructor = signature.declaration.kind === 135 || signature.declaration.kind === 139; + var type = createObjectType(32768 | 65536); + type.members = emptySymbols; + type.properties = emptyArray; + type.callSignatures = !isConstructor ? [signature] : emptyArray; + type.constructSignatures = isConstructor ? [signature] : emptyArray; + signature.isolatedSignatureType = type; + } + return signature.isolatedSignatureType; + } + function getIndexSymbol(symbol) { + return symbol.members["__index"]; + } + function getIndexDeclarationOfSymbol(symbol, kind) { + var syntaxKind = kind === 1 ? 119 : 121; + var indexSymbol = getIndexSymbol(symbol); + if (indexSymbol) { + var len = indexSymbol.declarations.length; + for (var _i = 0, _a = indexSymbol.declarations; _i < _a.length; _i++) { + var decl = _a[_i]; + var node = decl; + if (node.parameters.length === 1) { + var parameter = node.parameters[0]; + if (parameter && parameter.type && parameter.type.kind === syntaxKind) { + return node; + } + } + } + } + return undefined; + } + function getIndexTypeOfSymbol(symbol, kind) { + var declaration = getIndexDeclarationOfSymbol(symbol, kind); + return declaration + ? declaration.type ? getTypeFromTypeNode(declaration.type) : anyType + : undefined; + } + function getConstraintOfTypeParameter(type) { + if (!type.constraint) { + if (type.target) { + var targetConstraint = getConstraintOfTypeParameter(type.target); + type.constraint = targetConstraint ? instantiateType(targetConstraint, type.mapper) : noConstraintType; + } + else { + type.constraint = getTypeFromTypeNode(ts.getDeclarationOfKind(type.symbol, 128).constraint); + } + } + return type.constraint === noConstraintType ? undefined : type.constraint; + } + function getTypeListId(types) { + switch (types.length) { + case 1: + return "" + types[0].id; + case 2: + return types[0].id + "," + types[1].id; + default: + var result = ""; + for (var i = 0; i < types.length; i++) { + if (i > 0) { + result += ","; + } + result += types[i].id; + } + return result; + } + } + function getWideningFlagsOfTypes(types) { + var result = 0; + for (var _i = 0; _i < types.length; _i++) { + var type = types[_i]; + result |= type.flags; + } + return result & 786432; + } + function createTypeReference(target, typeArguments) { + var id = getTypeListId(typeArguments); + var type = target.instantiations[id]; + if (!type) { + var flags = 4096 | getWideningFlagsOfTypes(typeArguments); + type = target.instantiations[id] = createObjectType(flags, target.symbol); + type.target = target; + type.typeArguments = typeArguments; + } + return type; + } + function isTypeParameterReferenceIllegalInConstraint(typeReferenceNode, typeParameterSymbol) { + var links = getNodeLinks(typeReferenceNode); + if (links.isIllegalTypeReferenceInConstraint !== undefined) { + return links.isIllegalTypeReferenceInConstraint; + } + var currentNode = typeReferenceNode; + while (!ts.forEach(typeParameterSymbol.declarations, function (d) { return d.parent === currentNode.parent; })) { + currentNode = currentNode.parent; + } + links.isIllegalTypeReferenceInConstraint = currentNode.kind === 128; + return links.isIllegalTypeReferenceInConstraint; + } + function checkTypeParameterHasIllegalReferencesInConstraint(typeParameter) { + var typeParameterSymbol; + function check(n) { + if (n.kind === 141 && n.typeName.kind === 65) { + var links = getNodeLinks(n); + if (links.isIllegalTypeReferenceInConstraint === undefined) { + var symbol = resolveName(typeParameter, n.typeName.text, 793056, undefined, undefined); + if (symbol && (symbol.flags & 262144)) { + links.isIllegalTypeReferenceInConstraint = ts.forEach(symbol.declarations, function (d) { return d.parent == typeParameter.parent; }); + } + } + if (links.isIllegalTypeReferenceInConstraint) { + error(typeParameter, ts.Diagnostics.Constraint_of_a_type_parameter_cannot_reference_any_type_parameter_from_the_same_type_parameter_list); + } + } + ts.forEachChild(n, check); + } + if (typeParameter.constraint) { + typeParameterSymbol = getSymbolOfNode(typeParameter); + check(typeParameter.constraint); + } + } + function getTypeFromTypeReference(node) { + return getTypeFromTypeReferenceOrHeritageClauseElement(node); + } + function getTypeFromHeritageClauseElement(node) { + return getTypeFromTypeReferenceOrHeritageClauseElement(node); + } + function getTypeFromTypeReferenceOrHeritageClauseElement(node) { + var links = getNodeLinks(node); + if (!links.resolvedType) { + var type; + if (node.kind !== 177 || ts.isSupportedHeritageClauseElement(node)) { + var typeNameOrExpression = node.kind === 141 + ? node.typeName + : node.expression; + var symbol = resolveEntityName(typeNameOrExpression, 793056); + if (symbol) { + if ((symbol.flags & 262144) && isTypeParameterReferenceIllegalInConstraint(node, symbol)) { + type = unknownType; + } + else { + type = getDeclaredTypeOfSymbol(symbol); + if (type.flags & (1024 | 2048) && type.flags & 4096) { + var typeParameters = type.typeParameters; + if (node.typeArguments && node.typeArguments.length === typeParameters.length) { + type = createTypeReference(type, ts.map(node.typeArguments, getTypeFromTypeNode)); + } + else { + error(node, ts.Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, undefined, 1), typeParameters.length); + type = undefined; + } + } + else { + if (node.typeArguments) { + error(node, ts.Diagnostics.Type_0_is_not_generic, typeToString(type)); + type = undefined; + } + } + } + } + } + links.resolvedType = type || unknownType; + } + return links.resolvedType; + } + function getTypeFromTypeQueryNode(node) { + var links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = getWidenedType(checkExpressionOrQualifiedName(node.exprName)); + } + return links.resolvedType; + } + function getTypeOfGlobalSymbol(symbol, arity) { + function getTypeDeclaration(symbol) { + var declarations = symbol.declarations; + for (var _i = 0; _i < declarations.length; _i++) { + var declaration = declarations[_i]; + switch (declaration.kind) { + case 201: + case 202: + case 204: + return declaration; + } + } + } + if (!symbol) { + return emptyObjectType; + } + var type = getDeclaredTypeOfSymbol(symbol); + if (!(type.flags & 48128)) { + error(getTypeDeclaration(symbol), ts.Diagnostics.Global_type_0_must_be_a_class_or_interface_type, symbol.name); + return emptyObjectType; + } + if ((type.typeParameters ? type.typeParameters.length : 0) !== arity) { + error(getTypeDeclaration(symbol), ts.Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbol.name, arity); + return emptyObjectType; + } + return type; + } + function getGlobalValueSymbol(name) { + return getGlobalSymbol(name, 107455, ts.Diagnostics.Cannot_find_global_value_0); + } + function getGlobalTypeSymbol(name) { + return getGlobalSymbol(name, 793056, ts.Diagnostics.Cannot_find_global_type_0); + } + function getGlobalSymbol(name, meaning, diagnostic) { + return resolveName(undefined, name, meaning, diagnostic, name); + } + function getGlobalType(name, arity) { + if (arity === void 0) { arity = 0; } + return getTypeOfGlobalSymbol(getGlobalTypeSymbol(name), arity); + } + function getGlobalESSymbolConstructorSymbol() { + return globalESSymbolConstructorSymbol || (globalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol")); + } + function createIterableType(elementType) { + return globalIterableType !== emptyObjectType ? createTypeReference(globalIterableType, [elementType]) : emptyObjectType; + } + function createArrayType(elementType) { + var arrayType = globalArrayType || getDeclaredTypeOfSymbol(globalArraySymbol); + return arrayType !== emptyObjectType ? createTypeReference(arrayType, [elementType]) : emptyObjectType; + } + function getTypeFromArrayTypeNode(node) { + var links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = createArrayType(getTypeFromTypeNode(node.elementType)); + } + return links.resolvedType; + } + function createTupleType(elementTypes) { + var id = getTypeListId(elementTypes); + var type = tupleTypes[id]; + if (!type) { + type = tupleTypes[id] = createObjectType(8192); + type.elementTypes = elementTypes; + } + return type; + } + function getTypeFromTupleTypeNode(node) { + var links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = createTupleType(ts.map(node.elementTypes, getTypeFromTypeNode)); + } + return links.resolvedType; + } + function addTypeToSortedSet(sortedSet, type) { + if (type.flags & 16384) { + addTypesToSortedSet(sortedSet, type.types); + } + else { + var i = 0; + var id = type.id; + while (i < sortedSet.length && sortedSet[i].id < id) { + i++; + } + if (i === sortedSet.length || sortedSet[i].id !== id) { + sortedSet.splice(i, 0, type); + } + } + } + function addTypesToSortedSet(sortedTypes, types) { + for (var _i = 0; _i < types.length; _i++) { + var type = types[_i]; + addTypeToSortedSet(sortedTypes, type); + } + } + function isSubtypeOfAny(candidate, types) { + for (var _i = 0; _i < types.length; _i++) { + var type = types[_i]; + if (candidate !== type && isTypeSubtypeOf(candidate, type)) { + return true; + } + } + return false; + } + function removeSubtypes(types) { + var i = types.length; + while (i > 0) { + i--; + if (isSubtypeOfAny(types[i], types)) { + types.splice(i, 1); + } + } + } + function containsAnyType(types) { + for (var _i = 0; _i < types.length; _i++) { + var type = types[_i]; + if (type.flags & 1) { + return true; + } + } + return false; + } + function removeAllButLast(types, typeToRemove) { + var i = types.length; + while (i > 0 && types.length > 1) { + i--; + if (types[i] === typeToRemove) { + types.splice(i, 1); + } + } + } + function getUnionType(types, noSubtypeReduction) { + if (types.length === 0) { + return emptyObjectType; + } + var sortedTypes = []; + addTypesToSortedSet(sortedTypes, types); + if (noSubtypeReduction) { + if (containsAnyType(sortedTypes)) { + return anyType; + } + removeAllButLast(sortedTypes, undefinedType); + removeAllButLast(sortedTypes, nullType); + } + else { + removeSubtypes(sortedTypes); + } + if (sortedTypes.length === 1) { + return sortedTypes[0]; + } + var id = getTypeListId(sortedTypes); + var type = unionTypes[id]; + if (!type) { + type = unionTypes[id] = createObjectType(16384 | getWideningFlagsOfTypes(sortedTypes)); + type.types = sortedTypes; + type.reducedType = noSubtypeReduction ? undefined : type; + } + return type; + } + function getReducedTypeOfUnionType(type) { + if (!type.reducedType) { + type.reducedType = getUnionType(type.types, false); + } + return type.reducedType; + } + function getTypeFromUnionTypeNode(node) { + var links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = getUnionType(ts.map(node.types, getTypeFromTypeNode), true); + } + return links.resolvedType; + } + function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node) { + var links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = createObjectType(32768, node.symbol); + } + return links.resolvedType; + } + function getStringLiteralType(node) { + if (ts.hasProperty(stringLiteralTypes, node.text)) { + return stringLiteralTypes[node.text]; + } + var type = stringLiteralTypes[node.text] = createType(256); + type.text = ts.getTextOfNode(node); + return type; + } + function getTypeFromStringLiteral(node) { + var links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = getStringLiteralType(node); + } + return links.resolvedType; + } + function getTypeFromTypeNode(node) { + switch (node.kind) { + case 112: + return anyType; + case 121: + return stringType; + case 119: + return numberType; + case 113: + return booleanType; + case 122: + return esSymbolType; + case 99: + return voidType; + case 8: + return getTypeFromStringLiteral(node); + case 141: + return getTypeFromTypeReference(node); + case 177: + return getTypeFromHeritageClauseElement(node); + case 144: + return getTypeFromTypeQueryNode(node); + case 146: + return getTypeFromArrayTypeNode(node); + case 147: + return getTypeFromTupleTypeNode(node); + case 148: + return getTypeFromUnionTypeNode(node); + case 149: + return getTypeFromTypeNode(node.type); + case 142: + case 143: + case 145: + return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); + case 65: + case 126: + var symbol = getSymbolInfo(node); + return symbol && getDeclaredTypeOfSymbol(symbol); + default: + return unknownType; + } + } + function instantiateList(items, mapper, instantiator) { + if (items && items.length) { + var result = []; + for (var _i = 0; _i < items.length; _i++) { + var v = items[_i]; + result.push(instantiator(v, mapper)); + } + return result; + } + return items; + } + function createUnaryTypeMapper(source, target) { + return function (t) { return t === source ? target : t; }; + } + function createBinaryTypeMapper(source1, target1, source2, target2) { + return function (t) { return t === source1 ? target1 : t === source2 ? target2 : t; }; + } + function createTypeMapper(sources, targets) { + switch (sources.length) { + case 1: return createUnaryTypeMapper(sources[0], targets[0]); + case 2: return createBinaryTypeMapper(sources[0], targets[0], sources[1], targets[1]); + } + return function (t) { + for (var i = 0; i < sources.length; i++) { + if (t === sources[i]) { + return targets[i]; + } + } + return t; + }; + } + function createUnaryTypeEraser(source) { + return function (t) { return t === source ? anyType : t; }; + } + function createBinaryTypeEraser(source1, source2) { + return function (t) { return t === source1 || t === source2 ? anyType : t; }; + } + function createTypeEraser(sources) { + switch (sources.length) { + case 1: return createUnaryTypeEraser(sources[0]); + case 2: return createBinaryTypeEraser(sources[0], sources[1]); + } + return function (t) { + for (var _i = 0; _i < sources.length; _i++) { + var source = sources[_i]; + if (t === source) { + return anyType; + } + } + return t; + }; + } + function createInferenceMapper(context) { + return function (t) { + for (var i = 0; i < context.typeParameters.length; i++) { + if (t === context.typeParameters[i]) { + context.inferences[i].isFixed = true; + return getInferredType(context, i); + } + } + return t; + }; + } + function identityMapper(type) { + return type; + } + function combineTypeMappers(mapper1, mapper2) { + return function (t) { return instantiateType(mapper1(t), mapper2); }; + } + function instantiateTypeParameter(typeParameter, mapper) { + var result = createType(512); + result.symbol = typeParameter.symbol; + if (typeParameter.constraint) { + result.constraint = instantiateType(typeParameter.constraint, mapper); + } + else { + result.target = typeParameter; + result.mapper = mapper; + } + return result; + } + function instantiateSignature(signature, mapper, eraseTypeParameters) { + var freshTypeParameters; + if (signature.typeParameters && !eraseTypeParameters) { + freshTypeParameters = instantiateList(signature.typeParameters, mapper, instantiateTypeParameter); + mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper); + } + var result = createSignature(signature.declaration, freshTypeParameters, instantiateList(signature.parameters, mapper, instantiateSymbol), signature.resolvedReturnType ? instantiateType(signature.resolvedReturnType, mapper) : undefined, signature.minArgumentCount, signature.hasRestParameter, signature.hasStringLiterals); + result.target = signature; + result.mapper = mapper; + return result; + } + function instantiateSymbol(symbol, mapper) { + if (symbol.flags & 16777216) { + var links = getSymbolLinks(symbol); + symbol = links.target; + mapper = combineTypeMappers(links.mapper, mapper); + } + var result = createSymbol(16777216 | 67108864 | symbol.flags, symbol.name); + result.declarations = symbol.declarations; + result.parent = symbol.parent; + result.target = symbol; + result.mapper = mapper; + if (symbol.valueDeclaration) { + result.valueDeclaration = symbol.valueDeclaration; + } + return result; + } + function instantiateAnonymousType(type, mapper) { + var result = createObjectType(32768, type.symbol); + result.properties = instantiateList(getPropertiesOfObjectType(type), mapper, instantiateSymbol); + result.members = createSymbolTable(result.properties); + result.callSignatures = instantiateList(getSignaturesOfType(type, 0), mapper, instantiateSignature); + result.constructSignatures = instantiateList(getSignaturesOfType(type, 1), mapper, instantiateSignature); + var stringIndexType = getIndexTypeOfType(type, 0); + var numberIndexType = getIndexTypeOfType(type, 1); + if (stringIndexType) + result.stringIndexType = instantiateType(stringIndexType, mapper); + if (numberIndexType) + result.numberIndexType = instantiateType(numberIndexType, mapper); + return result; + } + function instantiateType(type, mapper) { + if (mapper !== identityMapper) { + if (type.flags & 512) { + return mapper(type); + } + if (type.flags & 32768) { + return type.symbol && type.symbol.flags & (16 | 8192 | 2048 | 4096) ? + instantiateAnonymousType(type, mapper) : type; + } + if (type.flags & 4096) { + return createTypeReference(type.target, instantiateList(type.typeArguments, mapper, instantiateType)); + } + if (type.flags & 8192) { + return createTupleType(instantiateList(type.elementTypes, mapper, instantiateType)); + } + if (type.flags & 16384) { + return getUnionType(instantiateList(type.types, mapper, instantiateType), true); + } + } + return type; + } + function isContextSensitive(node) { + ts.Debug.assert(node.kind !== 134 || ts.isObjectLiteralMethod(node)); + switch (node.kind) { + case 162: + case 163: + return isContextSensitiveFunctionLikeDeclaration(node); + case 154: + return ts.forEach(node.properties, isContextSensitive); + case 153: + return ts.forEach(node.elements, isContextSensitive); + case 170: + return isContextSensitive(node.whenTrue) || + isContextSensitive(node.whenFalse); + case 169: + return node.operatorToken.kind === 49 && + (isContextSensitive(node.left) || isContextSensitive(node.right)); + case 224: + return isContextSensitive(node.initializer); + case 134: + case 133: + return isContextSensitiveFunctionLikeDeclaration(node); + case 161: + return isContextSensitive(node.expression); + } + return false; + } + function isContextSensitiveFunctionLikeDeclaration(node) { + return !node.typeParameters && node.parameters.length && !ts.forEach(node.parameters, function (p) { return p.type; }); + } + function getTypeWithoutConstructors(type) { + if (type.flags & 48128) { + var resolved = resolveObjectOrUnionTypeMembers(type); + if (resolved.constructSignatures.length) { + var result = createObjectType(32768, type.symbol); + result.members = resolved.members; + result.properties = resolved.properties; + result.callSignatures = resolved.callSignatures; + result.constructSignatures = emptyArray; + type = result; + } + } + return type; + } + var subtypeRelation = {}; + var assignableRelation = {}; + var identityRelation = {}; + function isTypeIdenticalTo(source, target) { + return checkTypeRelatedTo(source, target, identityRelation, undefined); + } + function compareTypes(source, target) { + return checkTypeRelatedTo(source, target, identityRelation, undefined) ? -1 : 0; + } + function isTypeSubtypeOf(source, target) { + return checkTypeSubtypeOf(source, target, undefined); + } + function isTypeAssignableTo(source, target) { + return checkTypeAssignableTo(source, target, undefined); + } + function checkTypeSubtypeOf(source, target, errorNode, headMessage, containingMessageChain) { + return checkTypeRelatedTo(source, target, subtypeRelation, errorNode, headMessage, containingMessageChain); + } + function checkTypeAssignableTo(source, target, errorNode, headMessage) { + return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage); + } + function isSignatureAssignableTo(source, target) { + var sourceType = getOrCreateTypeFromSignature(source); + var targetType = getOrCreateTypeFromSignature(target); + return checkTypeRelatedTo(sourceType, targetType, assignableRelation, undefined); + } + function checkTypeRelatedTo(source, target, relation, errorNode, headMessage, containingMessageChain) { + var errorInfo; + var sourceStack; + var targetStack; + var maybeStack; + var expandingFlags; + var depth = 0; + var overflow = false; + var elaborateErrors = false; + ts.Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking"); + var result = isRelatedTo(source, target, errorNode !== undefined, headMessage); + if (overflow) { + error(errorNode, ts.Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target)); + } + else if (errorInfo) { + if (errorInfo.next === undefined) { + errorInfo = undefined; + elaborateErrors = true; + isRelatedTo(source, target, errorNode !== undefined, headMessage); + } + if (containingMessageChain) { + errorInfo = ts.concatenateDiagnosticMessageChains(containingMessageChain, errorInfo); + } + diagnostics.add(ts.createDiagnosticForNodeFromMessageChain(errorNode, errorInfo)); + } + return result !== 0; + function reportError(message, arg0, arg1, arg2) { + errorInfo = ts.chainDiagnosticMessages(errorInfo, message, arg0, arg1, arg2); + } + function isRelatedTo(source, target, reportErrors, headMessage) { + var result; + if (source === target) + return -1; + if (relation !== identityRelation) { + if (target.flags & 1) + return -1; + if (source === undefinedType) + return -1; + if (source === nullType && target !== undefinedType) + return -1; + if (source.flags & 128 && target === numberType) + return -1; + if (source.flags & 256 && target === stringType) + return -1; + if (relation === assignableRelation) { + if (source.flags & 1) + return -1; + if (source === numberType && target.flags & 128) + return -1; + } + } + var saveErrorInfo = errorInfo; + if (source.flags & 16384 || target.flags & 16384) { + if (relation === identityRelation) { + if (source.flags & 16384 && target.flags & 16384) { + if (result = unionTypeRelatedToUnionType(source, target)) { + if (result &= unionTypeRelatedToUnionType(target, source)) { + return result; + } + } + } + else if (source.flags & 16384) { + if (result = unionTypeRelatedToType(source, target, reportErrors)) { + return result; + } + } + else { + if (result = unionTypeRelatedToType(target, source, reportErrors)) { + return result; + } + } + } + else { + if (source.flags & 16384) { + if (result = unionTypeRelatedToType(source, target, reportErrors)) { + return result; + } + } + else { + if (result = typeRelatedToUnionType(source, target, reportErrors)) { + return result; + } + } + } + } + else if (source.flags & 512 && target.flags & 512) { + if (result = typeParameterRelatedTo(source, target, reportErrors)) { + return result; + } + } + else if (source.flags & 4096 && target.flags & 4096 && source.target === target.target) { + if (result = typesRelatedTo(source.typeArguments, target.typeArguments, reportErrors)) { + return result; + } + } + var reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; + var sourceOrApparentType = relation === identityRelation ? source : getApparentType(source); + if (sourceOrApparentType.flags & 48128 && target.flags & 48128) { + if (result = objectTypeRelatedTo(sourceOrApparentType, target, reportStructuralErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } + else if (source.flags & 512 && sourceOrApparentType.flags & 16384) { + errorInfo = saveErrorInfo; + if (result = isRelatedTo(sourceOrApparentType, target, reportErrors)) { + return result; + } + } + if (reportErrors) { + headMessage = headMessage || ts.Diagnostics.Type_0_is_not_assignable_to_type_1; + var sourceType = typeToString(source); + var targetType = typeToString(target); + if (sourceType === targetType) { + sourceType = typeToString(source, undefined, 128); + targetType = typeToString(target, undefined, 128); + } + reportError(headMessage, sourceType, targetType); + } + return 0; + } + function unionTypeRelatedToUnionType(source, target) { + var result = -1; + var sourceTypes = source.types; + for (var _i = 0; _i < sourceTypes.length; _i++) { + var sourceType = sourceTypes[_i]; + var related = typeRelatedToUnionType(sourceType, target, false); + if (!related) { + return 0; + } + result &= related; + } + return result; + } + function typeRelatedToUnionType(source, target, reportErrors) { + var targetTypes = target.types; + for (var i = 0, len = targetTypes.length; i < len; i++) { + var related = isRelatedTo(source, targetTypes[i], reportErrors && i === len - 1); + if (related) { + return related; + } + } + return 0; + } + function unionTypeRelatedToType(source, target, reportErrors) { + var result = -1; + var sourceTypes = source.types; + for (var _i = 0; _i < sourceTypes.length; _i++) { + var sourceType = sourceTypes[_i]; + var related = isRelatedTo(sourceType, target, reportErrors); + if (!related) { + return 0; + } + result &= related; + } + return result; + } + function typesRelatedTo(sources, targets, reportErrors) { + var result = -1; + for (var i = 0, len = sources.length; i < len; i++) { + var related = isRelatedTo(sources[i], targets[i], reportErrors); + if (!related) { + return 0; + } + result &= related; + } + return result; + } + function typeParameterRelatedTo(source, target, reportErrors) { + if (relation === identityRelation) { + if (source.symbol.name !== target.symbol.name) { + return 0; + } + if (source.constraint === target.constraint) { + return -1; + } + if (source.constraint === noConstraintType || target.constraint === noConstraintType) { + return 0; + } + return isRelatedTo(source.constraint, target.constraint, reportErrors); + } + else { + while (true) { + var constraint = getConstraintOfTypeParameter(source); + if (constraint === target) + return -1; + if (!(constraint && constraint.flags & 512)) + break; + source = constraint; + } + return 0; + } + } + function objectTypeRelatedTo(source, target, reportErrors) { + if (overflow) { + return 0; + } + var id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id; + var related = relation[id]; + if (related !== undefined) { + if (!elaborateErrors || (related === 3)) { + return related === 1 ? -1 : 0; + } + } + if (depth > 0) { + for (var i = 0; i < depth; i++) { + if (maybeStack[i][id]) { + return 1; + } + } + if (depth === 100) { + overflow = true; + return 0; + } + } + else { + sourceStack = []; + targetStack = []; + maybeStack = []; + expandingFlags = 0; + } + sourceStack[depth] = source; + targetStack[depth] = target; + maybeStack[depth] = {}; + maybeStack[depth][id] = 1; + depth++; + var saveExpandingFlags = expandingFlags; + if (!(expandingFlags & 1) && isDeeplyNestedGeneric(source, sourceStack)) + expandingFlags |= 1; + if (!(expandingFlags & 2) && isDeeplyNestedGeneric(target, targetStack)) + expandingFlags |= 2; + var result; + if (expandingFlags === 3) { + result = 1; + } + else { + result = propertiesRelatedTo(source, target, reportErrors); + if (result) { + result &= signaturesRelatedTo(source, target, 0, reportErrors); + if (result) { + result &= signaturesRelatedTo(source, target, 1, reportErrors); + if (result) { + result &= stringIndexTypesRelatedTo(source, target, reportErrors); + if (result) { + result &= numberIndexTypesRelatedTo(source, target, reportErrors); + } + } + } + } + } + expandingFlags = saveExpandingFlags; + depth--; + if (result) { + var maybeCache = maybeStack[depth]; + var destinationCache = (result === -1 || depth === 0) ? relation : maybeStack[depth - 1]; + ts.copyMap(maybeCache, destinationCache); + } + else { + relation[id] = reportErrors ? 3 : 2; + } + return result; + } + function isDeeplyNestedGeneric(type, stack) { + if (type.flags & 4096 && depth >= 10) { + var target_1 = type.target; + var count = 0; + for (var i = 0; i < depth; i++) { + var t = stack[i]; + if (t.flags & 4096 && t.target === target_1) { + count++; + if (count >= 10) + return true; + } + } + } + return false; + } + function propertiesRelatedTo(source, target, reportErrors) { + if (relation === identityRelation) { + return propertiesIdenticalTo(source, target); + } + var result = -1; + var properties = getPropertiesOfObjectType(target); + var requireOptionalProperties = relation === subtypeRelation && !(source.flags & 131072); + for (var _i = 0; _i < properties.length; _i++) { + var targetProp = properties[_i]; + var sourceProp = getPropertyOfType(source, targetProp.name); + if (sourceProp !== targetProp) { + if (!sourceProp) { + if (!(targetProp.flags & 536870912) || requireOptionalProperties) { + if (reportErrors) { + reportError(ts.Diagnostics.Property_0_is_missing_in_type_1, symbolToString(targetProp), typeToString(source)); + } + return 0; + } + } + else if (!(targetProp.flags & 134217728)) { + var sourceFlags = getDeclarationFlagsFromSymbol(sourceProp); + var targetFlags = getDeclarationFlagsFromSymbol(targetProp); + if (sourceFlags & 32 || targetFlags & 32) { + if (sourceProp.valueDeclaration !== targetProp.valueDeclaration) { + if (reportErrors) { + if (sourceFlags & 32 && targetFlags & 32) { + reportError(ts.Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp)); + } + else { + reportError(ts.Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, symbolToString(targetProp), typeToString(sourceFlags & 32 ? source : target), typeToString(sourceFlags & 32 ? target : source)); + } + } + return 0; + } + } + else if (targetFlags & 64) { + var sourceDeclaredInClass = sourceProp.parent && sourceProp.parent.flags & 32; + var sourceClass = sourceDeclaredInClass ? getDeclaredTypeOfSymbol(sourceProp.parent) : undefined; + var targetClass = getDeclaredTypeOfSymbol(targetProp.parent); + if (!sourceClass || !hasBaseType(sourceClass, targetClass)) { + if (reportErrors) { + reportError(ts.Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, symbolToString(targetProp), typeToString(sourceClass || source), typeToString(targetClass)); + } + return 0; + } + } + else if (sourceFlags & 64) { + if (reportErrors) { + reportError(ts.Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2, symbolToString(targetProp), typeToString(source), typeToString(target)); + } + return 0; + } + var related = isRelatedTo(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp), reportErrors); + if (!related) { + if (reportErrors) { + reportError(ts.Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp)); + } + return 0; + } + result &= related; + if (sourceProp.flags & 536870912 && !(targetProp.flags & 536870912)) { + if (reportErrors) { + reportError(ts.Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2, symbolToString(targetProp), typeToString(source), typeToString(target)); + } + return 0; + } + } + } + } + return result; + } + function propertiesIdenticalTo(source, target) { + var sourceProperties = getPropertiesOfObjectType(source); + var targetProperties = getPropertiesOfObjectType(target); + if (sourceProperties.length !== targetProperties.length) { + return 0; + } + var result = -1; + for (var _i = 0; _i < sourceProperties.length; _i++) { + var sourceProp = sourceProperties[_i]; + var targetProp = getPropertyOfObjectType(target, sourceProp.name); + if (!targetProp) { + return 0; + } + var related = compareProperties(sourceProp, targetProp, isRelatedTo); + if (!related) { + return 0; + } + result &= related; + } + return result; + } + function signaturesRelatedTo(source, target, kind, reportErrors) { + if (relation === identityRelation) { + return signaturesIdenticalTo(source, target, kind); + } + if (target === anyFunctionType || source === anyFunctionType) { + return -1; + } + var sourceSignatures = getSignaturesOfType(source, kind); + var targetSignatures = getSignaturesOfType(target, kind); + var result = -1; + var saveErrorInfo = errorInfo; + outer: for (var _i = 0; _i < targetSignatures.length; _i++) { + var t = targetSignatures[_i]; + if (!t.hasStringLiterals || target.flags & 65536) { + var localErrors = reportErrors; + for (var _a = 0; _a < sourceSignatures.length; _a++) { + var s = sourceSignatures[_a]; + if (!s.hasStringLiterals || source.flags & 65536) { + var related = signatureRelatedTo(s, t, localErrors); + if (related) { + result &= related; + errorInfo = saveErrorInfo; + continue outer; + } + localErrors = false; + } + } + return 0; + } + } + return result; + } + function signatureRelatedTo(source, target, reportErrors) { + if (source === target) { + return -1; + } + if (!target.hasRestParameter && source.minArgumentCount > target.parameters.length) { + return 0; + } + var sourceMax = source.parameters.length; + var targetMax = target.parameters.length; + var checkCount; + if (source.hasRestParameter && target.hasRestParameter) { + checkCount = sourceMax > targetMax ? sourceMax : targetMax; + sourceMax--; + targetMax--; + } + else if (source.hasRestParameter) { + sourceMax--; + checkCount = targetMax; + } + else if (target.hasRestParameter) { + targetMax--; + checkCount = sourceMax; + } + else { + checkCount = sourceMax < targetMax ? sourceMax : targetMax; + } + source = getErasedSignature(source); + target = getErasedSignature(target); + var result = -1; + for (var i = 0; i < checkCount; i++) { + var s_1 = i < sourceMax ? getTypeOfSymbol(source.parameters[i]) : getRestTypeOfSignature(source); + var t_1 = i < targetMax ? getTypeOfSymbol(target.parameters[i]) : getRestTypeOfSignature(target); + var saveErrorInfo = errorInfo; + var related = isRelatedTo(s_1, t_1, reportErrors); + if (!related) { + related = isRelatedTo(t_1, s_1, false); + if (!related) { + if (reportErrors) { + reportError(ts.Diagnostics.Types_of_parameters_0_and_1_are_incompatible, source.parameters[i < sourceMax ? i : sourceMax].name, target.parameters[i < targetMax ? i : targetMax].name); + } + return 0; + } + errorInfo = saveErrorInfo; + } + result &= related; + } + var t = getReturnTypeOfSignature(target); + if (t === voidType) + return result; + var s = getReturnTypeOfSignature(source); + return result & isRelatedTo(s, t, reportErrors); + } + function signaturesIdenticalTo(source, target, kind) { + var sourceSignatures = getSignaturesOfType(source, kind); + var targetSignatures = getSignaturesOfType(target, kind); + if (sourceSignatures.length !== targetSignatures.length) { + return 0; + } + var result = -1; + for (var i = 0, len = sourceSignatures.length; i < len; ++i) { + var related = compareSignatures(sourceSignatures[i], targetSignatures[i], true, isRelatedTo); + if (!related) { + return 0; + } + result &= related; + } + return result; + } + function stringIndexTypesRelatedTo(source, target, reportErrors) { + if (relation === identityRelation) { + return indexTypesIdenticalTo(0, source, target); + } + var targetType = getIndexTypeOfType(target, 0); + if (targetType) { + var sourceType = getIndexTypeOfType(source, 0); + if (!sourceType) { + if (reportErrors) { + reportError(ts.Diagnostics.Index_signature_is_missing_in_type_0, typeToString(source)); + } + return 0; + } + var related = isRelatedTo(sourceType, targetType, reportErrors); + if (!related) { + if (reportErrors) { + reportError(ts.Diagnostics.Index_signatures_are_incompatible); + } + return 0; + } + return related; + } + return -1; + } + function numberIndexTypesRelatedTo(source, target, reportErrors) { + if (relation === identityRelation) { + return indexTypesIdenticalTo(1, source, target); + } + var targetType = getIndexTypeOfType(target, 1); + if (targetType) { + var sourceStringType = getIndexTypeOfType(source, 0); + var sourceNumberType = getIndexTypeOfType(source, 1); + if (!(sourceStringType || sourceNumberType)) { + if (reportErrors) { + reportError(ts.Diagnostics.Index_signature_is_missing_in_type_0, typeToString(source)); + } + return 0; + } + var related; + if (sourceStringType && sourceNumberType) { + related = isRelatedTo(sourceStringType, targetType, false) || isRelatedTo(sourceNumberType, targetType, reportErrors); + } + else { + related = isRelatedTo(sourceStringType || sourceNumberType, targetType, reportErrors); + } + if (!related) { + if (reportErrors) { + reportError(ts.Diagnostics.Index_signatures_are_incompatible); + } + return 0; + } + return related; + } + return -1; + } + function indexTypesIdenticalTo(indexKind, source, target) { + var targetType = getIndexTypeOfType(target, indexKind); + var sourceType = getIndexTypeOfType(source, indexKind); + if (!sourceType && !targetType) { + return -1; + } + if (sourceType && targetType) { + return isRelatedTo(sourceType, targetType); + } + return 0; + } + } + function isPropertyIdenticalTo(sourceProp, targetProp) { + return compareProperties(sourceProp, targetProp, compareTypes) !== 0; + } + function compareProperties(sourceProp, targetProp, compareTypes) { + if (sourceProp === targetProp) { + return -1; + } + var sourcePropAccessibility = getDeclarationFlagsFromSymbol(sourceProp) & (32 | 64); + var targetPropAccessibility = getDeclarationFlagsFromSymbol(targetProp) & (32 | 64); + if (sourcePropAccessibility !== targetPropAccessibility) { + return 0; + } + if (sourcePropAccessibility) { + if (getTargetSymbol(sourceProp) !== getTargetSymbol(targetProp)) { + return 0; + } + } + else { + if ((sourceProp.flags & 536870912) !== (targetProp.flags & 536870912)) { + return 0; + } + } + return compareTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); + } + function compareSignatures(source, target, compareReturnTypes, compareTypes) { + if (source === target) { + return -1; + } + if (source.parameters.length !== target.parameters.length || + source.minArgumentCount !== target.minArgumentCount || + source.hasRestParameter !== target.hasRestParameter) { + return 0; + } + var result = -1; + if (source.typeParameters && target.typeParameters) { + if (source.typeParameters.length !== target.typeParameters.length) { + return 0; + } + for (var i = 0, len = source.typeParameters.length; i < len; ++i) { + var related = compareTypes(source.typeParameters[i], target.typeParameters[i]); + if (!related) { + return 0; + } + result &= related; + } + } + else if (source.typeParameters || target.typeParameters) { + return 0; + } + source = getErasedSignature(source); + target = getErasedSignature(target); + for (var i = 0, len = source.parameters.length; i < len; i++) { + var s = source.hasRestParameter && i === len - 1 ? getRestTypeOfSignature(source) : getTypeOfSymbol(source.parameters[i]); + var t = target.hasRestParameter && i === len - 1 ? getRestTypeOfSignature(target) : getTypeOfSymbol(target.parameters[i]); + var related = compareTypes(s, t); + if (!related) { + return 0; + } + result &= related; + } + if (compareReturnTypes) { + result &= compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + } + return result; + } + function isSupertypeOfEach(candidate, types) { + for (var _i = 0; _i < types.length; _i++) { + var type = types[_i]; + if (candidate !== type && !isTypeSubtypeOf(type, candidate)) + return false; + } + return true; + } + function getCommonSupertype(types) { + return ts.forEach(types, function (t) { return isSupertypeOfEach(t, types) ? t : undefined; }); + } + function reportNoCommonSupertypeError(types, errorLocation, errorMessageChainHead) { + var bestSupertype; + var bestSupertypeDownfallType; + var bestSupertypeScore = 0; + for (var i = 0; i < types.length; i++) { + var score = 0; + var downfallType = undefined; + for (var j = 0; j < types.length; j++) { + if (isTypeSubtypeOf(types[j], types[i])) { + score++; + } + else if (!downfallType) { + downfallType = types[j]; + } + } + ts.Debug.assert(!!downfallType, "If there is no common supertype, each type should have a downfallType"); + if (score > bestSupertypeScore) { + bestSupertype = types[i]; + bestSupertypeDownfallType = downfallType; + bestSupertypeScore = score; + } + if (bestSupertypeScore === types.length - 1) { + break; + } + } + checkTypeSubtypeOf(bestSupertypeDownfallType, bestSupertype, errorLocation, ts.Diagnostics.Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0, errorMessageChainHead); + } + function isArrayType(type) { + return type.flags & 4096 && type.target === globalArrayType; + } + function isArrayLikeType(type) { + return !(type.flags & (32 | 64)) && isTypeAssignableTo(type, anyArrayType); + } + function isTupleLikeType(type) { + return !!getPropertyOfType(type, "0"); + } + function isTupleType(type) { + return (type.flags & 8192) && !!type.elementTypes; + } + function getWidenedTypeOfObjectLiteral(type) { + var properties = getPropertiesOfObjectType(type); + var members = {}; + ts.forEach(properties, function (p) { + var propType = getTypeOfSymbol(p); + var widenedType = getWidenedType(propType); + if (propType !== widenedType) { + var symbol = createSymbol(p.flags | 67108864, p.name); + symbol.declarations = p.declarations; + symbol.parent = p.parent; + symbol.type = widenedType; + symbol.target = p; + if (p.valueDeclaration) + symbol.valueDeclaration = p.valueDeclaration; + p = symbol; + } + members[p.name] = p; + }); + var stringIndexType = getIndexTypeOfType(type, 0); + var numberIndexType = getIndexTypeOfType(type, 1); + if (stringIndexType) + stringIndexType = getWidenedType(stringIndexType); + if (numberIndexType) + numberIndexType = getWidenedType(numberIndexType); + return createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexType, numberIndexType); + } + function getWidenedType(type) { + if (type.flags & 786432) { + if (type.flags & (32 | 64)) { + return anyType; + } + if (type.flags & 131072) { + return getWidenedTypeOfObjectLiteral(type); + } + if (type.flags & 16384) { + return getUnionType(ts.map(type.types, getWidenedType)); + } + if (isArrayType(type)) { + return createArrayType(getWidenedType(type.typeArguments[0])); + } + } + return type; + } + function reportWideningErrorsInType(type) { + if (type.flags & 16384) { + var errorReported = false; + ts.forEach(type.types, function (t) { + if (reportWideningErrorsInType(t)) { + errorReported = true; + } + }); + return errorReported; + } + if (isArrayType(type)) { + return reportWideningErrorsInType(type.typeArguments[0]); + } + if (type.flags & 131072) { + var errorReported = false; + ts.forEach(getPropertiesOfObjectType(type), function (p) { + var t = getTypeOfSymbol(p); + if (t.flags & 262144) { + if (!reportWideningErrorsInType(t)) { + error(p.valueDeclaration, ts.Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(getWidenedType(t))); + } + errorReported = true; + } + }); + return errorReported; + } + return false; + } + function reportImplicitAnyError(declaration, type) { + var typeAsString = typeToString(getWidenedType(type)); + var diagnostic; + switch (declaration.kind) { + case 132: + case 131: + diagnostic = ts.Diagnostics.Member_0_implicitly_has_an_1_type; + break; + case 129: + diagnostic = declaration.dotDotDotToken ? + ts.Diagnostics.Rest_parameter_0_implicitly_has_an_any_type : + ts.Diagnostics.Parameter_0_implicitly_has_an_1_type; + break; + case 200: + case 134: + case 133: + case 136: + case 137: + case 162: + case 163: + if (!declaration.name) { + error(declaration, ts.Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString); + return; + } + diagnostic = ts.Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type; + break; + default: + diagnostic = ts.Diagnostics.Variable_0_implicitly_has_an_1_type; + } + error(declaration, diagnostic, ts.declarationNameToString(declaration.name), typeAsString); + } + function reportErrorsFromWidening(declaration, type) { + if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & 262144) { + if (!reportWideningErrorsInType(type)) { + reportImplicitAnyError(declaration, type); + } + } + } + function forEachMatchingParameterType(source, target, callback) { + var sourceMax = source.parameters.length; + var targetMax = target.parameters.length; + var count; + if (source.hasRestParameter && target.hasRestParameter) { + count = sourceMax > targetMax ? sourceMax : targetMax; + sourceMax--; + targetMax--; + } + else if (source.hasRestParameter) { + sourceMax--; + count = targetMax; + } + else if (target.hasRestParameter) { + targetMax--; + count = sourceMax; + } + else { + count = sourceMax < targetMax ? sourceMax : targetMax; + } + for (var i = 0; i < count; i++) { + var s = i < sourceMax ? getTypeOfSymbol(source.parameters[i]) : getRestTypeOfSignature(source); + var t = i < targetMax ? getTypeOfSymbol(target.parameters[i]) : getRestTypeOfSignature(target); + callback(s, t); + } + } + function createInferenceContext(typeParameters, inferUnionTypes) { + var inferences = []; + for (var _i = 0; _i < typeParameters.length; _i++) { + var unused = typeParameters[_i]; + inferences.push({ primary: undefined, secondary: undefined, isFixed: false }); + } + return { + typeParameters: typeParameters, + inferUnionTypes: inferUnionTypes, + inferences: inferences, + inferredTypes: new Array(typeParameters.length), + }; + } + function inferTypes(context, source, target) { + var sourceStack; + var targetStack; + var depth = 0; + var inferiority = 0; + inferFromTypes(source, target); + function isInProcess(source, target) { + for (var i = 0; i < depth; i++) { + if (source === sourceStack[i] && target === targetStack[i]) { + return true; + } + } + return false; + } + function isWithinDepthLimit(type, stack) { + if (depth >= 5) { + var target_2 = type.target; + var count = 0; + for (var i = 0; i < depth; i++) { + var t = stack[i]; + if (t.flags & 4096 && t.target === target_2) { + count++; + } + } + return count < 5; + } + return true; + } + function inferFromTypes(source, target) { + if (source === anyFunctionType) { + return; + } + if (target.flags & 512) { + var typeParameters = context.typeParameters; + for (var i = 0; i < typeParameters.length; i++) { + if (target === typeParameters[i]) { + var inferences = context.inferences[i]; + if (!inferences.isFixed) { + var candidates = inferiority ? + inferences.secondary || (inferences.secondary = []) : + inferences.primary || (inferences.primary = []); + if (!ts.contains(candidates, source)) { + candidates.push(source); + } + } + return; + } + } + } + else if (source.flags & 4096 && target.flags & 4096 && source.target === target.target) { + var sourceTypes = source.typeArguments; + var targetTypes = target.typeArguments; + for (var i = 0; i < sourceTypes.length; i++) { + inferFromTypes(sourceTypes[i], targetTypes[i]); + } + } + else if (target.flags & 16384) { + var targetTypes = target.types; + var typeParameterCount = 0; + var typeParameter; + for (var _i = 0; _i < targetTypes.length; _i++) { + var t = targetTypes[_i]; + if (t.flags & 512 && ts.contains(context.typeParameters, t)) { + typeParameter = t; + typeParameterCount++; + } + else { + inferFromTypes(source, t); + } + } + if (typeParameterCount === 1) { + inferiority++; + inferFromTypes(source, typeParameter); + inferiority--; + } + } + else if (source.flags & 16384) { + var sourceTypes = source.types; + for (var _a = 0; _a < sourceTypes.length; _a++) { + var sourceType = sourceTypes[_a]; + inferFromTypes(sourceType, target); + } + } + else if (source.flags & 48128 && (target.flags & (4096 | 8192) || + (target.flags & 32768) && target.symbol && target.symbol.flags & (8192 | 2048))) { + if (!isInProcess(source, target) && isWithinDepthLimit(source, sourceStack) && isWithinDepthLimit(target, targetStack)) { + if (depth === 0) { + sourceStack = []; + targetStack = []; + } + sourceStack[depth] = source; + targetStack[depth] = target; + depth++; + inferFromProperties(source, target); + inferFromSignatures(source, target, 0); + inferFromSignatures(source, target, 1); + inferFromIndexTypes(source, target, 0, 0); + inferFromIndexTypes(source, target, 1, 1); + inferFromIndexTypes(source, target, 0, 1); + depth--; + } + } + } + function inferFromProperties(source, target) { + var properties = getPropertiesOfObjectType(target); + for (var _i = 0; _i < properties.length; _i++) { + var targetProp = properties[_i]; + var sourceProp = getPropertyOfObjectType(source, targetProp.name); + if (sourceProp) { + inferFromTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); + } + } + } + function inferFromSignatures(source, target, kind) { + var sourceSignatures = getSignaturesOfType(source, kind); + var targetSignatures = getSignaturesOfType(target, kind); + var sourceLen = sourceSignatures.length; + var targetLen = targetSignatures.length; + var len = sourceLen < targetLen ? sourceLen : targetLen; + for (var i = 0; i < len; i++) { + inferFromSignature(getErasedSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i])); + } + } + function inferFromSignature(source, target) { + forEachMatchingParameterType(source, target, inferFromTypes); + inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + } + function inferFromIndexTypes(source, target, sourceKind, targetKind) { + var targetIndexType = getIndexTypeOfType(target, targetKind); + if (targetIndexType) { + var sourceIndexType = getIndexTypeOfType(source, sourceKind); + if (sourceIndexType) { + inferFromTypes(sourceIndexType, targetIndexType); + } + } + } + } + function getInferenceCandidates(context, index) { + var inferences = context.inferences[index]; + return inferences.primary || inferences.secondary || emptyArray; + } + function getInferredType(context, index) { + var inferredType = context.inferredTypes[index]; + var inferenceSucceeded; + if (!inferredType) { + var inferences = getInferenceCandidates(context, index); + if (inferences.length) { + var unionOrSuperType = context.inferUnionTypes ? getUnionType(inferences) : getCommonSupertype(inferences); + inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType; + inferenceSucceeded = !!unionOrSuperType; + } + else { + inferredType = emptyObjectType; + inferenceSucceeded = true; + } + if (inferenceSucceeded) { + var constraint = getConstraintOfTypeParameter(context.typeParameters[index]); + inferredType = constraint && !isTypeAssignableTo(inferredType, constraint) ? constraint : inferredType; + } + else if (context.failedTypeParameterIndex === undefined || context.failedTypeParameterIndex > index) { + context.failedTypeParameterIndex = index; + } + context.inferredTypes[index] = inferredType; + } + return inferredType; + } + function getInferredTypes(context) { + for (var i = 0; i < context.inferredTypes.length; i++) { + getInferredType(context, i); + } + return context.inferredTypes; + } + function hasAncestor(node, kind) { + return ts.getAncestor(node, kind) !== undefined; + } + function getResolvedSymbol(node) { + var links = getNodeLinks(node); + if (!links.resolvedSymbol) { + links.resolvedSymbol = (!ts.nodeIsMissing(node) && resolveName(node, node.text, 107455 | 1048576, ts.Diagnostics.Cannot_find_name_0, node)) || unknownSymbol; + } + return links.resolvedSymbol; + } + function isInTypeQuery(node) { + while (node) { + switch (node.kind) { + case 144: + return true; + case 65: + case 126: + node = node.parent; + continue; + default: + return false; + } + } + ts.Debug.fail("should not get here"); + } + function removeTypesFromUnionType(type, typeKind, isOfTypeKind, allowEmptyUnionResult) { + if (type.flags & 16384) { + var types = type.types; + if (ts.forEach(types, function (t) { return !!(t.flags & typeKind) === isOfTypeKind; })) { + var narrowedType = getUnionType(ts.filter(types, function (t) { return !(t.flags & typeKind) === isOfTypeKind; })); + if (allowEmptyUnionResult || narrowedType !== emptyObjectType) { + return narrowedType; + } + } + } + else if (allowEmptyUnionResult && !!(type.flags & typeKind) === isOfTypeKind) { + return getUnionType(emptyArray); + } + return type; + } + function hasInitializer(node) { + return !!(node.initializer || ts.isBindingPattern(node.parent) && hasInitializer(node.parent.parent)); + } + function isVariableAssignedWithin(symbol, node) { + var links = getNodeLinks(node); + if (links.assignmentChecks) { + var cachedResult = links.assignmentChecks[symbol.id]; + if (cachedResult !== undefined) { + return cachedResult; + } + } + else { + links.assignmentChecks = {}; + } + return links.assignmentChecks[symbol.id] = isAssignedIn(node); + function isAssignedInBinaryExpression(node) { + if (node.operatorToken.kind >= 53 && node.operatorToken.kind <= 64) { + var n = node.left; + while (n.kind === 161) { + n = n.expression; + } + if (n.kind === 65 && getResolvedSymbol(n) === symbol) { + return true; + } + } + return ts.forEachChild(node, isAssignedIn); + } + function isAssignedInVariableDeclaration(node) { + if (!ts.isBindingPattern(node.name) && getSymbolOfNode(node) === symbol && hasInitializer(node)) { + return true; + } + return ts.forEachChild(node, isAssignedIn); + } + function isAssignedIn(node) { + switch (node.kind) { + case 169: + return isAssignedInBinaryExpression(node); + case 198: + case 152: + return isAssignedInVariableDeclaration(node); + case 150: + case 151: + case 153: + case 154: + case 155: + case 156: + case 157: + case 158: + case 160: + case 161: + case 167: + case 164: + case 165: + case 166: + case 168: + case 170: + case 173: + case 179: + case 180: + case 182: + case 183: + case 184: + case 185: + case 186: + case 187: + case 188: + case 191: + case 192: + case 193: + case 220: + case 221: + case 194: + case 195: + case 196: + case 223: + return ts.forEachChild(node, isAssignedIn); + } + return false; + } + } + function resolveLocation(node) { + var containerNodes = []; + for (var parent_2 = node.parent; parent_2; parent_2 = parent_2.parent) { + if ((ts.isExpression(parent_2) || ts.isObjectLiteralMethod(node)) && + isContextSensitive(parent_2)) { + containerNodes.unshift(parent_2); + } + } + ts.forEach(containerNodes, function (node) { getTypeOfNode(node); }); + } + function getSymbolAtLocation(node) { + resolveLocation(node); + return getSymbolInfo(node); + } + function getTypeAtLocation(node) { + resolveLocation(node); + return getTypeOfNode(node); + } + function getTypeOfSymbolAtLocation(symbol, node) { + resolveLocation(node); + return getNarrowedTypeOfSymbol(symbol, node); + } + function getNarrowedTypeOfSymbol(symbol, node) { + var type = getTypeOfSymbol(symbol); + if (node && symbol.flags & 3 && type.flags & (1 | 48128 | 16384 | 512)) { + loop: while (node.parent) { + var child = node; + node = node.parent; + var narrowedType = type; + switch (node.kind) { + case 183: + if (child !== node.expression) { + narrowedType = narrowType(type, node.expression, child === node.thenStatement); + } + break; + case 170: + if (child !== node.condition) { + narrowedType = narrowType(type, node.condition, child === node.whenTrue); + } + break; + case 169: + if (child === node.right) { + if (node.operatorToken.kind === 48) { + narrowedType = narrowType(type, node.left, true); + } + else if (node.operatorToken.kind === 49) { + narrowedType = narrowType(type, node.left, false); + } + } + break; + case 227: + case 205: + case 200: + case 134: + case 133: + case 136: + case 137: + case 135: + break loop; + } + if (narrowedType !== type) { + if (isVariableAssignedWithin(symbol, node)) { + break; + } + type = narrowedType; + } + } + } + return type; + function narrowTypeByEquality(type, expr, assumeTrue) { + if (expr.left.kind !== 165 || expr.right.kind !== 8) { + return type; + } + var left = expr.left; + var right = expr.right; + if (left.expression.kind !== 65 || getResolvedSymbol(left.expression) !== symbol) { + return type; + } + var typeInfo = primitiveTypeInfo[right.text]; + if (expr.operatorToken.kind === 31) { + assumeTrue = !assumeTrue; + } + if (assumeTrue) { + if (!typeInfo) { + return removeTypesFromUnionType(type, 258 | 132 | 8 | 1048576, true, false); + } + if (isTypeSubtypeOf(typeInfo.type, type)) { + return typeInfo.type; + } + return removeTypesFromUnionType(type, typeInfo.flags, false, false); + } + else { + if (typeInfo) { + return removeTypesFromUnionType(type, typeInfo.flags, true, false); + } + return type; + } + } + function narrowTypeByAnd(type, expr, assumeTrue) { + if (assumeTrue) { + return narrowType(narrowType(type, expr.left, true), expr.right, true); + } + else { + return getUnionType([ + narrowType(type, expr.left, false), + narrowType(narrowType(type, expr.left, true), expr.right, false) + ]); + } + } + function narrowTypeByOr(type, expr, assumeTrue) { + if (assumeTrue) { + return getUnionType([ + narrowType(type, expr.left, true), + narrowType(narrowType(type, expr.left, false), expr.right, true) + ]); + } + else { + return narrowType(narrowType(type, expr.left, false), expr.right, false); + } + } + function narrowTypeByInstanceof(type, expr, assumeTrue) { + if (type.flags & 1 || !assumeTrue || expr.left.kind !== 65 || getResolvedSymbol(expr.left) !== symbol) { + return type; + } + var rightType = checkExpression(expr.right); + if (!isTypeSubtypeOf(rightType, globalFunctionType)) { + return type; + } + var prototypeProperty = getPropertyOfType(rightType, "prototype"); + if (!prototypeProperty) { + return type; + } + var targetType = getTypeOfSymbol(prototypeProperty); + if (isTypeSubtypeOf(targetType, type)) { + return targetType; + } + if (type.flags & 16384) { + return getUnionType(ts.filter(type.types, function (t) { return isTypeSubtypeOf(t, targetType); })); + } + return type; + } + function narrowType(type, expr, assumeTrue) { + switch (expr.kind) { + case 161: + return narrowType(type, expr.expression, assumeTrue); + case 169: + var operator = expr.operatorToken.kind; + if (operator === 30 || operator === 31) { + return narrowTypeByEquality(type, expr, assumeTrue); + } + else if (operator === 48) { + return narrowTypeByAnd(type, expr, assumeTrue); + } + else if (operator === 49) { + return narrowTypeByOr(type, expr, assumeTrue); + } + else if (operator === 87) { + return narrowTypeByInstanceof(type, expr, assumeTrue); + } + break; + case 167: + if (expr.operator === 46) { + return narrowType(type, expr.operand, !assumeTrue); + } + break; + } + return type; + } + } + function checkIdentifier(node) { + var symbol = getResolvedSymbol(node); + if (symbol === argumentsSymbol && ts.getContainingFunction(node).kind === 163 && languageVersion < 2) { + error(node, ts.Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression); + } + if (symbol.flags & 8388608 && !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(symbol))) { + markAliasSymbolAsReferenced(symbol); + } + checkCollisionWithCapturedSuperVariable(node, node); + checkCollisionWithCapturedThisVariable(node, node); + checkBlockScopedBindingCapturedInLoop(node, symbol); + return getNarrowedTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol), node); + } + function isInsideFunction(node, threshold) { + var current = node; + while (current && current !== threshold) { + if (ts.isFunctionLike(current)) { + return true; + } + current = current.parent; + } + return false; + } + function checkBlockScopedBindingCapturedInLoop(node, symbol) { + if (languageVersion >= 2 || + (symbol.flags & 2) === 0 || + symbol.valueDeclaration.parent.kind === 223) { + return; + } + var container = symbol.valueDeclaration; + while (container.kind !== 199) { + container = container.parent; + } + container = container.parent; + if (container.kind === 180) { + container = container.parent; + } + var inFunction = isInsideFunction(node.parent, container); + var current = container; + while (current && !ts.nodeStartsNewLexicalEnvironment(current)) { + if (isIterationStatement(current, false)) { + if (inFunction) { + grammarErrorOnFirstToken(current, ts.Diagnostics.Loop_contains_block_scoped_variable_0_referenced_by_a_function_in_the_loop_This_is_only_supported_in_ECMAScript_6_or_higher, ts.declarationNameToString(node)); + } + getNodeLinks(symbol.valueDeclaration).flags |= 256; + break; + } + current = current.parent; + } + } + function captureLexicalThis(node, container) { + var classNode = container.parent && container.parent.kind === 201 ? container.parent : undefined; + getNodeLinks(node).flags |= 2; + if (container.kind === 132 || container.kind === 135) { + getNodeLinks(classNode).flags |= 4; + } + else { + getNodeLinks(container).flags |= 4; + } + } + function checkThisExpression(node) { + var container = ts.getThisContainer(node, true); + var needToCaptureLexicalThis = false; + if (container.kind === 163) { + container = ts.getThisContainer(container, false); + needToCaptureLexicalThis = (languageVersion < 2); + } + switch (container.kind) { + case 205: + error(node, ts.Diagnostics.this_cannot_be_referenced_in_a_module_body); + break; + case 204: + error(node, ts.Diagnostics.this_cannot_be_referenced_in_current_location); + break; + case 135: + if (isInConstructorArgumentInitializer(node, container)) { + error(node, ts.Diagnostics.this_cannot_be_referenced_in_constructor_arguments); + } + break; + case 132: + case 131: + if (container.flags & 128) { + error(node, ts.Diagnostics.this_cannot_be_referenced_in_a_static_property_initializer); + } + break; + case 127: + error(node, ts.Diagnostics.this_cannot_be_referenced_in_a_computed_property_name); + break; + } + if (needToCaptureLexicalThis) { + captureLexicalThis(node, container); + } + var classNode = container.parent && container.parent.kind === 201 ? container.parent : undefined; + if (classNode) { + var symbol = getSymbolOfNode(classNode); + return container.flags & 128 ? getTypeOfSymbol(symbol) : getDeclaredTypeOfSymbol(symbol); + } + return anyType; + } + function isInConstructorArgumentInitializer(node, constructorDecl) { + for (var n = node; n && n !== constructorDecl; n = n.parent) { + if (n.kind === 129) { + return true; + } + } + return false; + } + function checkSuperExpression(node) { + var isCallExpression = node.parent.kind === 157 && node.parent.expression === node; + var enclosingClass = ts.getAncestor(node, 201); + var baseClass; + if (enclosingClass && ts.getClassExtendsHeritageClauseElement(enclosingClass)) { + var classType = getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClass)); + var baseTypes = getBaseTypes(classType); + baseClass = baseTypes.length && baseTypes[0]; + } + if (!baseClass) { + error(node, ts.Diagnostics.super_can_only_be_referenced_in_a_derived_class); + return unknownType; + } + var container = ts.getSuperContainer(node, true); + if (container) { + var canUseSuperExpression = false; + var needToCaptureLexicalThis; + if (isCallExpression) { + canUseSuperExpression = container.kind === 135; + } + else { + needToCaptureLexicalThis = false; + while (container && container.kind === 163) { + container = ts.getSuperContainer(container, true); + needToCaptureLexicalThis = languageVersion < 2; + } + if (container && container.parent && container.parent.kind === 201) { + if (container.flags & 128) { + canUseSuperExpression = + container.kind === 134 || + container.kind === 133 || + container.kind === 136 || + container.kind === 137; + } + else { + canUseSuperExpression = + container.kind === 134 || + container.kind === 133 || + container.kind === 136 || + container.kind === 137 || + container.kind === 132 || + container.kind === 131 || + container.kind === 135; + } + } + } + if (canUseSuperExpression) { + var returnType; + if ((container.flags & 128) || isCallExpression) { + getNodeLinks(node).flags |= 32; + returnType = getTypeOfSymbol(baseClass.symbol); + } + else { + getNodeLinks(node).flags |= 16; + returnType = baseClass; + } + if (container.kind === 135 && isInConstructorArgumentInitializer(node, container)) { + error(node, ts.Diagnostics.super_cannot_be_referenced_in_constructor_arguments); + returnType = unknownType; + } + if (!isCallExpression && needToCaptureLexicalThis) { + captureLexicalThis(node.parent, container); + } + return returnType; + } + } + if (container && container.kind === 127) { + error(node, ts.Diagnostics.super_cannot_be_referenced_in_a_computed_property_name); + } + else if (isCallExpression) { + error(node, ts.Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors); + } + else { + error(node, ts.Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class); + } + return unknownType; + } + function getContextuallyTypedParameterType(parameter) { + if (isFunctionExpressionOrArrowFunction(parameter.parent)) { + var func = parameter.parent; + if (isContextSensitive(func)) { + var contextualSignature = getContextualSignature(func); + if (contextualSignature) { + var funcHasRestParameters = ts.hasRestParameters(func); + var len = func.parameters.length - (funcHasRestParameters ? 1 : 0); + var indexOfParameter = ts.indexOf(func.parameters, parameter); + if (indexOfParameter < len) { + return getTypeAtPosition(contextualSignature, indexOfParameter); + } + if (indexOfParameter === (func.parameters.length - 1) && + funcHasRestParameters && contextualSignature.hasRestParameter && func.parameters.length >= contextualSignature.parameters.length) { + return getTypeOfSymbol(contextualSignature.parameters[contextualSignature.parameters.length - 1]); + } + } + } + } + return undefined; + } + function getContextualTypeForInitializerExpression(node) { + var declaration = node.parent; + if (node === declaration.initializer) { + if (declaration.type) { + return getTypeFromTypeNode(declaration.type); + } + if (declaration.kind === 129) { + var type = getContextuallyTypedParameterType(declaration); + if (type) { + return type; + } + } + if (ts.isBindingPattern(declaration.name)) { + return getTypeFromBindingPattern(declaration.name); + } + } + return undefined; + } + function getContextualTypeForReturnExpression(node) { + var func = ts.getContainingFunction(node); + if (func) { + if (func.type || func.kind === 135 || func.kind === 136 && getSetAccessorTypeAnnotationNode(ts.getDeclarationOfKind(func.symbol, 137))) { + return getReturnTypeOfSignature(getSignatureFromDeclaration(func)); + } + var signature = getContextualSignatureForFunctionLikeDeclaration(func); + if (signature) { + return getReturnTypeOfSignature(signature); + } + } + return undefined; + } + function getContextualTypeForArgument(callTarget, arg) { + var args = getEffectiveCallArguments(callTarget); + var argIndex = ts.indexOf(args, arg); + if (argIndex >= 0) { + var signature = getResolvedSignature(callTarget); + return getTypeAtPosition(signature, argIndex); + } + return undefined; + } + function getContextualTypeForSubstitutionExpression(template, substitutionExpression) { + if (template.parent.kind === 159) { + return getContextualTypeForArgument(template.parent, substitutionExpression); + } + return undefined; + } + function getContextualTypeForBinaryOperand(node) { + var binaryExpression = node.parent; + var operator = binaryExpression.operatorToken.kind; + if (operator >= 53 && operator <= 64) { + if (node === binaryExpression.right) { + return checkExpression(binaryExpression.left); + } + } + else if (operator === 49) { + var type = getContextualType(binaryExpression); + if (!type && node === binaryExpression.right) { + type = checkExpression(binaryExpression.left); + } + return type; + } + return undefined; + } + function applyToContextualType(type, mapper) { + if (!(type.flags & 16384)) { + return mapper(type); + } + var types = type.types; + var mappedType; + var mappedTypes; + for (var _i = 0; _i < types.length; _i++) { + var current = types[_i]; + var t = mapper(current); + if (t) { + if (!mappedType) { + mappedType = t; + } + else if (!mappedTypes) { + mappedTypes = [mappedType, t]; + } + else { + mappedTypes.push(t); + } + } + } + return mappedTypes ? getUnionType(mappedTypes) : mappedType; + } + function getTypeOfPropertyOfContextualType(type, name) { + return applyToContextualType(type, function (t) { + var prop = getPropertyOfObjectType(t, name); + return prop ? getTypeOfSymbol(prop) : undefined; + }); + } + function getIndexTypeOfContextualType(type, kind) { + return applyToContextualType(type, function (t) { return getIndexTypeOfObjectOrUnionType(t, kind); }); + } + function contextualTypeIsTupleLikeType(type) { + return !!(type.flags & 16384 ? ts.forEach(type.types, isTupleLikeType) : isTupleLikeType(type)); + } + function contextualTypeHasIndexSignature(type, kind) { + return !!(type.flags & 16384 ? ts.forEach(type.types, function (t) { return getIndexTypeOfObjectOrUnionType(t, kind); }) : getIndexTypeOfObjectOrUnionType(type, kind)); + } + function getContextualTypeForObjectLiteralMethod(node) { + ts.Debug.assert(ts.isObjectLiteralMethod(node)); + if (isInsideWithStatementBody(node)) { + return undefined; + } + return getContextualTypeForObjectLiteralElement(node); + } + function getContextualTypeForObjectLiteralElement(element) { + var objectLiteral = element.parent; + var type = getContextualType(objectLiteral); + if (type) { + if (!ts.hasDynamicName(element)) { + var symbolName = getSymbolOfNode(element).name; + var propertyType = getTypeOfPropertyOfContextualType(type, symbolName); + if (propertyType) { + return propertyType; + } + } + return isNumericName(element.name) && getIndexTypeOfContextualType(type, 1) || + getIndexTypeOfContextualType(type, 0); + } + return undefined; + } + function getContextualTypeForElementExpression(node) { + var arrayLiteral = node.parent; + var type = getContextualType(arrayLiteral); + if (type) { + var index = ts.indexOf(arrayLiteral.elements, node); + return getTypeOfPropertyOfContextualType(type, "" + index) + || getIndexTypeOfContextualType(type, 1) + || (languageVersion >= 2 ? checkIteratedType(type, undefined) : undefined); + } + return undefined; + } + function getContextualTypeForConditionalOperand(node) { + var conditional = node.parent; + return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined; + } + function getContextualType(node) { + if (isInsideWithStatementBody(node)) { + return undefined; + } + if (node.contextualType) { + return node.contextualType; + } + var parent = node.parent; + switch (parent.kind) { + case 198: + case 129: + case 132: + case 131: + case 152: + return getContextualTypeForInitializerExpression(node); + case 163: + case 191: + return getContextualTypeForReturnExpression(node); + case 157: + case 158: + return getContextualTypeForArgument(parent, node); + case 160: + return getTypeFromTypeNode(parent.type); + case 169: + return getContextualTypeForBinaryOperand(node); + case 224: + return getContextualTypeForObjectLiteralElement(parent); + case 153: + return getContextualTypeForElementExpression(node); + case 170: + return getContextualTypeForConditionalOperand(node); + case 176: + ts.Debug.assert(parent.parent.kind === 171); + return getContextualTypeForSubstitutionExpression(parent.parent, node); + case 161: + return getContextualType(parent); + } + return undefined; + } + function getNonGenericSignature(type) { + var signatures = getSignaturesOfObjectOrUnionType(type, 0); + if (signatures.length === 1) { + var signature = signatures[0]; + if (!signature.typeParameters) { + return signature; + } + } + } + function isFunctionExpressionOrArrowFunction(node) { + return node.kind === 162 || node.kind === 163; + } + function getContextualSignatureForFunctionLikeDeclaration(node) { + return isFunctionExpressionOrArrowFunction(node) ? getContextualSignature(node) : undefined; + } + function getContextualSignature(node) { + ts.Debug.assert(node.kind !== 134 || ts.isObjectLiteralMethod(node)); + var type = ts.isObjectLiteralMethod(node) + ? getContextualTypeForObjectLiteralMethod(node) + : getContextualType(node); + if (!type) { + return undefined; + } + if (!(type.flags & 16384)) { + return getNonGenericSignature(type); + } + var signatureList; + var types = type.types; + for (var _i = 0; _i < types.length; _i++) { + var current = types[_i]; + if (signatureList && + getSignaturesOfObjectOrUnionType(current, 0).length > 1) { + return undefined; + } + var signature = getNonGenericSignature(current); + if (signature) { + if (!signatureList) { + signatureList = [signature]; + } + else if (!compareSignatures(signatureList[0], signature, false, compareTypes)) { + return undefined; + } + else { + signatureList.push(signature); + } + } + } + var result; + if (signatureList) { + result = cloneSignature(signatureList[0]); + result.resolvedReturnType = undefined; + result.unionSignatures = signatureList; + } + return result; + } + function isInferentialContext(mapper) { + return mapper && mapper !== identityMapper; + } + function isAssignmentTarget(node) { + var parent = node.parent; + if (parent.kind === 169 && parent.operatorToken.kind === 53 && parent.left === node) { + return true; + } + if (parent.kind === 224) { + return isAssignmentTarget(parent.parent); + } + if (parent.kind === 153) { + return isAssignmentTarget(parent); + } + return false; + } + function checkSpreadElementExpression(node, contextualMapper) { + var arrayOrIterableType = checkExpressionCached(node.expression, contextualMapper); + return checkIteratedTypeOrElementType(arrayOrIterableType, node.expression, false); + } + function checkArrayLiteral(node, contextualMapper) { + var elements = node.elements; + if (!elements.length) { + return createArrayType(undefinedType); + } + var hasSpreadElement = false; + var elementTypes = []; + var inDestructuringPattern = isAssignmentTarget(node); + for (var _i = 0; _i < elements.length; _i++) { + var e = elements[_i]; + if (inDestructuringPattern && e.kind === 173) { + var restArrayType = checkExpression(e.expression, contextualMapper); + var restElementType = getIndexTypeOfType(restArrayType, 1) || + (languageVersion >= 2 ? checkIteratedType(restArrayType, undefined) : undefined); + if (restElementType) { + elementTypes.push(restElementType); + } + } + else { + var type = checkExpression(e, contextualMapper); + elementTypes.push(type); + } + hasSpreadElement = hasSpreadElement || e.kind === 173; + } + if (!hasSpreadElement) { + var contextualType = getContextualType(node); + if (contextualType && contextualTypeIsTupleLikeType(contextualType) || inDestructuringPattern) { + return createTupleType(elementTypes); + } + } + return createArrayType(getUnionType(elementTypes)); + } + function isNumericName(name) { + return name.kind === 127 ? isNumericComputedName(name) : isNumericLiteralName(name.text); + } + function isNumericComputedName(name) { + return allConstituentTypesHaveKind(checkComputedPropertyName(name), 1 | 132); + } + function isNumericLiteralName(name) { + return (+name).toString() === name; + } + function checkComputedPropertyName(node) { + var links = getNodeLinks(node.expression); + if (!links.resolvedType) { + links.resolvedType = checkExpression(node.expression); + if (!allConstituentTypesHaveKind(links.resolvedType, 1 | 132 | 258 | 1048576)) { + error(node, ts.Diagnostics.A_computed_property_name_must_be_of_type_string_number_symbol_or_any); + } + else { + checkThatExpressionIsProperSymbolReference(node.expression, links.resolvedType, true); + } + } + return links.resolvedType; + } + function checkObjectLiteral(node, contextualMapper) { + checkGrammarObjectLiteralExpression(node); + var propertiesTable = {}; + var propertiesArray = []; + var contextualType = getContextualType(node); + var typeFlags; + for (var _i = 0, _a = node.properties; _i < _a.length; _i++) { + var memberDecl = _a[_i]; + var member = memberDecl.symbol; + if (memberDecl.kind === 224 || + memberDecl.kind === 225 || + ts.isObjectLiteralMethod(memberDecl)) { + var type = void 0; + if (memberDecl.kind === 224) { + type = checkPropertyAssignment(memberDecl, contextualMapper); + } + else if (memberDecl.kind === 134) { + type = checkObjectLiteralMethod(memberDecl, contextualMapper); + } + else { + ts.Debug.assert(memberDecl.kind === 225); + type = checkExpression(memberDecl.name, contextualMapper); + } + typeFlags |= type.flags; + var prop = createSymbol(4 | 67108864 | member.flags, member.name); + prop.declarations = member.declarations; + prop.parent = member.parent; + if (member.valueDeclaration) { + prop.valueDeclaration = member.valueDeclaration; + } + prop.type = type; + prop.target = member; + member = prop; + } + else { + ts.Debug.assert(memberDecl.kind === 136 || memberDecl.kind === 137); + checkAccessorDeclaration(memberDecl); + } + if (!ts.hasDynamicName(memberDecl)) { + propertiesTable[member.name] = member; + } + propertiesArray.push(member); + } + var stringIndexType = getIndexType(0); + var numberIndexType = getIndexType(1); + var result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType); + result.flags |= 131072 | 524288 | (typeFlags & 262144); + return result; + function getIndexType(kind) { + if (contextualType && contextualTypeHasIndexSignature(contextualType, kind)) { + var propTypes = []; + for (var i = 0; i < propertiesArray.length; i++) { + var propertyDecl = node.properties[i]; + if (kind === 0 || isNumericName(propertyDecl.name)) { + var type = getTypeOfSymbol(propertiesArray[i]); + if (!ts.contains(propTypes, type)) { + propTypes.push(type); + } + } + } + var result_1 = propTypes.length ? getUnionType(propTypes) : undefinedType; + typeFlags |= result_1.flags; + return result_1; + } + return undefined; + } + } + function getDeclarationKindFromSymbol(s) { + return s.valueDeclaration ? s.valueDeclaration.kind : 132; + } + function getDeclarationFlagsFromSymbol(s) { + return s.valueDeclaration ? ts.getCombinedNodeFlags(s.valueDeclaration) : s.flags & 134217728 ? 16 | 128 : 0; + } + function checkClassPropertyAccess(node, left, type, prop) { + var flags = getDeclarationFlagsFromSymbol(prop); + if (!(flags & (32 | 64))) { + return; + } + var enclosingClassDeclaration = ts.getAncestor(node, 201); + var enclosingClass = enclosingClassDeclaration ? getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClassDeclaration)) : undefined; + var declaringClass = getDeclaredTypeOfSymbol(prop.parent); + if (flags & 32) { + if (declaringClass !== enclosingClass) { + error(node, ts.Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, symbolToString(prop), typeToString(declaringClass)); + } + return; + } + if (left.kind === 91) { + return; + } + if (!enclosingClass || !hasBaseType(enclosingClass, declaringClass)) { + error(node, ts.Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(declaringClass)); + return; + } + if (flags & 128) { + return; + } + if (!(getTargetType(type).flags & (1024 | 2048) && hasBaseType(type, enclosingClass))) { + error(node, ts.Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1, symbolToString(prop), typeToString(enclosingClass)); + } + } + function checkPropertyAccessExpression(node) { + return checkPropertyAccessExpressionOrQualifiedName(node, node.expression, node.name); + } + function checkQualifiedName(node) { + return checkPropertyAccessExpressionOrQualifiedName(node, node.left, node.right); + } + function checkPropertyAccessExpressionOrQualifiedName(node, left, right) { + var type = checkExpressionOrQualifiedName(left); + if (type === unknownType) + return type; + if (type !== anyType) { + var apparentType = getApparentType(getWidenedType(type)); + if (apparentType === unknownType) { + return unknownType; + } + var prop = getPropertyOfType(apparentType, right.text); + if (!prop) { + if (right.text) { + error(right, ts.Diagnostics.Property_0_does_not_exist_on_type_1, ts.declarationNameToString(right), typeToString(type)); + } + return unknownType; + } + getNodeLinks(node).resolvedSymbol = prop; + if (prop.parent && prop.parent.flags & 32) { + if (left.kind === 91 && getDeclarationKindFromSymbol(prop) !== 134) { + error(right, ts.Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); + } + else { + checkClassPropertyAccess(node, left, type, prop); + } + } + return getTypeOfSymbol(prop); + } + return anyType; + } + function isValidPropertyAccess(node, propertyName) { + var left = node.kind === 155 + ? node.expression + : node.left; + var type = checkExpressionOrQualifiedName(left); + if (type !== unknownType && type !== anyType) { + var prop = getPropertyOfType(getWidenedType(type), propertyName); + if (prop && prop.parent && prop.parent.flags & 32) { + if (left.kind === 91 && getDeclarationKindFromSymbol(prop) !== 134) { + return false; + } + else { + var modificationCount = diagnostics.getModificationCount(); + checkClassPropertyAccess(node, left, type, prop); + return diagnostics.getModificationCount() === modificationCount; + } + } + } + return true; + } + function checkIndexedAccess(node) { + if (!node.argumentExpression) { + var sourceFile = getSourceFile(node); + if (node.parent.kind === 158 && node.parent.expression === node) { + var start = ts.skipTrivia(sourceFile.text, node.expression.end); + var end = node.end; + grammarErrorAtPos(sourceFile, start, end - start, ts.Diagnostics.new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead); + } + else { + var start = node.end - "]".length; + var end = node.end; + grammarErrorAtPos(sourceFile, start, end - start, ts.Diagnostics.Expression_expected); + } + } + var objectType = getApparentType(checkExpression(node.expression)); + var indexType = node.argumentExpression ? checkExpression(node.argumentExpression) : unknownType; + if (objectType === unknownType) { + return unknownType; + } + var isConstEnum = isConstEnumObjectType(objectType); + if (isConstEnum && + (!node.argumentExpression || node.argumentExpression.kind !== 8)) { + error(node.argumentExpression, ts.Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal); + return unknownType; + } + if (node.argumentExpression) { + var name_3 = getPropertyNameForIndexedAccess(node.argumentExpression, indexType); + if (name_3 !== undefined) { + var prop = getPropertyOfType(objectType, name_3); + if (prop) { + getNodeLinks(node).resolvedSymbol = prop; + return getTypeOfSymbol(prop); + } + else if (isConstEnum) { + error(node.argumentExpression, ts.Diagnostics.Property_0_does_not_exist_on_const_enum_1, name_3, symbolToString(objectType.symbol)); + return unknownType; + } + } + } + if (allConstituentTypesHaveKind(indexType, 1 | 258 | 132 | 1048576)) { + if (allConstituentTypesHaveKind(indexType, 1 | 132)) { + var numberIndexType = getIndexTypeOfType(objectType, 1); + if (numberIndexType) { + return numberIndexType; + } + } + var stringIndexType = getIndexTypeOfType(objectType, 0); + if (stringIndexType) { + return stringIndexType; + } + if (compilerOptions.noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && objectType !== anyType) { + error(node, ts.Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type); + } + return anyType; + } + error(node, ts.Diagnostics.An_index_expression_argument_must_be_of_type_string_number_symbol_or_any); + return unknownType; + } + function getPropertyNameForIndexedAccess(indexArgumentExpression, indexArgumentType) { + if (indexArgumentExpression.kind === 8 || indexArgumentExpression.kind === 7) { + return indexArgumentExpression.text; + } + if (checkThatExpressionIsProperSymbolReference(indexArgumentExpression, indexArgumentType, false)) { + var rightHandSideName = indexArgumentExpression.name.text; + return ts.getPropertyNameForKnownSymbolName(rightHandSideName); + } + return undefined; + } + function checkThatExpressionIsProperSymbolReference(expression, expressionType, reportError) { + if (expressionType === unknownType) { + return false; + } + if (!ts.isWellKnownSymbolSyntactically(expression)) { + return false; + } + if ((expressionType.flags & 1048576) === 0) { + if (reportError) { + error(expression, ts.Diagnostics.A_computed_property_name_of_the_form_0_must_be_of_type_symbol, ts.getTextOfNode(expression)); + } + return false; + } + var leftHandSide = expression.expression; + var leftHandSideSymbol = getResolvedSymbol(leftHandSide); + if (!leftHandSideSymbol) { + return false; + } + var globalESSymbol = getGlobalESSymbolConstructorSymbol(); + if (!globalESSymbol) { + return false; + } + if (leftHandSideSymbol !== globalESSymbol) { + if (reportError) { + error(leftHandSide, ts.Diagnostics.Symbol_reference_does_not_refer_to_the_global_Symbol_constructor_object); + } + return false; + } + return true; + } + function resolveUntypedCall(node) { + if (node.kind === 159) { + checkExpression(node.template); + } + else { + ts.forEach(node.arguments, function (argument) { + checkExpression(argument); + }); + } + return anySignature; + } + function resolveErrorCall(node) { + resolveUntypedCall(node); + return unknownSignature; + } + function reorderCandidates(signatures, result) { + var lastParent; + var lastSymbol; + var cutoffIndex = 0; + var index; + var specializedIndex = -1; + var spliceIndex; + ts.Debug.assert(!result.length); + for (var _i = 0; _i < signatures.length; _i++) { + var signature = signatures[_i]; + var symbol = signature.declaration && getSymbolOfNode(signature.declaration); + var parent_3 = signature.declaration && signature.declaration.parent; + if (!lastSymbol || symbol === lastSymbol) { + if (lastParent && parent_3 === lastParent) { + index++; + } + else { + lastParent = parent_3; + index = cutoffIndex; + } + } + else { + index = cutoffIndex = result.length; + lastParent = parent_3; + } + lastSymbol = symbol; + if (signature.hasStringLiterals) { + specializedIndex++; + spliceIndex = specializedIndex; + cutoffIndex++; + } + else { + spliceIndex = index; + } + result.splice(spliceIndex, 0, signature); + } + } + function getSpreadArgumentIndex(args) { + for (var i = 0; i < args.length; i++) { + if (args[i].kind === 173) { + return i; + } + } + return -1; + } + function hasCorrectArity(node, args, signature) { + var adjustedArgCount; + var typeArguments; + var callIsIncomplete; + if (node.kind === 159) { + var tagExpression = node; + adjustedArgCount = args.length; + typeArguments = undefined; + if (tagExpression.template.kind === 171) { + var templateExpression = tagExpression.template; + var lastSpan = ts.lastOrUndefined(templateExpression.templateSpans); + ts.Debug.assert(lastSpan !== undefined); + callIsIncomplete = ts.nodeIsMissing(lastSpan.literal) || !!lastSpan.literal.isUnterminated; + } + else { + var templateLiteral = tagExpression.template; + ts.Debug.assert(templateLiteral.kind === 10); + callIsIncomplete = !!templateLiteral.isUnterminated; + } + } + else { + var callExpression = node; + if (!callExpression.arguments) { + ts.Debug.assert(callExpression.kind === 158); + return signature.minArgumentCount === 0; + } + adjustedArgCount = callExpression.arguments.hasTrailingComma ? args.length + 1 : args.length; + callIsIncomplete = callExpression.arguments.end === callExpression.end; + typeArguments = callExpression.typeArguments; + } + var hasRightNumberOfTypeArgs = !typeArguments || + (signature.typeParameters && typeArguments.length === signature.typeParameters.length); + if (!hasRightNumberOfTypeArgs) { + return false; + } + var spreadArgIndex = getSpreadArgumentIndex(args); + if (spreadArgIndex >= 0) { + return signature.hasRestParameter && spreadArgIndex >= signature.parameters.length - 1; + } + if (!signature.hasRestParameter && adjustedArgCount > signature.parameters.length) { + return false; + } + var hasEnoughArguments = adjustedArgCount >= signature.minArgumentCount; + return callIsIncomplete || hasEnoughArguments; + } + function getSingleCallSignature(type) { + if (type.flags & 48128) { + var resolved = resolveObjectOrUnionTypeMembers(type); + if (resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0 && + resolved.properties.length === 0 && !resolved.stringIndexType && !resolved.numberIndexType) { + return resolved.callSignatures[0]; + } + } + return undefined; + } + function instantiateSignatureInContextOf(signature, contextualSignature, contextualMapper) { + var context = createInferenceContext(signature.typeParameters, true); + forEachMatchingParameterType(contextualSignature, signature, function (source, target) { + inferTypes(context, instantiateType(source, contextualMapper), target); + }); + return getSignatureInstantiation(signature, getInferredTypes(context)); + } + function inferTypeArguments(signature, args, excludeArgument, context) { + var typeParameters = signature.typeParameters; + var inferenceMapper = createInferenceMapper(context); + for (var i = 0; i < typeParameters.length; i++) { + if (!context.inferences[i].isFixed) { + context.inferredTypes[i] = undefined; + } + } + if (context.failedTypeParameterIndex !== undefined && !context.inferences[context.failedTypeParameterIndex].isFixed) { + context.failedTypeParameterIndex = undefined; + } + for (var i = 0; i < args.length; i++) { + var arg = args[i]; + if (arg.kind !== 175) { + var paramType = getTypeAtPosition(signature, i); + var argType = void 0; + if (i === 0 && args[i].parent.kind === 159) { + argType = globalTemplateStringsArrayType; + } + else { + var mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper; + argType = checkExpressionWithContextualType(arg, paramType, mapper); + } + inferTypes(context, argType, paramType); + } + } + if (excludeArgument) { + for (var i = 0; i < args.length; i++) { + if (excludeArgument[i] === false) { + var arg = args[i]; + var paramType = getTypeAtPosition(signature, i); + inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType); + } + } + } + getInferredTypes(context); + } + function checkTypeArguments(signature, typeArguments, typeArgumentResultTypes, reportErrors) { + var typeParameters = signature.typeParameters; + var typeArgumentsAreAssignable = true; + for (var i = 0; i < typeParameters.length; i++) { + var typeArgNode = typeArguments[i]; + var typeArgument = getTypeFromTypeNode(typeArgNode); + typeArgumentResultTypes[i] = typeArgument; + if (typeArgumentsAreAssignable) { + var constraint = getConstraintOfTypeParameter(typeParameters[i]); + if (constraint) { + typeArgumentsAreAssignable = checkTypeAssignableTo(typeArgument, constraint, reportErrors ? typeArgNode : undefined, ts.Diagnostics.Type_0_does_not_satisfy_the_constraint_1); + } + } + } + return typeArgumentsAreAssignable; + } + function checkApplicableSignature(node, args, signature, relation, excludeArgument, reportErrors) { + for (var i = 0; i < args.length; i++) { + var arg = args[i]; + if (arg.kind !== 175) { + var paramType = getTypeAtPosition(signature, i); + var argType = i === 0 && node.kind === 159 + ? globalTemplateStringsArrayType + : arg.kind === 8 && !reportErrors + ? getStringLiteralType(arg) + : checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); + if (!checkTypeRelatedTo(argType, paramType, relation, reportErrors ? arg : undefined, ts.Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1)) { + return false; + } + } + } + return true; + } + function getEffectiveCallArguments(node) { + var args; + if (node.kind === 159) { + var template = node.template; + args = [template]; + if (template.kind === 171) { + ts.forEach(template.templateSpans, function (span) { + args.push(span.expression); + }); + } + } + else { + args = node.arguments || emptyArray; + } + return args; + } + function getEffectiveTypeArguments(callExpression) { + if (callExpression.expression.kind === 91) { + var containingClass = ts.getAncestor(callExpression, 201); + var baseClassTypeNode = containingClass && ts.getClassExtendsHeritageClauseElement(containingClass); + return baseClassTypeNode && baseClassTypeNode.typeArguments; + } + else { + return callExpression.typeArguments; + } + } + function resolveCall(node, signatures, candidatesOutArray) { + var isTaggedTemplate = node.kind === 159; + var typeArguments; + if (!isTaggedTemplate) { + typeArguments = getEffectiveTypeArguments(node); + if (node.expression.kind !== 91) { + ts.forEach(typeArguments, checkSourceElement); + } + } + var candidates = candidatesOutArray || []; + reorderCandidates(signatures, candidates); + if (!candidates.length) { + error(node, ts.Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target); + return resolveErrorCall(node); + } + var args = getEffectiveCallArguments(node); + var excludeArgument; + for (var i = isTaggedTemplate ? 1 : 0; i < args.length; i++) { + if (isContextSensitive(args[i])) { + if (!excludeArgument) { + excludeArgument = new Array(args.length); + } + excludeArgument[i] = true; + } + } + var candidateForArgumentError; + var candidateForTypeArgumentError; + var resultOfFailedInference; + var result; + if (candidates.length > 1) { + result = chooseOverload(candidates, subtypeRelation); + } + if (!result) { + candidateForArgumentError = undefined; + candidateForTypeArgumentError = undefined; + resultOfFailedInference = undefined; + result = chooseOverload(candidates, assignableRelation); + } + if (result) { + return result; + } + if (candidateForArgumentError) { + checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, undefined, true); + } + else if (candidateForTypeArgumentError) { + if (!isTaggedTemplate && node.typeArguments) { + checkTypeArguments(candidateForTypeArgumentError, node.typeArguments, [], true); + } + else { + ts.Debug.assert(resultOfFailedInference.failedTypeParameterIndex >= 0); + var failedTypeParameter = candidateForTypeArgumentError.typeParameters[resultOfFailedInference.failedTypeParameterIndex]; + var inferenceCandidates = getInferenceCandidates(resultOfFailedInference, resultOfFailedInference.failedTypeParameterIndex); + var diagnosticChainHead = ts.chainDiagnosticMessages(undefined, ts.Diagnostics.The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly, typeToString(failedTypeParameter)); + reportNoCommonSupertypeError(inferenceCandidates, node.expression || node.tag, diagnosticChainHead); + } + } + else { + error(node, ts.Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target); + } + if (!produceDiagnostics) { + for (var _i = 0; _i < candidates.length; _i++) { + var candidate = candidates[_i]; + if (hasCorrectArity(node, args, candidate)) { + return candidate; + } + } + } + return resolveErrorCall(node); + function chooseOverload(candidates, relation) { + for (var _i = 0; _i < candidates.length; _i++) { + var originalCandidate = candidates[_i]; + if (!hasCorrectArity(node, args, originalCandidate)) { + continue; + } + var candidate = void 0; + var typeArgumentsAreValid = void 0; + var inferenceContext = originalCandidate.typeParameters + ? createInferenceContext(originalCandidate.typeParameters, false) + : undefined; + while (true) { + candidate = originalCandidate; + if (candidate.typeParameters) { + var typeArgumentTypes = void 0; + if (typeArguments) { + typeArgumentTypes = new Array(candidate.typeParameters.length); + typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, false); + } + else { + inferTypeArguments(candidate, args, excludeArgument, inferenceContext); + typeArgumentsAreValid = inferenceContext.failedTypeParameterIndex === undefined; + typeArgumentTypes = inferenceContext.inferredTypes; + } + if (!typeArgumentsAreValid) { + break; + } + candidate = getSignatureInstantiation(candidate, typeArgumentTypes); + } + if (!checkApplicableSignature(node, args, candidate, relation, excludeArgument, false)) { + break; + } + var index = excludeArgument ? ts.indexOf(excludeArgument, true) : -1; + if (index < 0) { + return candidate; + } + excludeArgument[index] = false; + } + if (originalCandidate.typeParameters) { + var instantiatedCandidate = candidate; + if (typeArgumentsAreValid) { + candidateForArgumentError = instantiatedCandidate; + } + else { + candidateForTypeArgumentError = originalCandidate; + if (!typeArguments) { + resultOfFailedInference = inferenceContext; + } + } + } + else { + ts.Debug.assert(originalCandidate === candidate); + candidateForArgumentError = originalCandidate; + } + } + return undefined; + } + } + function resolveCallExpression(node, candidatesOutArray) { + if (node.expression.kind === 91) { + var superType = checkSuperExpression(node.expression); + if (superType !== unknownType) { + return resolveCall(node, getSignaturesOfType(superType, 1), candidatesOutArray); + } + return resolveUntypedCall(node); + } + var funcType = checkExpression(node.expression); + var apparentType = getApparentType(funcType); + if (apparentType === unknownType) { + return resolveErrorCall(node); + } + var callSignatures = getSignaturesOfType(apparentType, 0); + var constructSignatures = getSignaturesOfType(apparentType, 1); + if (funcType === anyType || (!callSignatures.length && !constructSignatures.length && !(funcType.flags & 16384) && isTypeAssignableTo(funcType, globalFunctionType))) { + if (node.typeArguments) { + error(node, ts.Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); + } + return resolveUntypedCall(node); + } + if (!callSignatures.length) { + if (constructSignatures.length) { + error(node, ts.Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); + } + else { + error(node, ts.Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature); + } + return resolveErrorCall(node); + } + return resolveCall(node, callSignatures, candidatesOutArray); + } + function resolveNewExpression(node, candidatesOutArray) { + if (node.arguments && languageVersion < 2) { + var spreadIndex = getSpreadArgumentIndex(node.arguments); + if (spreadIndex >= 0) { + error(node.arguments[spreadIndex], ts.Diagnostics.Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_6_and_higher); + } + } + var expressionType = checkExpression(node.expression); + if (expressionType === anyType) { + if (node.typeArguments) { + error(node, ts.Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); + } + return resolveUntypedCall(node); + } + expressionType = getApparentType(expressionType); + if (expressionType === unknownType) { + return resolveErrorCall(node); + } + var constructSignatures = getSignaturesOfType(expressionType, 1); + if (constructSignatures.length) { + return resolveCall(node, constructSignatures, candidatesOutArray); + } + var callSignatures = getSignaturesOfType(expressionType, 0); + if (callSignatures.length) { + var signature = resolveCall(node, callSignatures, candidatesOutArray); + if (getReturnTypeOfSignature(signature) !== voidType) { + error(node, ts.Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword); + } + return signature; + } + error(node, ts.Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature); + return resolveErrorCall(node); + } + function resolveTaggedTemplateExpression(node, candidatesOutArray) { + var tagType = checkExpression(node.tag); + var apparentType = getApparentType(tagType); + if (apparentType === unknownType) { + return resolveErrorCall(node); + } + var callSignatures = getSignaturesOfType(apparentType, 0); + if (tagType === anyType || (!callSignatures.length && !(tagType.flags & 16384) && isTypeAssignableTo(tagType, globalFunctionType))) { + return resolveUntypedCall(node); + } + if (!callSignatures.length) { + error(node, ts.Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature); + return resolveErrorCall(node); + } + return resolveCall(node, callSignatures, candidatesOutArray); + } + function getResolvedSignature(node, candidatesOutArray) { + var links = getNodeLinks(node); + if (!links.resolvedSignature || candidatesOutArray) { + links.resolvedSignature = anySignature; + if (node.kind === 157) { + links.resolvedSignature = resolveCallExpression(node, candidatesOutArray); + } + else if (node.kind === 158) { + links.resolvedSignature = resolveNewExpression(node, candidatesOutArray); + } + else if (node.kind === 159) { + links.resolvedSignature = resolveTaggedTemplateExpression(node, candidatesOutArray); + } + else { + ts.Debug.fail("Branch in 'getResolvedSignature' should be unreachable."); + } + } + return links.resolvedSignature; + } + function checkCallExpression(node) { + checkGrammarTypeArguments(node, node.typeArguments) || checkGrammarArguments(node, node.arguments); + var signature = getResolvedSignature(node); + if (node.expression.kind === 91) { + return voidType; + } + if (node.kind === 158) { + var declaration = signature.declaration; + if (declaration && + declaration.kind !== 135 && + declaration.kind !== 139 && + declaration.kind !== 143) { + if (compilerOptions.noImplicitAny) { + error(node, ts.Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type); + } + return anyType; + } + } + return getReturnTypeOfSignature(signature); + } + function checkTaggedTemplateExpression(node) { + return getReturnTypeOfSignature(getResolvedSignature(node)); + } + function checkTypeAssertion(node) { + var exprType = checkExpression(node.expression); + var targetType = getTypeFromTypeNode(node.type); + if (produceDiagnostics && targetType !== unknownType) { + var widenedType = getWidenedType(exprType); + if (!(isTypeAssignableTo(targetType, widenedType))) { + checkTypeAssignableTo(exprType, targetType, node, ts.Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other); + } + } + return targetType; + } + function getTypeAtPosition(signature, pos) { + return signature.hasRestParameter ? + pos < signature.parameters.length - 1 ? getTypeOfSymbol(signature.parameters[pos]) : getRestTypeOfSignature(signature) : + pos < signature.parameters.length ? getTypeOfSymbol(signature.parameters[pos]) : anyType; + } + function assignContextualParameterTypes(signature, context, mapper) { + var len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0); + for (var i = 0; i < len; i++) { + var parameter = signature.parameters[i]; + var links = getSymbolLinks(parameter); + links.type = instantiateType(getTypeAtPosition(context, i), mapper); + } + if (signature.hasRestParameter && context.hasRestParameter && signature.parameters.length >= context.parameters.length) { + var parameter = signature.parameters[signature.parameters.length - 1]; + var links = getSymbolLinks(parameter); + links.type = instantiateType(getTypeOfSymbol(context.parameters[context.parameters.length - 1]), mapper); + } + } + function getReturnTypeFromBody(func, contextualMapper) { + var contextualSignature = getContextualSignatureForFunctionLikeDeclaration(func); + if (!func.body) { + return unknownType; + } + var type; + if (func.body.kind !== 179) { + type = checkExpressionCached(func.body, contextualMapper); + } + else { + var types = checkAndAggregateReturnExpressionTypes(func.body, contextualMapper); + if (types.length === 0) { + return voidType; + } + type = contextualSignature ? getUnionType(types) : getCommonSupertype(types); + if (!type) { + error(func, ts.Diagnostics.No_best_common_type_exists_among_return_expressions); + return unknownType; + } + } + if (!contextualSignature) { + reportErrorsFromWidening(func, type); + } + return getWidenedType(type); + } + function checkAndAggregateReturnExpressionTypes(body, contextualMapper) { + var aggregatedTypes = []; + ts.forEachReturnStatement(body, function (returnStatement) { + var expr = returnStatement.expression; + if (expr) { + var type = checkExpressionCached(expr, contextualMapper); + if (!ts.contains(aggregatedTypes, type)) { + aggregatedTypes.push(type); + } + } + }); + return aggregatedTypes; + } + function bodyContainsAReturnStatement(funcBody) { + return ts.forEachReturnStatement(funcBody, function (returnStatement) { + return true; + }); + } + function bodyContainsSingleThrowStatement(body) { + return (body.statements.length === 1) && (body.statements[0].kind === 195); + } + function checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(func, returnType) { + if (!produceDiagnostics) { + return; + } + if (returnType === voidType || returnType === anyType) { + return; + } + if (ts.nodeIsMissing(func.body) || func.body.kind !== 179) { + return; + } + var bodyBlock = func.body; + if (bodyContainsAReturnStatement(bodyBlock)) { + return; + } + if (bodyContainsSingleThrowStatement(bodyBlock)) { + return; + } + error(func.type, ts.Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value_or_consist_of_a_single_throw_statement); + } + function checkFunctionExpressionOrObjectLiteralMethod(node, contextualMapper) { + ts.Debug.assert(node.kind !== 134 || ts.isObjectLiteralMethod(node)); + var hasGrammarError = checkGrammarDeclarationNameInStrictMode(node) || checkGrammarFunctionLikeDeclaration(node); + if (!hasGrammarError && node.kind === 162) { + checkGrammarFunctionName(node.name) || checkGrammarForGenerator(node); + } + if (contextualMapper === identityMapper && isContextSensitive(node)) { + return anyFunctionType; + } + var links = getNodeLinks(node); + var type = getTypeOfSymbol(node.symbol); + if (!(links.flags & 64)) { + var contextualSignature = getContextualSignature(node); + if (!(links.flags & 64)) { + links.flags |= 64; + if (contextualSignature) { + var signature = getSignaturesOfType(type, 0)[0]; + if (isContextSensitive(node)) { + assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper); + } + if (!node.type) { + signature.resolvedReturnType = resolvingType; + var returnType = getReturnTypeFromBody(node, contextualMapper); + if (signature.resolvedReturnType === resolvingType) { + signature.resolvedReturnType = returnType; + } + } + } + checkSignatureDeclaration(node); + } + } + if (produceDiagnostics && node.kind !== 134 && node.kind !== 133) { + checkCollisionWithCapturedSuperVariable(node, node.name); + checkCollisionWithCapturedThisVariable(node, node.name); + } + return type; + } + function checkFunctionExpressionOrObjectLiteralMethodBody(node) { + ts.Debug.assert(node.kind !== 134 || ts.isObjectLiteralMethod(node)); + if (node.type && !node.asteriskToken) { + checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type)); + } + if (node.body) { + if (node.body.kind === 179) { + checkSourceElement(node.body); + } + else { + var exprType = checkExpression(node.body); + if (node.type) { + checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), node.body, undefined); + } + checkFunctionExpressionBodies(node.body); + } + } + } + function checkArithmeticOperandType(operand, type, diagnostic) { + if (!allConstituentTypesHaveKind(type, 1 | 132)) { + error(operand, diagnostic); + return false; + } + return true; + } + function checkReferenceExpression(n, invalidReferenceMessage, constantVariableMessage) { + function findSymbol(n) { + var symbol = getNodeLinks(n).resolvedSymbol; + return symbol && getExportSymbolOfValueSymbolIfExported(symbol); + } + function isReferenceOrErrorExpression(n) { + switch (n.kind) { + case 65: { + var symbol = findSymbol(n); + return !symbol || symbol === unknownSymbol || symbol === argumentsSymbol || (symbol.flags & 3) !== 0; + } + case 155: { + var symbol = findSymbol(n); + return !symbol || symbol === unknownSymbol || (symbol.flags & ~8) !== 0; + } + case 156: + return true; + case 161: + return isReferenceOrErrorExpression(n.expression); + default: + return false; + } + } + function isConstVariableReference(n) { + switch (n.kind) { + case 65: + case 155: { + var symbol = findSymbol(n); + return symbol && (symbol.flags & 3) !== 0 && (getDeclarationFlagsFromSymbol(symbol) & 8192) !== 0; + } + case 156: { + var index = n.argumentExpression; + var symbol = findSymbol(n.expression); + if (symbol && index && index.kind === 8) { + var name_4 = index.text; + var prop = getPropertyOfType(getTypeOfSymbol(symbol), name_4); + return prop && (prop.flags & 3) !== 0 && (getDeclarationFlagsFromSymbol(prop) & 8192) !== 0; + } + return false; + } + case 161: + return isConstVariableReference(n.expression); + default: + return false; + } + } + if (!isReferenceOrErrorExpression(n)) { + error(n, invalidReferenceMessage); + return false; + } + if (isConstVariableReference(n)) { + error(n, constantVariableMessage); + return false; + } + return true; + } + function checkDeleteExpression(node) { + if (node.parserContextFlags & 1 && node.expression.kind === 65) { + grammarErrorOnNode(node.expression, ts.Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode); + } + var operandType = checkExpression(node.expression); + return booleanType; + } + function checkTypeOfExpression(node) { + var operandType = checkExpression(node.expression); + return stringType; + } + function checkVoidExpression(node) { + var operandType = checkExpression(node.expression); + return undefinedType; + } + function checkPrefixUnaryExpression(node) { + if ((node.operator === 38 || node.operator === 39)) { + checkGrammarEvalOrArgumentsInStrictMode(node, node.operand); + } + var operandType = checkExpression(node.operand); + switch (node.operator) { + case 33: + case 34: + case 47: + if (someConstituentTypeHasKind(operandType, 1048576)) { + error(node.operand, ts.Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, ts.tokenToString(node.operator)); + } + return numberType; + case 46: + return booleanType; + case 38: + case 39: + var ok = checkArithmeticOperandType(node.operand, operandType, ts.Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type); + if (ok) { + checkReferenceExpression(node.operand, ts.Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_property_or_indexer, ts.Diagnostics.The_operand_of_an_increment_or_decrement_operator_cannot_be_a_constant); + } + return numberType; + } + return unknownType; + } + function checkPostfixUnaryExpression(node) { + checkGrammarEvalOrArgumentsInStrictMode(node, node.operand); + var operandType = checkExpression(node.operand); + var ok = checkArithmeticOperandType(node.operand, operandType, ts.Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type); + if (ok) { + checkReferenceExpression(node.operand, ts.Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_property_or_indexer, ts.Diagnostics.The_operand_of_an_increment_or_decrement_operator_cannot_be_a_constant); + } + return numberType; + } + function someConstituentTypeHasKind(type, kind) { + if (type.flags & kind) { + return true; + } + if (type.flags & 16384) { + var types = type.types; + for (var _i = 0; _i < types.length; _i++) { + var current = types[_i]; + if (current.flags & kind) { + return true; + } + } + return false; + } + return false; + } + function allConstituentTypesHaveKind(type, kind) { + if (type.flags & kind) { + return true; + } + if (type.flags & 16384) { + var types = type.types; + for (var _i = 0; _i < types.length; _i++) { + var current = types[_i]; + if (!(current.flags & kind)) { + return false; + } + } + return true; + } + return false; + } + function isConstEnumObjectType(type) { + return type.flags & (48128 | 32768) && type.symbol && isConstEnumSymbol(type.symbol); + } + function isConstEnumSymbol(symbol) { + return (symbol.flags & 128) !== 0; + } + function checkInstanceOfExpression(node, leftType, rightType) { + if (allConstituentTypesHaveKind(leftType, 1049086)) { + error(node.left, ts.Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); + } + if (!(rightType.flags & 1 || isTypeSubtypeOf(rightType, globalFunctionType))) { + error(node.right, ts.Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type); + } + return booleanType; + } + function checkInExpression(node, leftType, rightType) { + if (!allConstituentTypesHaveKind(leftType, 1 | 258 | 132 | 1048576)) { + error(node.left, ts.Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol); + } + if (!allConstituentTypesHaveKind(rightType, 1 | 48128 | 512)) { + error(node.right, ts.Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); + } + return booleanType; + } + function checkObjectLiteralAssignment(node, sourceType, contextualMapper) { + var properties = node.properties; + for (var _i = 0; _i < properties.length; _i++) { + var p = properties[_i]; + if (p.kind === 224 || p.kind === 225) { + var name_5 = p.name; + var type = sourceType.flags & 1 ? sourceType : + getTypeOfPropertyOfType(sourceType, name_5.text) || + isNumericLiteralName(name_5.text) && getIndexTypeOfType(sourceType, 1) || + getIndexTypeOfType(sourceType, 0); + if (type) { + checkDestructuringAssignment(p.initializer || name_5, type); + } + else { + error(name_5, ts.Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(sourceType), ts.declarationNameToString(name_5)); + } + } + else { + error(p, ts.Diagnostics.Property_assignment_expected); + } + } + return sourceType; + } + function checkArrayLiteralAssignment(node, sourceType, contextualMapper) { + var elementType = checkIteratedTypeOrElementType(sourceType, node, false) || unknownType; + var elements = node.elements; + for (var i = 0; i < elements.length; i++) { + var e = elements[i]; + if (e.kind !== 175) { + if (e.kind !== 173) { + var propName = "" + i; + var type = sourceType.flags & 1 ? sourceType : + isTupleLikeType(sourceType) + ? getTypeOfPropertyOfType(sourceType, propName) + : elementType; + if (type) { + checkDestructuringAssignment(e, type, contextualMapper); + } + else { + if (isTupleType(sourceType)) { + error(e, ts.Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), sourceType.elementTypes.length, elements.length); + } + else { + error(e, ts.Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName); + } + } + } + else { + if (i < elements.length - 1) { + error(e, ts.Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern); + } + else { + var restExpression = e.expression; + if (restExpression.kind === 169 && restExpression.operatorToken.kind === 53) { + error(restExpression.operatorToken, ts.Diagnostics.A_rest_element_cannot_have_an_initializer); + } + else { + checkDestructuringAssignment(restExpression, createArrayType(elementType), contextualMapper); + } + } + } + } + } + return sourceType; + } + function checkDestructuringAssignment(target, sourceType, contextualMapper) { + if (target.kind === 169 && target.operatorToken.kind === 53) { + checkBinaryExpression(target, contextualMapper); + target = target.left; + } + if (target.kind === 154) { + return checkObjectLiteralAssignment(target, sourceType, contextualMapper); + } + if (target.kind === 153) { + return checkArrayLiteralAssignment(target, sourceType, contextualMapper); + } + return checkReferenceAssignment(target, sourceType, contextualMapper); + } + function checkReferenceAssignment(target, sourceType, contextualMapper) { + var targetType = checkExpression(target, contextualMapper); + if (checkReferenceExpression(target, ts.Diagnostics.Invalid_left_hand_side_of_assignment_expression, ts.Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant)) { + checkTypeAssignableTo(sourceType, targetType, target, undefined); + } + return sourceType; + } + function checkBinaryExpression(node, contextualMapper) { + if (ts.isLeftHandSideExpression(node.left) && ts.isAssignmentOperator(node.operatorToken.kind)) { + checkGrammarEvalOrArgumentsInStrictMode(node, node.left); + } + var operator = node.operatorToken.kind; + if (operator === 53 && (node.left.kind === 154 || node.left.kind === 153)) { + return checkDestructuringAssignment(node.left, checkExpression(node.right, contextualMapper), contextualMapper); + } + var leftType = checkExpression(node.left, contextualMapper); + var rightType = checkExpression(node.right, contextualMapper); + switch (operator) { + case 35: + case 56: + case 36: + case 57: + case 37: + case 58: + case 34: + case 55: + case 40: + case 59: + case 41: + case 60: + case 42: + case 61: + case 44: + case 63: + case 45: + case 64: + case 43: + case 62: + if (leftType.flags & (32 | 64)) + leftType = rightType; + if (rightType.flags & (32 | 64)) + rightType = leftType; + var suggestedOperator; + if ((leftType.flags & 8) && + (rightType.flags & 8) && + (suggestedOperator = getSuggestedBooleanOperator(node.operatorToken.kind)) !== undefined) { + error(node, ts.Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, ts.tokenToString(node.operatorToken.kind), ts.tokenToString(suggestedOperator)); + } + else { + var leftOk = checkArithmeticOperandType(node.left, leftType, ts.Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type); + var rightOk = checkArithmeticOperandType(node.right, rightType, ts.Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type); + if (leftOk && rightOk) { + checkAssignmentOperator(numberType); + } + } + return numberType; + case 33: + case 54: + if (leftType.flags & (32 | 64)) + leftType = rightType; + if (rightType.flags & (32 | 64)) + rightType = leftType; + var resultType; + if (allConstituentTypesHaveKind(leftType, 132) && allConstituentTypesHaveKind(rightType, 132)) { + resultType = numberType; + } + else { + if (allConstituentTypesHaveKind(leftType, 258) || allConstituentTypesHaveKind(rightType, 258)) { + resultType = stringType; + } + else if (leftType.flags & 1 || rightType.flags & 1) { + resultType = anyType; + } + if (resultType && !checkForDisallowedESSymbolOperand(operator)) { + return resultType; + } + } + if (!resultType) { + reportOperatorError(); + return anyType; + } + if (operator === 54) { + checkAssignmentOperator(resultType); + } + return resultType; + case 24: + case 25: + case 26: + case 27: + if (!checkForDisallowedESSymbolOperand(operator)) { + return booleanType; + } + case 28: + case 29: + case 30: + case 31: + if (!isTypeAssignableTo(leftType, rightType) && !isTypeAssignableTo(rightType, leftType)) { + reportOperatorError(); + } + return booleanType; + case 87: + return checkInstanceOfExpression(node, leftType, rightType); + case 86: + return checkInExpression(node, leftType, rightType); + case 48: + return rightType; + case 49: + return getUnionType([leftType, rightType]); + case 53: + checkAssignmentOperator(rightType); + return rightType; + case 23: + return rightType; + } + function checkForDisallowedESSymbolOperand(operator) { + var offendingSymbolOperand = someConstituentTypeHasKind(leftType, 1048576) ? node.left : + someConstituentTypeHasKind(rightType, 1048576) ? node.right : + undefined; + if (offendingSymbolOperand) { + error(offendingSymbolOperand, ts.Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, ts.tokenToString(operator)); + return false; + } + return true; + } + function getSuggestedBooleanOperator(operator) { + switch (operator) { + case 44: + case 63: + return 49; + case 45: + case 64: + return 31; + case 43: + case 62: + return 48; + default: + return undefined; + } + } + function checkAssignmentOperator(valueType) { + if (produceDiagnostics && operator >= 53 && operator <= 64) { + var ok = checkReferenceExpression(node.left, ts.Diagnostics.Invalid_left_hand_side_of_assignment_expression, ts.Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant); + if (ok) { + checkTypeAssignableTo(valueType, leftType, node.left, undefined); + } + } + } + function reportOperatorError() { + error(node, ts.Diagnostics.Operator_0_cannot_be_applied_to_types_1_and_2, ts.tokenToString(node.operatorToken.kind), typeToString(leftType), typeToString(rightType)); + } + } + function checkYieldExpression(node) { + if (!(node.parserContextFlags & 4)) { + grammarErrorOnFirstToken(node, ts.Diagnostics.yield_expression_must_be_contained_within_a_generator_declaration); + } + else { + grammarErrorOnFirstToken(node, ts.Diagnostics.yield_expressions_are_not_currently_supported); + } + } + function checkConditionalExpression(node, contextualMapper) { + checkExpression(node.condition); + var type1 = checkExpression(node.whenTrue, contextualMapper); + var type2 = checkExpression(node.whenFalse, contextualMapper); + return getUnionType([type1, type2]); + } + function checkTemplateExpression(node) { + ts.forEach(node.templateSpans, function (templateSpan) { + checkExpression(templateSpan.expression); + }); + return stringType; + } + function checkExpressionWithContextualType(node, contextualType, contextualMapper) { + var saveContextualType = node.contextualType; + node.contextualType = contextualType; + var result = checkExpression(node, contextualMapper); + node.contextualType = saveContextualType; + return result; + } + function checkExpressionCached(node, contextualMapper) { + var links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = checkExpression(node, contextualMapper); + } + return links.resolvedType; + } + function checkPropertyAssignment(node, contextualMapper) { + if (node.name.kind === 127) { + checkComputedPropertyName(node.name); + } + return checkExpression(node.initializer, contextualMapper); + } + function checkObjectLiteralMethod(node, contextualMapper) { + checkGrammarMethod(node); + if (node.name.kind === 127) { + checkComputedPropertyName(node.name); + } + var uninstantiatedType = checkFunctionExpressionOrObjectLiteralMethod(node, contextualMapper); + return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, contextualMapper); + } + function instantiateTypeWithSingleGenericCallSignature(node, type, contextualMapper) { + if (contextualMapper && contextualMapper !== identityMapper) { + var signature = getSingleCallSignature(type); + if (signature && signature.typeParameters) { + var contextualType = getContextualType(node); + if (contextualType) { + var contextualSignature = getSingleCallSignature(contextualType); + if (contextualSignature && !contextualSignature.typeParameters) { + return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, contextualMapper)); + } + } + } + } + return type; + } + function checkExpression(node, contextualMapper) { + checkGrammarIdentifierInStrictMode(node); + return checkExpressionOrQualifiedName(node, contextualMapper); + } + function checkExpressionOrQualifiedName(node, contextualMapper) { + var type; + if (node.kind == 126) { + type = checkQualifiedName(node); + } + else { + var uninstantiatedType = checkExpressionWorker(node, contextualMapper); + type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, contextualMapper); + } + if (isConstEnumObjectType(type)) { + var ok = (node.parent.kind === 155 && node.parent.expression === node) || + (node.parent.kind === 156 && node.parent.expression === node) || + ((node.kind === 65 || node.kind === 126) && isInRightSideOfImportOrExportAssignment(node)); + if (!ok) { + error(node, ts.Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment); + } + } + return type; + } + function checkNumericLiteral(node) { + checkGrammarNumericLiteral(node); + return numberType; + } + function checkExpressionWorker(node, contextualMapper) { + switch (node.kind) { + case 65: + return checkIdentifier(node); + case 93: + return checkThisExpression(node); + case 91: + return checkSuperExpression(node); + case 89: + return nullType; + case 95: + case 80: + return booleanType; + case 7: + return checkNumericLiteral(node); + case 171: + return checkTemplateExpression(node); + case 8: + case 10: + return stringType; + case 9: + return globalRegExpType; + case 153: + return checkArrayLiteral(node, contextualMapper); + case 154: + return checkObjectLiteral(node, contextualMapper); + case 155: + return checkPropertyAccessExpression(node); + case 156: + return checkIndexedAccess(node); + case 157: + case 158: + return checkCallExpression(node); + case 159: + return checkTaggedTemplateExpression(node); + case 160: + return checkTypeAssertion(node); + case 161: + return checkExpression(node.expression, contextualMapper); + case 174: + return checkClassExpression(node); + case 162: + case 163: + return checkFunctionExpressionOrObjectLiteralMethod(node, contextualMapper); + case 165: + return checkTypeOfExpression(node); + case 164: + return checkDeleteExpression(node); + case 166: + return checkVoidExpression(node); + case 167: + return checkPrefixUnaryExpression(node); + case 168: + return checkPostfixUnaryExpression(node); + case 169: + return checkBinaryExpression(node, contextualMapper); + case 170: + return checkConditionalExpression(node, contextualMapper); + case 173: + return checkSpreadElementExpression(node, contextualMapper); + case 175: + return undefinedType; + case 172: + checkYieldExpression(node); + return unknownType; + } + return unknownType; + } + function checkTypeParameter(node) { + checkGrammarDeclarationNameInStrictMode(node); + if (node.expression) { + grammarErrorOnFirstToken(node.expression, ts.Diagnostics.Type_expected); + } + checkSourceElement(node.constraint); + if (produceDiagnostics) { + checkTypeParameterHasIllegalReferencesInConstraint(node); + checkTypeNameIsReserved(node.name, ts.Diagnostics.Type_parameter_name_cannot_be_0); + } + } + function checkParameter(node) { + // Grammar checking + // It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the + // Identifier in a PropertySetParameterList of a PropertyAssignment that is contained in strict code + // or if its FunctionBody is strict code(11.1.5). + // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a + // strict mode FunctionLikeDeclaration or FunctionExpression(13.1) + checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarEvalOrArgumentsInStrictMode(node, node.name); + checkVariableLikeDeclaration(node); + var func = ts.getContainingFunction(node); + if (node.flags & 112) { + func = ts.getContainingFunction(node); + if (!(func.kind === 135 && ts.nodeIsPresent(func.body))) { + error(node, ts.Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); + } + } + if (node.questionToken && ts.isBindingPattern(node.name) && func.body) { + error(node, ts.Diagnostics.A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature); + } + if (node.dotDotDotToken && !ts.isBindingPattern(node.name) && !isArrayType(getTypeOfSymbol(node.symbol))) { + error(node, ts.Diagnostics.A_rest_parameter_must_be_of_an_array_type); + } + } + function checkSignatureDeclaration(node) { + if (node.kind === 140) { + checkGrammarIndexSignature(node); + } + else if (node.kind === 142 || node.kind === 200 || node.kind === 143 || + node.kind === 138 || node.kind === 135 || + node.kind === 139) { + checkGrammarFunctionLikeDeclaration(node); + } + checkTypeParameters(node.typeParameters); + ts.forEach(node.parameters, checkParameter); + if (node.type) { + checkSourceElement(node.type); + } + if (produceDiagnostics) { + checkCollisionWithArgumentsInGeneratedCode(node); + if (compilerOptions.noImplicitAny && !node.type) { + switch (node.kind) { + case 139: + error(node, ts.Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); + break; + case 138: + error(node, ts.Diagnostics.Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); + break; + } + } + } + checkSpecializedSignatureDeclaration(node); + } + function checkTypeForDuplicateIndexSignatures(node) { + if (node.kind === 202) { + var nodeSymbol = getSymbolOfNode(node); + if (nodeSymbol.declarations.length > 0 && nodeSymbol.declarations[0] !== node) { + return; + } + } + var indexSymbol = getIndexSymbol(getSymbolOfNode(node)); + if (indexSymbol) { + var seenNumericIndexer = false; + var seenStringIndexer = false; + for (var _i = 0, _a = indexSymbol.declarations; _i < _a.length; _i++) { + var decl = _a[_i]; + var declaration = decl; + if (declaration.parameters.length === 1 && declaration.parameters[0].type) { + switch (declaration.parameters[0].type.kind) { + case 121: + if (!seenStringIndexer) { + seenStringIndexer = true; + } + else { + error(declaration, ts.Diagnostics.Duplicate_string_index_signature); + } + break; + case 119: + if (!seenNumericIndexer) { + seenNumericIndexer = true; + } + else { + error(declaration, ts.Diagnostics.Duplicate_number_index_signature); + } + break; + } + } + } + } + } + function checkPropertyDeclaration(node) { + checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarProperty(node) || checkGrammarComputedPropertyName(node.name); + checkVariableLikeDeclaration(node); + } + function checkMethodDeclaration(node) { + checkGrammarMethod(node) || checkGrammarComputedPropertyName(node.name); + checkFunctionLikeDeclaration(node); + } + function checkConstructorDeclaration(node) { + checkSignatureDeclaration(node); + checkGrammarConstructorTypeParameters(node) || checkGrammarConstructorTypeAnnotation(node); + checkSourceElement(node.body); + var symbol = getSymbolOfNode(node); + var firstDeclaration = ts.getDeclarationOfKind(symbol, node.kind); + if (node === firstDeclaration) { + checkFunctionOrConstructorSymbol(symbol); + } + if (ts.nodeIsMissing(node.body)) { + return; + } + if (!produceDiagnostics) { + return; + } + function isSuperCallExpression(n) { + return n.kind === 157 && n.expression.kind === 91; + } + function containsSuperCall(n) { + if (isSuperCallExpression(n)) { + return true; + } + switch (n.kind) { + case 162: + case 200: + case 163: + case 154: return false; + default: return ts.forEachChild(n, containsSuperCall); + } + } + function markThisReferencesAsErrors(n) { + if (n.kind === 93) { + error(n, ts.Diagnostics.this_cannot_be_referenced_in_current_location); + } + else if (n.kind !== 162 && n.kind !== 200) { + ts.forEachChild(n, markThisReferencesAsErrors); + } + } + function isInstancePropertyWithInitializer(n) { + return n.kind === 132 && + !(n.flags & 128) && + !!n.initializer; + } + if (ts.getClassExtendsHeritageClauseElement(node.parent)) { + if (containsSuperCall(node.body)) { + var superCallShouldBeFirst = ts.forEach(node.parent.members, isInstancePropertyWithInitializer) || + ts.forEach(node.parameters, function (p) { return p.flags & (16 | 32 | 64); }); + if (superCallShouldBeFirst) { + var statements = node.body.statements; + if (!statements.length || statements[0].kind !== 182 || !isSuperCallExpression(statements[0].expression)) { + error(node, ts.Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties); + } + else { + markThisReferencesAsErrors(statements[0].expression); + } + } + } + else { + error(node, ts.Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call); + } + } + } + function checkAccessorDeclaration(node) { + if (produceDiagnostics) { + checkGrammarFunctionLikeDeclaration(node) || checkGrammarAccessor(node) || checkGrammarComputedPropertyName(node.name); + if (node.kind === 136) { + if (!ts.isInAmbientContext(node) && ts.nodeIsPresent(node.body) && !(bodyContainsAReturnStatement(node.body) || bodyContainsSingleThrowStatement(node.body))) { + error(node.name, ts.Diagnostics.A_get_accessor_must_return_a_value_or_consist_of_a_single_throw_statement); + } + } + if (!ts.hasDynamicName(node)) { + var otherKind = node.kind === 136 ? 137 : 136; + var otherAccessor = ts.getDeclarationOfKind(node.symbol, otherKind); + if (otherAccessor) { + if (((node.flags & 112) !== (otherAccessor.flags & 112))) { + error(node.name, ts.Diagnostics.Getter_and_setter_accessors_do_not_agree_in_visibility); + } + var currentAccessorType = getAnnotatedAccessorType(node); + var otherAccessorType = getAnnotatedAccessorType(otherAccessor); + if (currentAccessorType && otherAccessorType) { + if (!isTypeIdenticalTo(currentAccessorType, otherAccessorType)) { + error(node, ts.Diagnostics.get_and_set_accessor_must_have_the_same_type); + } + } + } + } + checkAndStoreTypeOfAccessors(getSymbolOfNode(node)); + } + checkFunctionLikeDeclaration(node); + } + function checkMissingDeclaration(node) { + checkDecorators(node); + } + function checkTypeReferenceNode(node) { + checkGrammarTypeReferenceInStrictMode(node.typeName); + return checkTypeReferenceOrHeritageClauseElement(node); + } + function checkHeritageClauseElement(node) { + checkGrammarHeritageClauseElementInStrictMode(node.expression); + return checkTypeReferenceOrHeritageClauseElement(node); + } + function checkTypeReferenceOrHeritageClauseElement(node) { + checkGrammarTypeArguments(node, node.typeArguments); + var type = getTypeFromTypeReferenceOrHeritageClauseElement(node); + if (type !== unknownType && node.typeArguments) { + var len = node.typeArguments.length; + for (var i = 0; i < len; i++) { + checkSourceElement(node.typeArguments[i]); + var constraint = getConstraintOfTypeParameter(type.target.typeParameters[i]); + if (produceDiagnostics && constraint) { + var typeArgument = type.typeArguments[i]; + checkTypeAssignableTo(typeArgument, constraint, node, ts.Diagnostics.Type_0_does_not_satisfy_the_constraint_1); + } + } + } + } + function checkTypeQuery(node) { + getTypeFromTypeQueryNode(node); + } + function checkTypeLiteral(node) { + ts.forEach(node.members, checkSourceElement); + if (produceDiagnostics) { + var type = getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); + checkIndexConstraints(type); + checkTypeForDuplicateIndexSignatures(node); + } + } + function checkArrayType(node) { + checkSourceElement(node.elementType); + } + function checkTupleType(node) { + var hasErrorFromDisallowedTrailingComma = checkGrammarForDisallowedTrailingComma(node.elementTypes); + if (!hasErrorFromDisallowedTrailingComma && node.elementTypes.length === 0) { + grammarErrorOnNode(node, ts.Diagnostics.A_tuple_type_element_list_cannot_be_empty); + } + ts.forEach(node.elementTypes, checkSourceElement); + } + function checkUnionType(node) { + ts.forEach(node.types, checkSourceElement); + } + function isPrivateWithinAmbient(node) { + return (node.flags & 32) && ts.isInAmbientContext(node); + } + function checkSpecializedSignatureDeclaration(signatureDeclarationNode) { + if (!produceDiagnostics) { + return; + } + var signature = getSignatureFromDeclaration(signatureDeclarationNode); + if (!signature.hasStringLiterals) { + return; + } + if (ts.nodeIsPresent(signatureDeclarationNode.body)) { + error(signatureDeclarationNode, ts.Diagnostics.A_signature_with_an_implementation_cannot_use_a_string_literal_type); + return; + } + var signaturesToCheck; + if (!signatureDeclarationNode.name && signatureDeclarationNode.parent && signatureDeclarationNode.parent.kind === 202) { + ts.Debug.assert(signatureDeclarationNode.kind === 138 || signatureDeclarationNode.kind === 139); + var signatureKind = signatureDeclarationNode.kind === 138 ? 0 : 1; + var containingSymbol = getSymbolOfNode(signatureDeclarationNode.parent); + var containingType = getDeclaredTypeOfSymbol(containingSymbol); + signaturesToCheck = getSignaturesOfType(containingType, signatureKind); + } + else { + signaturesToCheck = getSignaturesOfSymbol(getSymbolOfNode(signatureDeclarationNode)); + } + for (var _i = 0; _i < signaturesToCheck.length; _i++) { + var otherSignature = signaturesToCheck[_i]; + if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature)) { + return; + } + } + error(signatureDeclarationNode, ts.Diagnostics.Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature); + } + function getEffectiveDeclarationFlags(n, flagsToCheck) { + var flags = ts.getCombinedNodeFlags(n); + if (n.parent.kind !== 202 && ts.isInAmbientContext(n)) { + if (!(flags & 2)) { + flags |= 1; + } + flags |= 2; + } + return flags & flagsToCheck; + } + function checkFunctionOrConstructorSymbol(symbol) { + if (!produceDiagnostics) { + return; + } + function getCanonicalOverload(overloads, implementation) { + var implementationSharesContainerWithFirstOverload = implementation !== undefined && implementation.parent === overloads[0].parent; + return implementationSharesContainerWithFirstOverload ? implementation : overloads[0]; + } + function checkFlagAgreementBetweenOverloads(overloads, implementation, flagsToCheck, someOverloadFlags, allOverloadFlags) { + var someButNotAllOverloadFlags = someOverloadFlags ^ allOverloadFlags; + if (someButNotAllOverloadFlags !== 0) { + var canonicalFlags = getEffectiveDeclarationFlags(getCanonicalOverload(overloads, implementation), flagsToCheck); + ts.forEach(overloads, function (o) { + var deviation = getEffectiveDeclarationFlags(o, flagsToCheck) ^ canonicalFlags; + if (deviation & 1) { + error(o.name, ts.Diagnostics.Overload_signatures_must_all_be_exported_or_not_exported); + } + else if (deviation & 2) { + error(o.name, ts.Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient); + } + else if (deviation & (32 | 64)) { + error(o.name, ts.Diagnostics.Overload_signatures_must_all_be_public_private_or_protected); + } + }); + } + } + function checkQuestionTokenAgreementBetweenOverloads(overloads, implementation, someHaveQuestionToken, allHaveQuestionToken) { + if (someHaveQuestionToken !== allHaveQuestionToken) { + var canonicalHasQuestionToken = ts.hasQuestionToken(getCanonicalOverload(overloads, implementation)); + ts.forEach(overloads, function (o) { + var deviation = ts.hasQuestionToken(o) !== canonicalHasQuestionToken; + if (deviation) { + error(o.name, ts.Diagnostics.Overload_signatures_must_all_be_optional_or_required); + } + }); + } + } + var flagsToCheck = 1 | 2 | 32 | 64; + var someNodeFlags = 0; + var allNodeFlags = flagsToCheck; + var someHaveQuestionToken = false; + var allHaveQuestionToken = true; + var hasOverloads = false; + var bodyDeclaration; + var lastSeenNonAmbientDeclaration; + var previousDeclaration; + var declarations = symbol.declarations; + var isConstructor = (symbol.flags & 16384) !== 0; + function reportImplementationExpectedError(node) { + if (node.name && ts.nodeIsMissing(node.name)) { + return; + } + var seen = false; + var subsequentNode = ts.forEachChild(node.parent, function (c) { + if (seen) { + return c; + } + else { + seen = c === node; + } + }); + if (subsequentNode) { + if (subsequentNode.kind === node.kind) { + var errorNode_1 = subsequentNode.name || subsequentNode; + if (node.name && subsequentNode.name && node.name.text === subsequentNode.name.text) { + ts.Debug.assert(node.kind === 134 || node.kind === 133); + ts.Debug.assert((node.flags & 128) !== (subsequentNode.flags & 128)); + var diagnostic = node.flags & 128 ? ts.Diagnostics.Function_overload_must_be_static : ts.Diagnostics.Function_overload_must_not_be_static; + error(errorNode_1, diagnostic); + return; + } + else if (ts.nodeIsPresent(subsequentNode.body)) { + error(errorNode_1, ts.Diagnostics.Function_implementation_name_must_be_0, ts.declarationNameToString(node.name)); + return; + } + } + } + var errorNode = node.name || node; + if (isConstructor) { + error(errorNode, ts.Diagnostics.Constructor_implementation_is_missing); + } + else { + error(errorNode, ts.Diagnostics.Function_implementation_is_missing_or_not_immediately_following_the_declaration); + } + } + var isExportSymbolInsideModule = symbol.parent && symbol.parent.flags & 1536; + var duplicateFunctionDeclaration = false; + var multipleConstructorImplementation = false; + for (var _i = 0; _i < declarations.length; _i++) { + var current = declarations[_i]; + var node = current; + var inAmbientContext = ts.isInAmbientContext(node); + var inAmbientContextOrInterface = node.parent.kind === 202 || node.parent.kind === 145 || inAmbientContext; + if (inAmbientContextOrInterface) { + previousDeclaration = undefined; + } + if (node.kind === 200 || node.kind === 134 || node.kind === 133 || node.kind === 135) { + var currentNodeFlags = getEffectiveDeclarationFlags(node, flagsToCheck); + someNodeFlags |= currentNodeFlags; + allNodeFlags &= currentNodeFlags; + someHaveQuestionToken = someHaveQuestionToken || ts.hasQuestionToken(node); + allHaveQuestionToken = allHaveQuestionToken && ts.hasQuestionToken(node); + if (ts.nodeIsPresent(node.body) && bodyDeclaration) { + if (isConstructor) { + multipleConstructorImplementation = true; + } + else { + duplicateFunctionDeclaration = true; + } + } + else if (!isExportSymbolInsideModule && previousDeclaration && previousDeclaration.parent === node.parent && previousDeclaration.end !== node.pos) { + reportImplementationExpectedError(previousDeclaration); + } + if (ts.nodeIsPresent(node.body)) { + if (!bodyDeclaration) { + bodyDeclaration = node; + } + } + else { + hasOverloads = true; + } + previousDeclaration = node; + if (!inAmbientContextOrInterface) { + lastSeenNonAmbientDeclaration = node; + } + } + } + if (multipleConstructorImplementation) { + ts.forEach(declarations, function (declaration) { + error(declaration, ts.Diagnostics.Multiple_constructor_implementations_are_not_allowed); + }); + } + if (duplicateFunctionDeclaration) { + ts.forEach(declarations, function (declaration) { + error(declaration.name, ts.Diagnostics.Duplicate_function_implementation); + }); + } + if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body) { + reportImplementationExpectedError(lastSeenNonAmbientDeclaration); + } + if (hasOverloads) { + checkFlagAgreementBetweenOverloads(declarations, bodyDeclaration, flagsToCheck, someNodeFlags, allNodeFlags); + checkQuestionTokenAgreementBetweenOverloads(declarations, bodyDeclaration, someHaveQuestionToken, allHaveQuestionToken); + if (bodyDeclaration) { + var signatures = getSignaturesOfSymbol(symbol); + var bodySignature = getSignatureFromDeclaration(bodyDeclaration); + if (!bodySignature.hasStringLiterals) { + for (var _a = 0; _a < signatures.length; _a++) { + var signature = signatures[_a]; + if (!signature.hasStringLiterals && !isSignatureAssignableTo(bodySignature, signature)) { + error(signature.declaration, ts.Diagnostics.Overload_signature_is_not_compatible_with_function_implementation); + break; + } + } + } + } + } + } + function checkExportsOnMergedDeclarations(node) { + if (!produceDiagnostics) { + return; + } + var symbol = node.localSymbol; + if (!symbol) { + symbol = getSymbolOfNode(node); + if (!(symbol.flags & 7340032)) { + return; + } + } + if (ts.getDeclarationOfKind(symbol, node.kind) !== node) { + return; + } + var exportedDeclarationSpaces = 0; + var nonExportedDeclarationSpaces = 0; + ts.forEach(symbol.declarations, function (d) { + var declarationSpaces = getDeclarationSpaces(d); + if (getEffectiveDeclarationFlags(d, 1)) { + exportedDeclarationSpaces |= declarationSpaces; + } + else { + nonExportedDeclarationSpaces |= declarationSpaces; + } + }); + var commonDeclarationSpace = exportedDeclarationSpaces & nonExportedDeclarationSpaces; + if (commonDeclarationSpace) { + ts.forEach(symbol.declarations, function (d) { + if (getDeclarationSpaces(d) & commonDeclarationSpace) { + error(d.name, ts.Diagnostics.Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local, ts.declarationNameToString(d.name)); + } + }); + } + function getDeclarationSpaces(d) { + switch (d.kind) { + case 202: + return 2097152; + case 205: + return d.name.kind === 8 || ts.getModuleInstanceState(d) !== 0 + ? 4194304 | 1048576 + : 4194304; + case 201: + case 204: + return 2097152 | 1048576; + case 208: + var result = 0; + var target = resolveAlias(getSymbolOfNode(d)); + ts.forEach(target.declarations, function (d) { result |= getDeclarationSpaces(d); }); + return result; + default: + return 1048576; + } + } + } + function checkDecorator(node) { + var expression = node.expression; + var exprType = checkExpression(expression); + switch (node.parent.kind) { + case 201: + var classSymbol = getSymbolOfNode(node.parent); + var classConstructorType = getTypeOfSymbol(classSymbol); + var classDecoratorType = instantiateSingleCallFunctionType(getGlobalClassDecoratorType(), [classConstructorType]); + checkTypeAssignableTo(exprType, classDecoratorType, node); + break; + case 132: + checkTypeAssignableTo(exprType, getGlobalPropertyDecoratorType(), node); + break; + case 134: + case 136: + case 137: + var methodType = getTypeOfNode(node.parent); + var methodDecoratorType = instantiateSingleCallFunctionType(getGlobalMethodDecoratorType(), [methodType]); + checkTypeAssignableTo(exprType, methodDecoratorType, node); + break; + case 129: + checkTypeAssignableTo(exprType, getGlobalParameterDecoratorType(), node); + break; + } + } + function checkTypeNodeAsExpression(node) { + if (node && node.kind === 141) { + var type = getTypeFromTypeNode(node); + var shouldCheckIfUnknownType = type === unknownType && compilerOptions.separateCompilation; + if (!type || (!shouldCheckIfUnknownType && type.flags & (1048703 | 132 | 258))) { + return; + } + if (shouldCheckIfUnknownType || type.symbol.valueDeclaration) { + checkExpressionOrQualifiedName(node.typeName); + } + } + } + function checkTypeAnnotationAsExpression(node) { + switch (node.kind) { + case 132: + checkTypeNodeAsExpression(node.type); + break; + case 129: + checkTypeNodeAsExpression(node.type); + break; + case 134: + checkTypeNodeAsExpression(node.type); + break; + case 136: + checkTypeNodeAsExpression(node.type); + break; + case 137: + checkTypeNodeAsExpression(getSetAccessorTypeAnnotationNode(node)); + break; + } + } + function checkParameterTypeAnnotationsAsExpressions(node) { + for (var _i = 0, _a = node.parameters; _i < _a.length; _i++) { + var parameter = _a[_i]; + checkTypeAnnotationAsExpression(parameter); + } + } + function checkDecorators(node) { + if (!node.decorators) { + return; + } + if (!ts.nodeCanBeDecorated(node)) { + return; + } + if (compilerOptions.emitDecoratorMetadata) { + switch (node.kind) { + case 201: + var constructor = ts.getFirstConstructorWithBody(node); + if (constructor) { + checkParameterTypeAnnotationsAsExpressions(constructor); + } + break; + case 134: + checkParameterTypeAnnotationsAsExpressions(node); + case 137: + case 136: + case 132: + case 129: + checkTypeAnnotationAsExpression(node); + break; + } + } + emitDecorate = true; + if (node.kind === 129) { + emitParam = true; + } + ts.forEach(node.decorators, checkDecorator); + } + function checkFunctionDeclaration(node) { + if (produceDiagnostics) { + checkFunctionLikeDeclaration(node) || + checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) || + checkGrammarFunctionName(node.name) || + checkGrammarForGenerator(node); + checkCollisionWithCapturedSuperVariable(node, node.name); + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + } + } + function checkFunctionLikeDeclaration(node) { + checkGrammarDeclarationNameInStrictMode(node); + checkDecorators(node); + checkSignatureDeclaration(node); + if (node.name && node.name.kind === 127) { + checkComputedPropertyName(node.name); + } + if (!ts.hasDynamicName(node)) { + var symbol = getSymbolOfNode(node); + var localSymbol = node.localSymbol || symbol; + var firstDeclaration = ts.getDeclarationOfKind(localSymbol, node.kind); + if (node === firstDeclaration) { + checkFunctionOrConstructorSymbol(localSymbol); + } + if (symbol.parent) { + if (ts.getDeclarationOfKind(symbol, node.kind) === node) { + checkFunctionOrConstructorSymbol(symbol); + } + } + } + checkSourceElement(node.body); + if (node.type && !isAccessor(node.kind) && !node.asteriskToken) { + checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type)); + } + if (compilerOptions.noImplicitAny && ts.nodeIsMissing(node.body) && !node.type && !isPrivateWithinAmbient(node)) { + reportImplicitAnyError(node, anyType); + } + } + function checkBlock(node) { + if (node.kind === 179) { + checkGrammarStatementInAmbientContext(node); + } + ts.forEach(node.statements, checkSourceElement); + if (ts.isFunctionBlock(node) || node.kind === 206) { + checkFunctionExpressionBodies(node); + } + } + function checkCollisionWithArgumentsInGeneratedCode(node) { + if (!ts.hasRestParameters(node) || ts.isInAmbientContext(node) || ts.nodeIsMissing(node.body)) { + return; + } + ts.forEach(node.parameters, function (p) { + if (p.name && !ts.isBindingPattern(p.name) && p.name.text === argumentsSymbol.name) { + error(p, ts.Diagnostics.Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters); + } + }); + } + function needCollisionCheckForIdentifier(node, identifier, name) { + if (!(identifier && identifier.text === name)) { + return false; + } + if (node.kind === 132 || + node.kind === 131 || + node.kind === 134 || + node.kind === 133 || + node.kind === 136 || + node.kind === 137) { + return false; + } + if (ts.isInAmbientContext(node)) { + return false; + } + var root = getRootDeclaration(node); + if (root.kind === 129 && ts.nodeIsMissing(root.parent.body)) { + return false; + } + return true; + } + function checkCollisionWithCapturedThisVariable(node, name) { + if (needCollisionCheckForIdentifier(node, name, "_this")) { + potentialThisCollisions.push(node); + } + } + function checkIfThisIsCapturedInEnclosingScope(node) { + var current = node; + while (current) { + if (getNodeCheckFlags(current) & 4) { + var isDeclaration_1 = node.kind !== 65; + if (isDeclaration_1) { + error(node.name, ts.Diagnostics.Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference); + } + else { + error(node, ts.Diagnostics.Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference); + } + return; + } + current = current.parent; + } + } + function checkCollisionWithCapturedSuperVariable(node, name) { + if (!needCollisionCheckForIdentifier(node, name, "_super")) { + return; + } + var enclosingClass = ts.getAncestor(node, 201); + if (!enclosingClass || ts.isInAmbientContext(enclosingClass)) { + return; + } + if (ts.getClassExtendsHeritageClauseElement(enclosingClass)) { + var isDeclaration_2 = node.kind !== 65; + if (isDeclaration_2) { + error(node, ts.Diagnostics.Duplicate_identifier_super_Compiler_uses_super_to_capture_base_class_reference); + } + else { + error(node, ts.Diagnostics.Expression_resolves_to_super_that_compiler_uses_to_capture_base_class_reference); + } + } + } + function checkCollisionWithRequireExportsInGeneratedCode(node, name) { + if (!needCollisionCheckForIdentifier(node, name, "require") && !needCollisionCheckForIdentifier(node, name, "exports")) { + return; + } + if (node.kind === 205 && ts.getModuleInstanceState(node) !== 1) { + return; + } + var parent = getDeclarationContainer(node); + if (parent.kind === 227 && ts.isExternalModule(parent)) { + error(name, ts.Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_an_external_module, ts.declarationNameToString(name), ts.declarationNameToString(name)); + } + } + function checkVarDeclaredNamesNotShadowed(node) { + // - ScriptBody : StatementList + // It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList + // also occurs in the VarDeclaredNames of StatementList. + if ((ts.getCombinedNodeFlags(node) & 12288) !== 0 || isParameterDeclaration(node)) { + return; + } + if (node.kind === 198 && !node.initializer) { + return; + } + var symbol = getSymbolOfNode(node); + if (symbol.flags & 1) { + var localDeclarationSymbol = resolveName(node, node.name.text, 3, undefined, undefined); + if (localDeclarationSymbol && + localDeclarationSymbol !== symbol && + localDeclarationSymbol.flags & 2) { + if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & 12288) { + var varDeclList = ts.getAncestor(localDeclarationSymbol.valueDeclaration, 199); + var container = varDeclList.parent.kind === 180 && varDeclList.parent.parent + ? varDeclList.parent.parent + : undefined; + var namesShareScope = container && + (container.kind === 179 && ts.isFunctionLike(container.parent) || + container.kind === 206 || + container.kind === 205 || + container.kind === 227); + if (!namesShareScope) { + var name_6 = symbolToString(localDeclarationSymbol); + error(node, ts.Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name_6, name_6); + } + } + } + } + } + function isParameterDeclaration(node) { + while (node.kind === 152) { + node = node.parent.parent; + } + return node.kind === 129; + } + function checkParameterInitializer(node) { + if (getRootDeclaration(node).kind !== 129) { + return; + } + var func = ts.getContainingFunction(node); + visit(node.initializer); + function visit(n) { + if (n.kind === 65) { + var referencedSymbol = getNodeLinks(n).resolvedSymbol; + if (referencedSymbol && referencedSymbol !== unknownSymbol && getSymbol(func.locals, referencedSymbol.name, 107455) === referencedSymbol) { + if (referencedSymbol.valueDeclaration.kind === 129) { + if (referencedSymbol.valueDeclaration === node) { + error(n, ts.Diagnostics.Parameter_0_cannot_be_referenced_in_its_initializer, ts.declarationNameToString(node.name)); + return; + } + if (referencedSymbol.valueDeclaration.pos < node.pos) { + return; + } + } + error(n, ts.Diagnostics.Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it, ts.declarationNameToString(node.name), ts.declarationNameToString(n)); + } + } + else { + ts.forEachChild(n, visit); + } + } + } + function checkVariableLikeDeclaration(node) { + checkGrammarDeclarationNameInStrictMode(node); + checkDecorators(node); + checkSourceElement(node.type); + if (node.name.kind === 127) { + checkComputedPropertyName(node.name); + if (node.initializer) { + checkExpressionCached(node.initializer); + } + } + if (ts.isBindingPattern(node.name)) { + ts.forEach(node.name.elements, checkSourceElement); + } + if (node.initializer && getRootDeclaration(node).kind === 129 && ts.nodeIsMissing(ts.getContainingFunction(node).body)) { + error(node, ts.Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation); + return; + } + if (ts.isBindingPattern(node.name)) { + if (node.initializer) { + checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), node, undefined); + checkParameterInitializer(node); + } + return; + } + var symbol = getSymbolOfNode(node); + var type = getTypeOfVariableOrParameterOrProperty(symbol); + if (node === symbol.valueDeclaration) { + if (node.initializer) { + checkTypeAssignableTo(checkExpressionCached(node.initializer), type, node, undefined); + checkParameterInitializer(node); + } + } + else { + var declarationType = getWidenedTypeForVariableLikeDeclaration(node); + if (type !== unknownType && declarationType !== unknownType && !isTypeIdenticalTo(type, declarationType)) { + error(node.name, ts.Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2, ts.declarationNameToString(node.name), typeToString(type), typeToString(declarationType)); + } + if (node.initializer) { + checkTypeAssignableTo(checkExpressionCached(node.initializer), declarationType, node, undefined); + } + } + if (node.kind !== 132 && node.kind !== 131) { + checkExportsOnMergedDeclarations(node); + if (node.kind === 198 || node.kind === 152) { + checkVarDeclaredNamesNotShadowed(node); + } + checkCollisionWithCapturedSuperVariable(node, node.name); + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + } + } + function checkVariableDeclaration(node) { + checkGrammarVariableDeclaration(node); + return checkVariableLikeDeclaration(node); + } + function checkBindingElement(node) { + checkGrammarBindingElement(node); + return checkVariableLikeDeclaration(node); + } + function checkVariableStatement(node) { + checkGrammarDecorators(node) || checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) || checkGrammarModifiers(node) || checkGrammarVariableDeclarationList(node.declarationList) || checkGrammarForDisallowedLetOrConstStatement(node); + ts.forEach(node.declarationList.declarations, checkSourceElement); + } + function checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) { + if (node.modifiers) { + if (inBlockOrObjectLiteralExpression(node)) { + return grammarErrorOnFirstToken(node, ts.Diagnostics.Modifiers_cannot_appear_here); + } + } + } + function inBlockOrObjectLiteralExpression(node) { + while (node) { + if (node.kind === 179 || node.kind === 154) { + return true; + } + node = node.parent; + } + } + function checkExpressionStatement(node) { + checkGrammarStatementInAmbientContext(node); + checkExpression(node.expression); + } + function checkIfStatement(node) { + checkGrammarStatementInAmbientContext(node); + checkExpression(node.expression); + checkSourceElement(node.thenStatement); + checkSourceElement(node.elseStatement); + } + function checkDoStatement(node) { + checkGrammarStatementInAmbientContext(node); + checkSourceElement(node.statement); + checkExpression(node.expression); + } + function checkWhileStatement(node) { + checkGrammarStatementInAmbientContext(node); + checkExpression(node.expression); + checkSourceElement(node.statement); + } + function checkForStatement(node) { + if (!checkGrammarStatementInAmbientContext(node)) { + if (node.initializer && node.initializer.kind == 199) { + checkGrammarVariableDeclarationList(node.initializer); + } + } + if (node.initializer) { + if (node.initializer.kind === 199) { + ts.forEach(node.initializer.declarations, checkVariableDeclaration); + } + else { + checkExpression(node.initializer); + } + } + if (node.condition) + checkExpression(node.condition); + if (node.incrementor) + checkExpression(node.incrementor); + checkSourceElement(node.statement); + } + function checkForOfStatement(node) { + checkGrammarForInOrForOfStatement(node); + if (node.initializer.kind === 199) { + checkForInOrForOfVariableDeclaration(node); + } + else { + var varExpr = node.initializer; + var iteratedType = checkRightHandSideOfForOf(node.expression); + if (varExpr.kind === 153 || varExpr.kind === 154) { + checkDestructuringAssignment(varExpr, iteratedType || unknownType); + } + else { + var leftType = checkExpression(varExpr); + checkReferenceExpression(varExpr, ts.Diagnostics.Invalid_left_hand_side_in_for_of_statement, ts.Diagnostics.The_left_hand_side_of_a_for_of_statement_cannot_be_a_previously_defined_constant); + if (iteratedType) { + checkTypeAssignableTo(iteratedType, leftType, varExpr, undefined); + } + } + } + checkSourceElement(node.statement); + } + function checkForInStatement(node) { + checkGrammarForInOrForOfStatement(node); + if (node.initializer.kind === 199) { + var variable = node.initializer.declarations[0]; + if (variable && ts.isBindingPattern(variable.name)) { + error(variable.name, ts.Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); + } + checkForInOrForOfVariableDeclaration(node); + } + else { + var varExpr = node.initializer; + var leftType = checkExpression(varExpr); + if (varExpr.kind === 153 || varExpr.kind === 154) { + error(varExpr, ts.Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); + } + else if (!allConstituentTypesHaveKind(leftType, 1 | 258)) { + error(varExpr, ts.Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any); + } + else { + checkReferenceExpression(varExpr, ts.Diagnostics.Invalid_left_hand_side_in_for_in_statement, ts.Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_previously_defined_constant); + } + } + var rightType = checkExpression(node.expression); + if (!allConstituentTypesHaveKind(rightType, 1 | 48128 | 512)) { + error(node.expression, ts.Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter); + } + checkSourceElement(node.statement); + } + function checkForInOrForOfVariableDeclaration(iterationStatement) { + var variableDeclarationList = iterationStatement.initializer; + if (variableDeclarationList.declarations.length >= 1) { + var decl = variableDeclarationList.declarations[0]; + checkVariableDeclaration(decl); + } + } + function checkRightHandSideOfForOf(rhsExpression) { + var expressionType = getTypeOfExpression(rhsExpression); + return checkIteratedTypeOrElementType(expressionType, rhsExpression, true); + } + function checkIteratedTypeOrElementType(inputType, errorNode, allowStringInput) { + if (inputType.flags & 1) { + return inputType; + } + if (languageVersion >= 2) { + return checkIteratedType(inputType, errorNode) || anyType; + } + if (allowStringInput) { + return checkElementTypeOfArrayOrString(inputType, errorNode); + } + if (isArrayLikeType(inputType)) { + var indexType = getIndexTypeOfType(inputType, 1); + if (indexType) { + return indexType; + } + } + error(errorNode, ts.Diagnostics.Type_0_is_not_an_array_type, typeToString(inputType)); + return unknownType; + } + function checkIteratedType(iterable, errorNode) { + ts.Debug.assert(languageVersion >= 2); + var iteratedType = getIteratedType(iterable, errorNode); + if (errorNode && iteratedType) { + checkTypeAssignableTo(iterable, createIterableType(iteratedType), errorNode); + } + return iteratedType; + function getIteratedType(iterable, errorNode) { + // We want to treat type as an iterable, and get the type it is an iterable of. The iterable + // must have the following structure (annotated with the names of the variables below): + // + // { // iterable + // [Symbol.iterator]: { // iteratorFunction + // (): { // iterator + // next: { // iteratorNextFunction + // (): { // iteratorNextResult + // value: T // iteratorNextValue + // } + // } + // } + // } + // } + // + // T is the type we are after. At every level that involves analyzing return types + // of signatures, we union the return types of all the signatures. + // + // Another thing to note is that at any step of this process, we could run into a dead end, + // meaning either the property is missing, or we run into the anyType. If either of these things + // happens, we return undefined to signal that we could not find the iterated type. If a property + // is missing, and the previous step did not result in 'any', then we also give an error if the + // caller requested it. Then the caller can decide what to do in the case where there is no iterated + // type. This is different from returning anyType, because that would signify that we have matched the + // whole pattern and that T (above) is 'any'. + if (allConstituentTypesHaveKind(iterable, 1)) { + return undefined; + } + if ((iterable.flags & 4096) && iterable.target === globalIterableType) { + return iterable.typeArguments[0]; + } + var iteratorFunction = getTypeOfPropertyOfType(iterable, ts.getPropertyNameForKnownSymbolName("iterator")); + if (iteratorFunction && allConstituentTypesHaveKind(iteratorFunction, 1)) { + return undefined; + } + var iteratorFunctionSignatures = iteratorFunction ? getSignaturesOfType(iteratorFunction, 0) : emptyArray; + if (iteratorFunctionSignatures.length === 0) { + if (errorNode) { + error(errorNode, ts.Diagnostics.Type_must_have_a_Symbol_iterator_method_that_returns_an_iterator); + } + return undefined; + } + var iterator = getUnionType(ts.map(iteratorFunctionSignatures, getReturnTypeOfSignature)); + if (allConstituentTypesHaveKind(iterator, 1)) { + return undefined; + } + var iteratorNextFunction = getTypeOfPropertyOfType(iterator, "next"); + if (iteratorNextFunction && allConstituentTypesHaveKind(iteratorNextFunction, 1)) { + return undefined; + } + var iteratorNextFunctionSignatures = iteratorNextFunction ? getSignaturesOfType(iteratorNextFunction, 0) : emptyArray; + if (iteratorNextFunctionSignatures.length === 0) { + if (errorNode) { + error(errorNode, ts.Diagnostics.An_iterator_must_have_a_next_method); + } + return undefined; + } + var iteratorNextResult = getUnionType(ts.map(iteratorNextFunctionSignatures, getReturnTypeOfSignature)); + if (allConstituentTypesHaveKind(iteratorNextResult, 1)) { + return undefined; + } + var iteratorNextValue = getTypeOfPropertyOfType(iteratorNextResult, "value"); + if (!iteratorNextValue) { + if (errorNode) { + error(errorNode, ts.Diagnostics.The_type_returned_by_the_next_method_of_an_iterator_must_have_a_value_property); + } + return undefined; + } + return iteratorNextValue; + } + } + function checkElementTypeOfArrayOrString(arrayOrStringType, errorNode) { + ts.Debug.assert(languageVersion < 2); + var arrayType = removeTypesFromUnionType(arrayOrStringType, 258, true, true); + var hasStringConstituent = arrayOrStringType !== arrayType; + var reportedError = false; + if (hasStringConstituent) { + if (languageVersion < 1) { + error(errorNode, ts.Diagnostics.Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher); + reportedError = true; + } + if (arrayType === emptyObjectType) { + return stringType; + } + } + if (!isArrayLikeType(arrayType)) { + if (!reportedError) { + var diagnostic = hasStringConstituent + ? ts.Diagnostics.Type_0_is_not_an_array_type + : ts.Diagnostics.Type_0_is_not_an_array_type_or_a_string_type; + error(errorNode, diagnostic, typeToString(arrayType)); + } + return hasStringConstituent ? stringType : unknownType; + } + var arrayElementType = getIndexTypeOfType(arrayType, 1) || unknownType; + if (hasStringConstituent) { + if (arrayElementType.flags & 258) { + return stringType; + } + return getUnionType([arrayElementType, stringType]); + } + return arrayElementType; + } + function checkBreakOrContinueStatement(node) { + checkGrammarStatementInAmbientContext(node) || checkGrammarBreakOrContinueStatement(node); + } + function isGetAccessorWithAnnotatatedSetAccessor(node) { + return !!(node.kind === 136 && getSetAccessorTypeAnnotationNode(ts.getDeclarationOfKind(node.symbol, 137))); + } + function checkReturnStatement(node) { + if (!checkGrammarStatementInAmbientContext(node)) { + var functionBlock = ts.getContainingFunction(node); + if (!functionBlock) { + grammarErrorOnFirstToken(node, ts.Diagnostics.A_return_statement_can_only_be_used_within_a_function_body); + } + } + if (node.expression) { + var func = ts.getContainingFunction(node); + if (func) { + var returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func)); + var exprType = checkExpressionCached(node.expression); + if (func.kind === 137) { + error(node.expression, ts.Diagnostics.Setters_cannot_return_a_value); + } + else { + if (func.kind === 135) { + if (!isTypeAssignableTo(exprType, returnType)) { + error(node.expression, ts.Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); + } + } + else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func)) { + checkTypeAssignableTo(exprType, returnType, node.expression, undefined); + } + } + } + } + } + function checkWithStatement(node) { + if (!checkGrammarStatementInAmbientContext(node)) { + if (node.parserContextFlags & 1) { + grammarErrorOnFirstToken(node, ts.Diagnostics.with_statements_are_not_allowed_in_strict_mode); + } + } + checkExpression(node.expression); + error(node.expression, ts.Diagnostics.All_symbols_within_a_with_block_will_be_resolved_to_any); + } + function checkSwitchStatement(node) { + checkGrammarStatementInAmbientContext(node); + var firstDefaultClause; + var hasDuplicateDefaultClause = false; + var expressionType = checkExpression(node.expression); + ts.forEach(node.caseBlock.clauses, function (clause) { + if (clause.kind === 221 && !hasDuplicateDefaultClause) { + if (firstDefaultClause === undefined) { + firstDefaultClause = clause; + } + else { + var sourceFile = ts.getSourceFileOfNode(node); + var start = ts.skipTrivia(sourceFile.text, clause.pos); + var end = clause.statements.length > 0 ? clause.statements[0].pos : clause.end; + grammarErrorAtPos(sourceFile, start, end - start, ts.Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement); + hasDuplicateDefaultClause = true; + } + } + if (produceDiagnostics && clause.kind === 220) { + var caseClause = clause; + var caseType = checkExpression(caseClause.expression); + if (!isTypeAssignableTo(expressionType, caseType)) { + checkTypeAssignableTo(caseType, expressionType, caseClause.expression, undefined); + } + } + ts.forEach(clause.statements, checkSourceElement); + }); + } + function checkLabeledStatement(node) { + if (!checkGrammarStatementInAmbientContext(node)) { + var current = node.parent; + while (current) { + if (ts.isFunctionLike(current)) { + break; + } + if (current.kind === 194 && current.label.text === node.label.text) { + var sourceFile = ts.getSourceFileOfNode(node); + grammarErrorOnNode(node.label, ts.Diagnostics.Duplicate_label_0, ts.getTextOfNodeFromSourceText(sourceFile.text, node.label)); + break; + } + current = current.parent; + } + } + checkSourceElement(node.statement); + } + function checkThrowStatement(node) { + if (!checkGrammarStatementInAmbientContext(node)) { + if (node.expression === undefined) { + grammarErrorAfterFirstToken(node, ts.Diagnostics.Line_break_not_permitted_here); + } + } + if (node.expression) { + checkExpression(node.expression); + } + } + function checkTryStatement(node) { + checkGrammarStatementInAmbientContext(node); + checkBlock(node.tryBlock); + var catchClause = node.catchClause; + if (catchClause) { + if (catchClause.variableDeclaration) { + if (catchClause.variableDeclaration.name.kind !== 65) { + grammarErrorOnFirstToken(catchClause.variableDeclaration.name, ts.Diagnostics.Catch_clause_variable_name_must_be_an_identifier); + } + else if (catchClause.variableDeclaration.type) { + grammarErrorOnFirstToken(catchClause.variableDeclaration.type, ts.Diagnostics.Catch_clause_variable_cannot_have_a_type_annotation); + } + else if (catchClause.variableDeclaration.initializer) { + grammarErrorOnFirstToken(catchClause.variableDeclaration.initializer, ts.Diagnostics.Catch_clause_variable_cannot_have_an_initializer); + } + else { + var identifierName = catchClause.variableDeclaration.name.text; + var locals = catchClause.block.locals; + if (locals && ts.hasProperty(locals, identifierName)) { + var localSymbol = locals[identifierName]; + if (localSymbol && (localSymbol.flags & 2) !== 0) { + grammarErrorOnNode(localSymbol.valueDeclaration, ts.Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, identifierName); + } + } + checkGrammarEvalOrArgumentsInStrictMode(node, catchClause.variableDeclaration.name); + } + } + checkBlock(catchClause.block); + } + if (node.finallyBlock) { + checkBlock(node.finallyBlock); + } + } + function checkIndexConstraints(type) { + var declaredNumberIndexer = getIndexDeclarationOfSymbol(type.symbol, 1); + var declaredStringIndexer = getIndexDeclarationOfSymbol(type.symbol, 0); + var stringIndexType = getIndexTypeOfType(type, 0); + var numberIndexType = getIndexTypeOfType(type, 1); + if (stringIndexType || numberIndexType) { + ts.forEach(getPropertiesOfObjectType(type), function (prop) { + var propType = getTypeOfSymbol(prop); + checkIndexConstraintForProperty(prop, propType, type, declaredStringIndexer, stringIndexType, 0); + checkIndexConstraintForProperty(prop, propType, type, declaredNumberIndexer, numberIndexType, 1); + }); + if (type.flags & 1024 && type.symbol.valueDeclaration.kind === 201) { + var classDeclaration = type.symbol.valueDeclaration; + for (var _i = 0, _a = classDeclaration.members; _i < _a.length; _i++) { + var member = _a[_i]; + if (!(member.flags & 128) && ts.hasDynamicName(member)) { + var propType = getTypeOfSymbol(member.symbol); + checkIndexConstraintForProperty(member.symbol, propType, type, declaredStringIndexer, stringIndexType, 0); + checkIndexConstraintForProperty(member.symbol, propType, type, declaredNumberIndexer, numberIndexType, 1); + } + } + } + } + var errorNode; + if (stringIndexType && numberIndexType) { + errorNode = declaredNumberIndexer || declaredStringIndexer; + if (!errorNode && (type.flags & 2048)) { + var someBaseTypeHasBothIndexers = ts.forEach(getBaseTypes(type), function (base) { return getIndexTypeOfType(base, 0) && getIndexTypeOfType(base, 1); }); + errorNode = someBaseTypeHasBothIndexers ? undefined : type.symbol.declarations[0]; + } + } + if (errorNode && !isTypeAssignableTo(numberIndexType, stringIndexType)) { + error(errorNode, ts.Diagnostics.Numeric_index_type_0_is_not_assignable_to_string_index_type_1, typeToString(numberIndexType), typeToString(stringIndexType)); + } + function checkIndexConstraintForProperty(prop, propertyType, containingType, indexDeclaration, indexType, indexKind) { + if (!indexType) { + return; + } + if (indexKind === 1 && !isNumericName(prop.valueDeclaration.name)) { + return; + } + var errorNode; + if (prop.valueDeclaration.name.kind === 127 || prop.parent === containingType.symbol) { + errorNode = prop.valueDeclaration; + } + else if (indexDeclaration) { + errorNode = indexDeclaration; + } + else if (containingType.flags & 2048) { + var someBaseClassHasBothPropertyAndIndexer = ts.forEach(getBaseTypes(containingType), function (base) { return getPropertyOfObjectType(base, prop.name) && getIndexTypeOfType(base, indexKind); }); + errorNode = someBaseClassHasBothPropertyAndIndexer ? undefined : containingType.symbol.declarations[0]; + } + if (errorNode && !isTypeAssignableTo(propertyType, indexType)) { + var errorMessage = indexKind === 0 + ? ts.Diagnostics.Property_0_of_type_1_is_not_assignable_to_string_index_type_2 + : ts.Diagnostics.Property_0_of_type_1_is_not_assignable_to_numeric_index_type_2; + error(errorNode, errorMessage, symbolToString(prop), typeToString(propertyType), typeToString(indexType)); + } + } + } + function checkTypeNameIsReserved(name, message) { + switch (name.text) { + case "any": + case "number": + case "boolean": + case "string": + case "symbol": + case "void": + error(name, message, name.text); + } + } + function checkTypeParameters(typeParameterDeclarations) { + if (typeParameterDeclarations) { + for (var i = 0, n = typeParameterDeclarations.length; i < n; i++) { + var node = typeParameterDeclarations[i]; + checkTypeParameter(node); + if (produceDiagnostics) { + for (var j = 0; j < i; j++) { + if (typeParameterDeclarations[j].symbol === node.symbol) { + error(node.name, ts.Diagnostics.Duplicate_identifier_0, ts.declarationNameToString(node.name)); + } + } + } + } + } + } + function checkClassExpression(node) { + grammarErrorOnNode(node, ts.Diagnostics.class_expressions_are_not_currently_supported); + ts.forEach(node.members, checkSourceElement); + return unknownType; + } + function checkClassDeclaration(node) { + checkGrammarDeclarationNameInStrictMode(node); + if (node.parent.kind !== 206 && node.parent.kind !== 227) { + grammarErrorOnNode(node, ts.Diagnostics.class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration); + } + if (!node.name && !(node.flags & 256)) { + grammarErrorOnFirstToken(node, ts.Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); + } + checkGrammarClassDeclarationHeritageClauses(node); + checkDecorators(node); + if (node.name) { + checkTypeNameIsReserved(node.name, ts.Diagnostics.Class_name_cannot_be_0); + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + } + checkTypeParameters(node.typeParameters); + checkExportsOnMergedDeclarations(node); + var symbol = getSymbolOfNode(node); + var type = getDeclaredTypeOfSymbol(symbol); + var staticType = getTypeOfSymbol(symbol); + var baseTypeNode = ts.getClassExtendsHeritageClauseElement(node); + if (baseTypeNode) { + if (!ts.isSupportedHeritageClauseElement(baseTypeNode)) { + error(baseTypeNode.expression, ts.Diagnostics.Only_identifiers_Slashqualified_names_with_optional_type_arguments_are_currently_supported_in_a_class_extends_clauses); + } + emitExtends = emitExtends || !ts.isInAmbientContext(node); + checkHeritageClauseElement(baseTypeNode); + } + var baseTypes = getBaseTypes(type); + if (baseTypes.length) { + if (produceDiagnostics) { + var baseType = baseTypes[0]; + checkTypeAssignableTo(type, baseType, node.name || node, ts.Diagnostics.Class_0_incorrectly_extends_base_class_1); + var staticBaseType = getTypeOfSymbol(baseType.symbol); + checkTypeAssignableTo(staticType, getTypeWithoutConstructors(staticBaseType), node.name || node, ts.Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1); + if (baseType.symbol !== resolveEntityName(baseTypeNode.expression, 107455)) { + error(baseTypeNode, ts.Diagnostics.Type_name_0_in_extends_clause_does_not_reference_constructor_function_for_0, typeToString(baseType)); + } + checkKindsOfPropertyMemberOverrides(type, baseType); + } + } + if (baseTypes.length || (baseTypeNode && compilerOptions.separateCompilation)) { + checkExpressionOrQualifiedName(baseTypeNode.expression); + } + var implementedTypeNodes = ts.getClassImplementsHeritageClauseElements(node); + if (implementedTypeNodes) { + ts.forEach(implementedTypeNodes, function (typeRefNode) { + if (!ts.isSupportedHeritageClauseElement(typeRefNode)) { + error(typeRefNode.expression, ts.Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments); + } + checkHeritageClauseElement(typeRefNode); + if (produceDiagnostics) { + var t = getTypeFromHeritageClauseElement(typeRefNode); + if (t !== unknownType) { + var declaredType = (t.flags & 4096) ? t.target : t; + if (declaredType.flags & (1024 | 2048)) { + checkTypeAssignableTo(type, t, node.name || node, ts.Diagnostics.Class_0_incorrectly_implements_interface_1); + } + else { + error(typeRefNode, ts.Diagnostics.A_class_may_only_implement_another_class_or_interface); + } + } + } + }); + } + ts.forEach(node.members, checkSourceElement); + if (produceDiagnostics) { + checkIndexConstraints(type); + checkTypeForDuplicateIndexSignatures(node); + } + } + function getTargetSymbol(s) { + return s.flags & 16777216 ? getSymbolLinks(s).target : s; + } + function checkKindsOfPropertyMemberOverrides(type, baseType) { + // TypeScript 1.0 spec (April 2014): 8.2.3 + // A derived class inherits all members from its base class it doesn't override. + // Inheritance means that a derived class implicitly contains all non - overridden members of the base class. + // Both public and private property members are inherited, but only public property members can be overridden. + // A property member in a derived class is said to override a property member in a base class + // when the derived class property member has the same name and kind(instance or static) + // as the base class property member. + // The type of an overriding property member must be assignable(section 3.8.4) + // to the type of the overridden property member, or otherwise a compile - time error occurs. + // Base class instance member functions can be overridden by derived class instance member functions, + // but not by other kinds of members. + // Base class instance member variables and accessors can be overridden by + // derived class instance member variables and accessors, but not by other kinds of members. + var baseProperties = getPropertiesOfObjectType(baseType); + for (var _i = 0; _i < baseProperties.length; _i++) { + var baseProperty = baseProperties[_i]; + var base = getTargetSymbol(baseProperty); + if (base.flags & 134217728) { + continue; + } + var derived = getTargetSymbol(getPropertyOfObjectType(type, base.name)); + if (derived) { + var baseDeclarationFlags = getDeclarationFlagsFromSymbol(base); + var derivedDeclarationFlags = getDeclarationFlagsFromSymbol(derived); + if ((baseDeclarationFlags & 32) || (derivedDeclarationFlags & 32)) { + continue; + } + if ((baseDeclarationFlags & 128) !== (derivedDeclarationFlags & 128)) { + continue; + } + if ((base.flags & derived.flags & 8192) || ((base.flags & 98308) && (derived.flags & 98308))) { + continue; + } + var errorMessage = void 0; + if (base.flags & 8192) { + if (derived.flags & 98304) { + errorMessage = ts.Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor; + } + else { + ts.Debug.assert((derived.flags & 4) !== 0); + errorMessage = ts.Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property; + } + } + else if (base.flags & 4) { + ts.Debug.assert((derived.flags & 8192) !== 0); + errorMessage = ts.Diagnostics.Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function; + } + else { + ts.Debug.assert((base.flags & 98304) !== 0); + ts.Debug.assert((derived.flags & 8192) !== 0); + errorMessage = ts.Diagnostics.Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function; + } + error(derived.valueDeclaration.name, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type)); + } + } + } + function isAccessor(kind) { + return kind === 136 || kind === 137; + } + function areTypeParametersIdentical(list1, list2) { + if (!list1 && !list2) { + return true; + } + if (!list1 || !list2 || list1.length !== list2.length) { + return false; + } + for (var i = 0, len = list1.length; i < len; i++) { + var tp1 = list1[i]; + var tp2 = list2[i]; + if (tp1.name.text !== tp2.name.text) { + return false; + } + if (!tp1.constraint && !tp2.constraint) { + continue; + } + if (!tp1.constraint || !tp2.constraint) { + return false; + } + if (!isTypeIdenticalTo(getTypeFromTypeNode(tp1.constraint), getTypeFromTypeNode(tp2.constraint))) { + return false; + } + } + return true; + } + function checkInheritedPropertiesAreIdentical(type, typeNode) { + var baseTypes = getBaseTypes(type); + if (baseTypes.length < 2) { + return true; + } + var seen = {}; + ts.forEach(resolveDeclaredMembers(type).declaredProperties, function (p) { seen[p.name] = { prop: p, containingType: type }; }); + var ok = true; + for (var _i = 0; _i < baseTypes.length; _i++) { + var base = baseTypes[_i]; + var properties = getPropertiesOfObjectType(base); + for (var _a = 0; _a < properties.length; _a++) { + var prop = properties[_a]; + if (!ts.hasProperty(seen, prop.name)) { + seen[prop.name] = { prop: prop, containingType: base }; + } + else { + var existing = seen[prop.name]; + var isInheritedProperty = existing.containingType !== type; + if (isInheritedProperty && !isPropertyIdenticalTo(existing.prop, prop)) { + ok = false; + var typeName1 = typeToString(existing.containingType); + var typeName2 = typeToString(base); + var errorInfo = ts.chainDiagnosticMessages(undefined, ts.Diagnostics.Named_property_0_of_types_1_and_2_are_not_identical, symbolToString(prop), typeName1, typeName2); + errorInfo = ts.chainDiagnosticMessages(errorInfo, ts.Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, typeToString(type), typeName1, typeName2); + diagnostics.add(ts.createDiagnosticForNodeFromMessageChain(typeNode, errorInfo)); + } + } + } + } + return ok; + } + function checkInterfaceDeclaration(node) { + checkGrammarDeclarationNameInStrictMode(node) || checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarInterfaceDeclaration(node); + checkTypeParameters(node.typeParameters); + if (produceDiagnostics) { + checkTypeNameIsReserved(node.name, ts.Diagnostics.Interface_name_cannot_be_0); + checkExportsOnMergedDeclarations(node); + var symbol = getSymbolOfNode(node); + var firstInterfaceDecl = ts.getDeclarationOfKind(symbol, 202); + if (symbol.declarations.length > 1) { + if (node !== firstInterfaceDecl && !areTypeParametersIdentical(firstInterfaceDecl.typeParameters, node.typeParameters)) { + error(node.name, ts.Diagnostics.All_declarations_of_an_interface_must_have_identical_type_parameters); + } + } + if (node === firstInterfaceDecl) { + var type = getDeclaredTypeOfSymbol(symbol); + if (checkInheritedPropertiesAreIdentical(type, node.name)) { + ts.forEach(getBaseTypes(type), function (baseType) { + checkTypeAssignableTo(type, baseType, node.name, ts.Diagnostics.Interface_0_incorrectly_extends_interface_1); + }); + checkIndexConstraints(type); + } + } + } + ts.forEach(ts.getInterfaceBaseTypeNodes(node), function (heritageElement) { + if (!ts.isSupportedHeritageClauseElement(heritageElement)) { + error(heritageElement.expression, ts.Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments); + } + checkHeritageClauseElement(heritageElement); + }); + ts.forEach(node.members, checkSourceElement); + if (produceDiagnostics) { + checkTypeForDuplicateIndexSignatures(node); + } + } + function checkTypeAliasDeclaration(node) { + checkGrammarDecorators(node) || checkGrammarModifiers(node); + checkTypeNameIsReserved(node.name, ts.Diagnostics.Type_alias_name_cannot_be_0); + checkSourceElement(node.type); + } + function computeEnumMemberValues(node) { + var nodeLinks = getNodeLinks(node); + if (!(nodeLinks.flags & 128)) { + var enumSymbol = getSymbolOfNode(node); + var enumType = getDeclaredTypeOfSymbol(enumSymbol); + var autoValue = 0; + var ambient = ts.isInAmbientContext(node); + var enumIsConst = ts.isConst(node); + ts.forEach(node.members, function (member) { + if (member.name.kind !== 127 && isNumericLiteralName(member.name.text)) { + error(member.name, ts.Diagnostics.An_enum_member_cannot_have_a_numeric_name); + } + var initializer = member.initializer; + if (initializer) { + autoValue = getConstantValueForEnumMemberInitializer(initializer); + if (autoValue === undefined) { + if (enumIsConst) { + error(initializer, ts.Diagnostics.In_const_enum_declarations_member_initializer_must_be_constant_expression); + } + else if (!ambient) { + checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, undefined); + } + } + else if (enumIsConst) { + if (isNaN(autoValue)) { + error(initializer, ts.Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN); + } + else if (!isFinite(autoValue)) { + error(initializer, ts.Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value); + } + } + } + else if (ambient && !enumIsConst) { + autoValue = undefined; + } + if (autoValue !== undefined) { + getNodeLinks(member).enumMemberValue = autoValue++; + } + }); + nodeLinks.flags |= 128; + } + function getConstantValueForEnumMemberInitializer(initializer) { + return evalConstant(initializer); + function evalConstant(e) { + switch (e.kind) { + case 167: + var value = evalConstant(e.operand); + if (value === undefined) { + return undefined; + } + switch (e.operator) { + case 33: return value; + case 34: return -value; + case 47: return ~value; + } + return undefined; + case 169: + var left = evalConstant(e.left); + if (left === undefined) { + return undefined; + } + var right = evalConstant(e.right); + if (right === undefined) { + return undefined; + } + switch (e.operatorToken.kind) { + case 44: return left | right; + case 43: return left & right; + case 41: return left >> right; + case 42: return left >>> right; + case 40: return left << right; + case 45: return left ^ right; + case 35: return left * right; + case 36: return left / right; + case 33: return left + right; + case 34: return left - right; + case 37: return left % right; + } + return undefined; + case 7: + return +e.text; + case 161: + return evalConstant(e.expression); + case 65: + case 156: + case 155: + var member = initializer.parent; + var currentType = getTypeOfSymbol(getSymbolOfNode(member.parent)); + var enumType; + var propertyName; + if (e.kind === 65) { + enumType = currentType; + propertyName = e.text; + } + else { + var expression; + if (e.kind === 156) { + if (e.argumentExpression === undefined || + e.argumentExpression.kind !== 8) { + return undefined; + } + expression = e.expression; + propertyName = e.argumentExpression.text; + } + else { + expression = e.expression; + propertyName = e.name.text; + } + var current = expression; + while (current) { + if (current.kind === 65) { + break; + } + else if (current.kind === 155) { + current = current.expression; + } + else { + return undefined; + } + } + enumType = checkExpression(expression); + if (!(enumType.symbol && (enumType.symbol.flags & 384))) { + return undefined; + } + } + if (propertyName === undefined) { + return undefined; + } + var property = getPropertyOfObjectType(enumType, propertyName); + if (!property || !(property.flags & 8)) { + return undefined; + } + var propertyDecl = property.valueDeclaration; + if (member === propertyDecl) { + return undefined; + } + if (!isDefinedBefore(propertyDecl, member)) { + return undefined; + } + return getNodeLinks(propertyDecl).enumMemberValue; + } + } + } + } + function checkEnumDeclaration(node) { + if (!produceDiagnostics) { + return; + } + checkGrammarDeclarationNameInStrictMode(node) || checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarEnumDeclaration(node); + checkTypeNameIsReserved(node.name, ts.Diagnostics.Enum_name_cannot_be_0); + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + checkExportsOnMergedDeclarations(node); + computeEnumMemberValues(node); + var enumIsConst = ts.isConst(node); + if (compilerOptions.separateCompilation && enumIsConst && ts.isInAmbientContext(node)) { + error(node.name, ts.Diagnostics.Ambient_const_enums_are_not_allowed_when_the_separateCompilation_flag_is_provided); + } + var enumSymbol = getSymbolOfNode(node); + var firstDeclaration = ts.getDeclarationOfKind(enumSymbol, node.kind); + if (node === firstDeclaration) { + if (enumSymbol.declarations.length > 1) { + ts.forEach(enumSymbol.declarations, function (decl) { + if (ts.isConstEnumDeclaration(decl) !== enumIsConst) { + error(decl.name, ts.Diagnostics.Enum_declarations_must_all_be_const_or_non_const); + } + }); + } + var seenEnumMissingInitialInitializer = false; + ts.forEach(enumSymbol.declarations, function (declaration) { + if (declaration.kind !== 204) { + return false; + } + var enumDeclaration = declaration; + if (!enumDeclaration.members.length) { + return false; + } + var firstEnumMember = enumDeclaration.members[0]; + if (!firstEnumMember.initializer) { + if (seenEnumMissingInitialInitializer) { + error(firstEnumMember.name, ts.Diagnostics.In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element); + } + else { + seenEnumMissingInitialInitializer = true; + } + } + }); + } + } + function getFirstNonAmbientClassOrFunctionDeclaration(symbol) { + var declarations = symbol.declarations; + for (var _i = 0; _i < declarations.length; _i++) { + var declaration = declarations[_i]; + if ((declaration.kind === 201 || + (declaration.kind === 200 && ts.nodeIsPresent(declaration.body))) && + !ts.isInAmbientContext(declaration)) { + return declaration; + } + } + return undefined; + } + function inSameLexicalScope(node1, node2) { + var container1 = ts.getEnclosingBlockScopeContainer(node1); + var container2 = ts.getEnclosingBlockScopeContainer(node2); + if (isGlobalSourceFile(container1)) { + return isGlobalSourceFile(container2); + } + else if (isGlobalSourceFile(container2)) { + return false; + } + else { + return container1 === container2; + } + } + function checkModuleDeclaration(node) { + if (produceDiagnostics) { + if (!checkGrammarDeclarationNameInStrictMode(node) && !checkGrammarDecorators(node) && !checkGrammarModifiers(node)) { + if (!ts.isInAmbientContext(node) && node.name.kind === 8) { + grammarErrorOnNode(node.name, ts.Diagnostics.Only_ambient_modules_can_use_quoted_names); + } + } + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + checkExportsOnMergedDeclarations(node); + var symbol = getSymbolOfNode(node); + if (symbol.flags & 512 + && symbol.declarations.length > 1 + && !ts.isInAmbientContext(node) + && ts.isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.separateCompilation)) { + var firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol); + if (firstNonAmbientClassOrFunc) { + if (ts.getSourceFileOfNode(node) !== ts.getSourceFileOfNode(firstNonAmbientClassOrFunc)) { + error(node.name, ts.Diagnostics.A_module_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged); + } + else if (node.pos < firstNonAmbientClassOrFunc.pos) { + error(node.name, ts.Diagnostics.A_module_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged); + } + } + var mergedClass = ts.getDeclarationOfKind(symbol, 201); + if (mergedClass && + inSameLexicalScope(node, mergedClass)) { + getNodeLinks(node).flags |= 2048; + } + } + if (node.name.kind === 8) { + if (!isGlobalSourceFile(node.parent)) { + error(node.name, ts.Diagnostics.Ambient_external_modules_cannot_be_nested_in_other_modules); + } + if (isExternalModuleNameRelative(node.name.text)) { + error(node.name, ts.Diagnostics.Ambient_external_module_declaration_cannot_specify_relative_module_name); + } + } + } + checkSourceElement(node.body); + } + function getFirstIdentifier(node) { + while (true) { + if (node.kind === 126) { + node = node.left; + } + else if (node.kind === 155) { + node = node.expression; + } + else { + break; + } + } + ts.Debug.assert(node.kind === 65); + return node; + } + function checkExternalImportOrExportDeclaration(node) { + var moduleName = ts.getExternalModuleName(node); + if (!ts.nodeIsMissing(moduleName) && moduleName.kind !== 8) { + error(moduleName, ts.Diagnostics.String_literal_expected); + return false; + } + var inAmbientExternalModule = node.parent.kind === 206 && node.parent.parent.name.kind === 8; + if (node.parent.kind !== 227 && !inAmbientExternalModule) { + error(moduleName, node.kind === 215 ? + ts.Diagnostics.Export_declarations_are_not_permitted_in_an_internal_module : + ts.Diagnostics.Import_declarations_in_an_internal_module_cannot_reference_an_external_module); + return false; + } + if (inAmbientExternalModule && isExternalModuleNameRelative(moduleName.text)) { + error(node, ts.Diagnostics.Import_or_export_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name); + return false; + } + return true; + } + function checkAliasSymbol(node) { + var symbol = getSymbolOfNode(node); + var target = resolveAlias(symbol); + if (target !== unknownSymbol) { + var excludedMeanings = (symbol.flags & 107455 ? 107455 : 0) | + (symbol.flags & 793056 ? 793056 : 0) | + (symbol.flags & 1536 ? 1536 : 0); + if (target.flags & excludedMeanings) { + var message = node.kind === 217 ? + ts.Diagnostics.Export_declaration_conflicts_with_exported_declaration_of_0 : + ts.Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0; + error(node, message, symbolToString(symbol)); + } + } + } + function checkImportBinding(node) { + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + checkAliasSymbol(node); + } + function checkImportDeclaration(node) { + if (!checkGrammarImportDeclarationNameInStrictMode(node) && !checkGrammarDecorators(node) && !checkGrammarModifiers(node) && (node.flags & 499)) { + grammarErrorOnFirstToken(node, ts.Diagnostics.An_import_declaration_cannot_have_modifiers); + } + if (checkExternalImportOrExportDeclaration(node)) { + var importClause = node.importClause; + if (importClause) { + if (importClause.name) { + checkImportBinding(importClause); + } + if (importClause.namedBindings) { + if (importClause.namedBindings.kind === 211) { + checkImportBinding(importClause.namedBindings); + } + else { + ts.forEach(importClause.namedBindings.elements, checkImportBinding); + } + } + } + } + } + function checkImportEqualsDeclaration(node) { + checkGrammarDeclarationNameInStrictMode(node) || checkGrammarDecorators(node) || checkGrammarModifiers(node); + if (ts.isInternalModuleImportEqualsDeclaration(node) || checkExternalImportOrExportDeclaration(node)) { + checkImportBinding(node); + if (node.flags & 1) { + markExportAsReferenced(node); + } + if (ts.isInternalModuleImportEqualsDeclaration(node)) { + var target = resolveAlias(getSymbolOfNode(node)); + if (target !== unknownSymbol) { + if (target.flags & 107455) { + var moduleName = getFirstIdentifier(node.moduleReference); + if (!(resolveEntityName(moduleName, 107455 | 1536).flags & 1536)) { + error(moduleName, ts.Diagnostics.Module_0_is_hidden_by_a_local_declaration_with_the_same_name, ts.declarationNameToString(moduleName)); + } + } + if (target.flags & 793056) { + checkTypeNameIsReserved(node.name, ts.Diagnostics.Import_name_cannot_be_0); + } + } + } + else { + if (languageVersion >= 2) { + grammarErrorOnNode(node, ts.Diagnostics.Import_assignment_cannot_be_used_when_targeting_ECMAScript_6_or_higher_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_or_import_d_from_mod_instead); + } + } + } + } + function checkExportDeclaration(node) { + if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && (node.flags & 499)) { + grammarErrorOnFirstToken(node, ts.Diagnostics.An_export_declaration_cannot_have_modifiers); + } + if (!node.moduleSpecifier || checkExternalImportOrExportDeclaration(node)) { + if (node.exportClause) { + ts.forEach(node.exportClause.elements, checkExportSpecifier); + var inAmbientExternalModule = node.parent.kind === 206 && node.parent.parent.name.kind === 8; + if (node.parent.kind !== 227 && !inAmbientExternalModule) { + error(node, ts.Diagnostics.Export_declarations_are_not_permitted_in_an_internal_module); + } + } + else { + var moduleSymbol = resolveExternalModuleName(node, node.moduleSpecifier); + if (moduleSymbol && moduleSymbol.exports["export="]) { + error(node.moduleSpecifier, ts.Diagnostics.External_module_0_uses_export_and_cannot_be_used_with_export_Asterisk, symbolToString(moduleSymbol)); + } + } + } + } + function checkExportSpecifier(node) { + checkAliasSymbol(node); + if (!node.parent.parent.moduleSpecifier) { + markExportAsReferenced(node); + } + } + function checkExportAssignment(node) { + var container = node.parent.kind === 227 ? node.parent : node.parent.parent; + if (container.kind === 205 && container.name.kind === 65) { + error(node, ts.Diagnostics.An_export_assignment_cannot_be_used_in_an_internal_module); + return; + } + if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && (node.flags & 499)) { + grammarErrorOnFirstToken(node, ts.Diagnostics.An_export_assignment_cannot_have_modifiers); + } + if (node.expression.kind === 65) { + markExportAsReferenced(node); + } + else { + checkExpressionCached(node.expression); + } + checkExternalModuleExports(container); + if (node.isExportEquals && languageVersion >= 2) { + grammarErrorOnNode(node, ts.Diagnostics.Export_assignment_cannot_be_used_when_targeting_ECMAScript_6_or_higher_Consider_using_export_default_instead); + } + } + function getModuleStatements(node) { + if (node.kind === 227) { + return node.statements; + } + if (node.kind === 205 && node.body.kind === 206) { + return node.body.statements; + } + return emptyArray; + } + function hasExportedMembers(moduleSymbol) { + for (var id in moduleSymbol.exports) { + if (id !== "export=") { + return true; + } + } + return false; + } + function checkExternalModuleExports(node) { + var moduleSymbol = getSymbolOfNode(node); + var links = getSymbolLinks(moduleSymbol); + if (!links.exportsChecked) { + var exportEqualsSymbol = moduleSymbol.exports["export="]; + if (exportEqualsSymbol && hasExportedMembers(moduleSymbol)) { + var declaration = getDeclarationOfAliasSymbol(exportEqualsSymbol) || exportEqualsSymbol.valueDeclaration; + error(declaration, ts.Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements); + } + links.exportsChecked = true; + } + } + function checkSourceElement(node) { + if (!node) + return; + switch (node.kind) { + case 128: + return checkTypeParameter(node); + case 129: + return checkParameter(node); + case 132: + case 131: + return checkPropertyDeclaration(node); + case 142: + case 143: + case 138: + case 139: + return checkSignatureDeclaration(node); + case 140: + return checkSignatureDeclaration(node); + case 134: + case 133: + return checkMethodDeclaration(node); + case 135: + return checkConstructorDeclaration(node); + case 136: + case 137: + return checkAccessorDeclaration(node); + case 141: + return checkTypeReferenceNode(node); + case 144: + return checkTypeQuery(node); + case 145: + return checkTypeLiteral(node); + case 146: + return checkArrayType(node); + case 147: + return checkTupleType(node); + case 148: + return checkUnionType(node); + case 149: + return checkSourceElement(node.type); + case 200: + return checkFunctionDeclaration(node); + case 179: + case 206: + return checkBlock(node); + case 180: + return checkVariableStatement(node); + case 182: + return checkExpressionStatement(node); + case 183: + return checkIfStatement(node); + case 184: + return checkDoStatement(node); + case 185: + return checkWhileStatement(node); + case 186: + return checkForStatement(node); + case 187: + return checkForInStatement(node); + case 188: + return checkForOfStatement(node); + case 189: + case 190: + return checkBreakOrContinueStatement(node); + case 191: + return checkReturnStatement(node); + case 192: + return checkWithStatement(node); + case 193: + return checkSwitchStatement(node); + case 194: + return checkLabeledStatement(node); + case 195: + return checkThrowStatement(node); + case 196: + return checkTryStatement(node); + case 198: + return checkVariableDeclaration(node); + case 152: + return checkBindingElement(node); + case 201: + return checkClassDeclaration(node); + case 202: + return checkInterfaceDeclaration(node); + case 203: + return checkTypeAliasDeclaration(node); + case 204: + return checkEnumDeclaration(node); + case 205: + return checkModuleDeclaration(node); + case 209: + return checkImportDeclaration(node); + case 208: + return checkImportEqualsDeclaration(node); + case 215: + return checkExportDeclaration(node); + case 214: + return checkExportAssignment(node); + case 181: + checkGrammarStatementInAmbientContext(node); + return; + case 197: + checkGrammarStatementInAmbientContext(node); + return; + case 218: + return checkMissingDeclaration(node); + } + } + function checkFunctionExpressionBodies(node) { + switch (node.kind) { + case 162: + case 163: + ts.forEach(node.parameters, checkFunctionExpressionBodies); + checkFunctionExpressionOrObjectLiteralMethodBody(node); + break; + case 134: + case 133: + ts.forEach(node.parameters, checkFunctionExpressionBodies); + if (ts.isObjectLiteralMethod(node)) { + checkFunctionExpressionOrObjectLiteralMethodBody(node); + } + break; + case 135: + case 136: + case 137: + case 200: + ts.forEach(node.parameters, checkFunctionExpressionBodies); + break; + case 192: + checkFunctionExpressionBodies(node.expression); + break; + case 129: + case 132: + case 131: + case 150: + case 151: + case 152: + case 153: + case 154: + case 224: + case 155: + case 156: + case 157: + case 158: + case 159: + case 171: + case 176: + case 160: + case 161: + case 165: + case 166: + case 164: + case 167: + case 168: + case 169: + case 170: + case 173: + case 179: + case 206: + case 180: + case 182: + case 183: + case 184: + case 185: + case 186: + case 187: + case 188: + case 189: + case 190: + case 191: + case 193: + case 207: + case 220: + case 221: + case 194: + case 195: + case 196: + case 223: + case 198: + case 199: + case 201: + case 204: + case 226: + case 214: + case 227: + ts.forEachChild(node, checkFunctionExpressionBodies); + break; + } + } + function checkSourceFile(node) { + var start = new Date().getTime(); + checkSourceFileWorker(node); + ts.checkTime += new Date().getTime() - start; + } + function checkSourceFileWorker(node) { + var links = getNodeLinks(node); + if (!(links.flags & 1)) { + checkGrammarSourceFile(node); + emitExtends = false; + emitDecorate = false; + emitParam = false; + potentialThisCollisions.length = 0; + ts.forEach(node.statements, checkSourceElement); + checkFunctionExpressionBodies(node); + if (ts.isExternalModule(node)) { + checkExternalModuleExports(node); + } + if (potentialThisCollisions.length) { + ts.forEach(potentialThisCollisions, checkIfThisIsCapturedInEnclosingScope); + potentialThisCollisions.length = 0; + } + if (emitExtends) { + links.flags |= 8; + } + if (emitDecorate) { + links.flags |= 512; + } + if (emitParam) { + links.flags |= 1024; + } + links.flags |= 1; + } + } + function getDiagnostics(sourceFile) { + throwIfNonDiagnosticsProducing(); + if (sourceFile) { + checkSourceFile(sourceFile); + return diagnostics.getDiagnostics(sourceFile.fileName); + } + ts.forEach(host.getSourceFiles(), checkSourceFile); + return diagnostics.getDiagnostics(); + } + function getGlobalDiagnostics() { + throwIfNonDiagnosticsProducing(); + return diagnostics.getGlobalDiagnostics(); + } + function throwIfNonDiagnosticsProducing() { + if (!produceDiagnostics) { + throw new Error("Trying to get diagnostics from a type checker that does not produce them."); + } + } + function isInsideWithStatementBody(node) { + if (node) { + while (node.parent) { + if (node.parent.kind === 192 && node.parent.statement === node) { + return true; + } + node = node.parent; + } + } + return false; + } + function getSymbolsInScope(location, meaning) { + var symbols = {}; + var memberFlags = 0; + if (isInsideWithStatementBody(location)) { + return []; + } + populateSymbols(); + return symbolsToArray(symbols); + function populateSymbols() { + while (location) { + if (location.locals && !isGlobalSourceFile(location)) { + copySymbols(location.locals, meaning); + } + switch (location.kind) { + case 227: + if (!ts.isExternalModule(location)) { + break; + } + case 205: + copySymbols(getSymbolOfNode(location).exports, meaning & 8914931); + break; + case 204: + copySymbols(getSymbolOfNode(location).exports, meaning & 8); + break; + case 201: + case 202: + if (!(memberFlags & 128)) { + copySymbols(getSymbolOfNode(location).members, meaning & 793056); + } + break; + case 162: + if (location.name) { + copySymbol(location.symbol, meaning); + } + break; + } + memberFlags = location.flags; + location = location.parent; + } + copySymbols(globals, meaning); + } + function copySymbol(symbol, meaning) { + if (symbol.flags & meaning) { + var id = symbol.name; + if (!isReservedMemberName(id) && !ts.hasProperty(symbols, id)) { + symbols[id] = symbol; + } + } + } + function copySymbols(source, meaning) { + if (meaning) { + for (var id in source) { + if (ts.hasProperty(source, id)) { + copySymbol(source[id], meaning); + } + } + } + } + if (isInsideWithStatementBody(location)) { + return []; + } + while (location) { + if (location.locals && !isGlobalSourceFile(location)) { + copySymbols(location.locals, meaning); + } + switch (location.kind) { + case 227: + if (!ts.isExternalModule(location)) + break; + case 205: + copySymbols(getSymbolOfNode(location).exports, meaning & 8914931); + break; + case 204: + copySymbols(getSymbolOfNode(location).exports, meaning & 8); + break; + case 201: + case 202: + if (!(memberFlags & 128)) { + copySymbols(getSymbolOfNode(location).members, meaning & 793056); + } + break; + case 162: + if (location.name) { + copySymbol(location.symbol, meaning); + } + break; + } + memberFlags = location.flags; + location = location.parent; + } + copySymbols(globals, meaning); + return symbolsToArray(symbols); + } + function isTypeDeclarationName(name) { + return name.kind == 65 && + isTypeDeclaration(name.parent) && + name.parent.name === name; + } + function isTypeDeclaration(node) { + switch (node.kind) { + case 128: + case 201: + case 202: + case 203: + case 204: + return true; + } + } + function isTypeReferenceIdentifier(entityName) { + var node = entityName; + while (node.parent && node.parent.kind === 126) { + node = node.parent; + } + return node.parent && node.parent.kind === 141; + } + function isHeritageClauseElementIdentifier(entityName) { + var node = entityName; + while (node.parent && node.parent.kind === 155) { + node = node.parent; + } + return node.parent && node.parent.kind === 177; + } + function isTypeNode(node) { + if (141 <= node.kind && node.kind <= 149) { + return true; + } + switch (node.kind) { + case 112: + case 119: + case 121: + case 113: + case 122: + return true; + case 99: + return node.parent.kind !== 166; + case 8: + return node.parent.kind === 129; + case 177: + return true; + case 65: + if (node.parent.kind === 126 && node.parent.right === node) { + node = node.parent; + } + else if (node.parent.kind === 155 && node.parent.name === node) { + node = node.parent; + } + case 126: + case 155: + ts.Debug.assert(node.kind === 65 || node.kind === 126 || node.kind === 155, "'node' was expected to be a qualified name, identifier or property access in 'isTypeNode'."); + var parent_4 = node.parent; + if (parent_4.kind === 144) { + return false; + } + if (141 <= parent_4.kind && parent_4.kind <= 149) { + return true; + } + switch (parent_4.kind) { + case 177: + return true; + case 128: + return node === parent_4.constraint; + case 132: + case 131: + case 129: + case 198: + return node === parent_4.type; + case 200: + case 162: + case 163: + case 135: + case 134: + case 133: + case 136: + case 137: + return node === parent_4.type; + case 138: + case 139: + case 140: + return node === parent_4.type; + case 160: + return node === parent_4.type; + case 157: + case 158: + return parent_4.typeArguments && ts.indexOf(parent_4.typeArguments, node) >= 0; + case 159: + return false; + } + } + return false; + } + function getLeftSideOfImportEqualsOrExportAssignment(nodeOnRightSide) { + while (nodeOnRightSide.parent.kind === 126) { + nodeOnRightSide = nodeOnRightSide.parent; + } + if (nodeOnRightSide.parent.kind === 208) { + return nodeOnRightSide.parent.moduleReference === nodeOnRightSide && nodeOnRightSide.parent; + } + if (nodeOnRightSide.parent.kind === 214) { + return nodeOnRightSide.parent.expression === nodeOnRightSide && nodeOnRightSide.parent; + } + return undefined; + } + function isInRightSideOfImportOrExportAssignment(node) { + return getLeftSideOfImportEqualsOrExportAssignment(node) !== undefined; + } + function getSymbolOfEntityNameOrPropertyAccessExpression(entityName) { + if (ts.isDeclarationName(entityName)) { + return getSymbolOfNode(entityName.parent); + } + if (entityName.parent.kind === 214) { + return resolveEntityName(entityName, 107455 | 793056 | 1536 | 8388608); + } + if (entityName.kind !== 155) { + if (isInRightSideOfImportOrExportAssignment(entityName)) { + return getSymbolOfPartOfRightHandSideOfImportEquals(entityName); + } + } + if (ts.isRightSideOfQualifiedNameOrPropertyAccess(entityName)) { + entityName = entityName.parent; + } + if (isHeritageClauseElementIdentifier(entityName)) { + var meaning = entityName.parent.kind === 177 ? 793056 : 1536; + meaning |= 8388608; + return resolveEntityName(entityName, meaning); + } + else if (ts.isExpression(entityName)) { + if (ts.nodeIsMissing(entityName)) { + return undefined; + } + if (entityName.kind === 65) { + var meaning = 107455 | 8388608; + return resolveEntityName(entityName, meaning); + } + else if (entityName.kind === 155) { + var symbol = getNodeLinks(entityName).resolvedSymbol; + if (!symbol) { + checkPropertyAccessExpression(entityName); + } + return getNodeLinks(entityName).resolvedSymbol; + } + else if (entityName.kind === 126) { + var symbol = getNodeLinks(entityName).resolvedSymbol; + if (!symbol) { + checkQualifiedName(entityName); + } + return getNodeLinks(entityName).resolvedSymbol; + } + } + else if (isTypeReferenceIdentifier(entityName)) { + var meaning = entityName.parent.kind === 141 ? 793056 : 1536; + meaning |= 8388608; + return resolveEntityName(entityName, meaning); + } + return undefined; + } + function getSymbolInfo(node) { + if (isInsideWithStatementBody(node)) { + return undefined; + } + if (ts.isDeclarationName(node)) { + return getSymbolOfNode(node.parent); + } + if (node.kind === 65 && isInRightSideOfImportOrExportAssignment(node)) { + return node.parent.kind === 214 + ? getSymbolOfEntityNameOrPropertyAccessExpression(node) + : getSymbolOfPartOfRightHandSideOfImportEquals(node); + } + switch (node.kind) { + case 65: + case 155: + case 126: + return getSymbolOfEntityNameOrPropertyAccessExpression(node); + case 93: + case 91: + var type = checkExpression(node); + return type.symbol; + case 114: + var constructorDeclaration = node.parent; + if (constructorDeclaration && constructorDeclaration.kind === 135) { + return constructorDeclaration.parent.symbol; + } + return undefined; + case 8: + var moduleName; + if ((ts.isExternalModuleImportEqualsDeclaration(node.parent.parent) && + ts.getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) || + ((node.parent.kind === 209 || node.parent.kind === 215) && + node.parent.moduleSpecifier === node)) { + return resolveExternalModuleName(node, node); + } + case 7: + if (node.parent.kind == 156 && node.parent.argumentExpression === node) { + var objectType = checkExpression(node.parent.expression); + if (objectType === unknownType) + return undefined; + var apparentType = getApparentType(objectType); + if (apparentType === unknownType) + return undefined; + return getPropertyOfType(apparentType, node.text); + } + break; + } + return undefined; + } + function getShorthandAssignmentValueSymbol(location) { + if (location && location.kind === 225) { + return resolveEntityName(location.name, 107455); + } + return undefined; + } + function getTypeOfNode(node) { + if (isInsideWithStatementBody(node)) { + return unknownType; + } + if (isTypeNode(node)) { + return getTypeFromTypeNode(node); + } + if (ts.isExpression(node)) { + return getTypeOfExpression(node); + } + if (isTypeDeclaration(node)) { + var symbol = getSymbolOfNode(node); + return getDeclaredTypeOfSymbol(symbol); + } + if (isTypeDeclarationName(node)) { + var symbol = getSymbolInfo(node); + return symbol && getDeclaredTypeOfSymbol(symbol); + } + if (ts.isDeclaration(node)) { + var symbol = getSymbolOfNode(node); + return getTypeOfSymbol(symbol); + } + if (ts.isDeclarationName(node)) { + var symbol = getSymbolInfo(node); + return symbol && getTypeOfSymbol(symbol); + } + if (isInRightSideOfImportOrExportAssignment(node)) { + var symbol = getSymbolInfo(node); + var declaredType = symbol && getDeclaredTypeOfSymbol(symbol); + return declaredType !== unknownType ? declaredType : getTypeOfSymbol(symbol); + } + return unknownType; + } + function getTypeOfExpression(expr) { + if (ts.isRightSideOfQualifiedNameOrPropertyAccess(expr)) { + expr = expr.parent; + } + return checkExpression(expr); + } + function getAugmentedPropertiesOfType(type) { + type = getApparentType(type); + var propsByName = createSymbolTable(getPropertiesOfType(type)); + if (getSignaturesOfType(type, 0).length || getSignaturesOfType(type, 1).length) { + ts.forEach(getPropertiesOfType(globalFunctionType), function (p) { + if (!ts.hasProperty(propsByName, p.name)) { + propsByName[p.name] = p; + } + }); + } + return getNamedMembers(propsByName); + } + function getRootSymbols(symbol) { + if (symbol.flags & 268435456) { + var symbols = []; + var name_7 = symbol.name; + ts.forEach(getSymbolLinks(symbol).unionType.types, function (t) { + symbols.push(getPropertyOfType(t, name_7)); + }); + return symbols; + } + else if (symbol.flags & 67108864) { + var target = getSymbolLinks(symbol).target; + if (target) { + return [target]; + } + } + return [symbol]; + } + function isExternalModuleSymbol(symbol) { + return symbol.flags & 512 && symbol.declarations.length === 1 && symbol.declarations[0].kind === 227; + } + function getAliasNameSubstitution(symbol, getGeneratedNameForNode) { + if (languageVersion >= 2) { + return undefined; + } + var node = getDeclarationOfAliasSymbol(symbol); + if (node) { + if (node.kind === 210) { + var defaultKeyword; + if (languageVersion === 0) { + defaultKeyword = "[\"default\"]"; + } + else { + defaultKeyword = ".default"; + } + return getGeneratedNameForNode(node.parent) + defaultKeyword; + } + if (node.kind === 213) { + var moduleName = getGeneratedNameForNode(node.parent.parent.parent); + var propertyName = node.propertyName || node.name; + return moduleName + "." + ts.unescapeIdentifier(propertyName.text); + } + } + } + function getExportNameSubstitution(symbol, location, getGeneratedNameForNode) { + if (isExternalModuleSymbol(symbol.parent)) { + if (languageVersion >= 2) { + return undefined; + } + return "exports." + ts.unescapeIdentifier(symbol.name); + } + var node = location; + var containerSymbol = getParentOfSymbol(symbol); + while (node) { + if ((node.kind === 205 || node.kind === 204) && getSymbolOfNode(node) === containerSymbol) { + return getGeneratedNameForNode(node) + "." + ts.unescapeIdentifier(symbol.name); + } + node = node.parent; + } + } + function getExpressionNameSubstitution(node, getGeneratedNameForNode) { + var symbol = getNodeLinks(node).resolvedSymbol || (ts.isDeclarationName(node) ? getSymbolOfNode(node.parent) : undefined); + if (symbol) { + if (symbol.parent) { + return getExportNameSubstitution(symbol, node.parent, getGeneratedNameForNode); + } + var exportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); + if (symbol !== exportSymbol && !(exportSymbol.flags & 944)) { + return getExportNameSubstitution(exportSymbol, node.parent, getGeneratedNameForNode); + } + if (symbol.flags & 8388608) { + return getAliasNameSubstitution(symbol, getGeneratedNameForNode); + } + } + } + function isValueAliasDeclaration(node) { + switch (node.kind) { + case 208: + case 210: + case 211: + case 213: + case 217: + return isAliasResolvedToValue(getSymbolOfNode(node)); + case 215: + var exportClause = node.exportClause; + return exportClause && ts.forEach(exportClause.elements, isValueAliasDeclaration); + case 214: + return node.expression && node.expression.kind === 65 ? isAliasResolvedToValue(getSymbolOfNode(node)) : true; + } + return false; + } + function isTopLevelValueImportEqualsWithEntityName(node) { + if (node.parent.kind !== 227 || !ts.isInternalModuleImportEqualsDeclaration(node)) { + return false; + } + var isValue = isAliasResolvedToValue(getSymbolOfNode(node)); + return isValue && node.moduleReference && !ts.nodeIsMissing(node.moduleReference); + } + function isAliasResolvedToValue(symbol) { + var target = resolveAlias(symbol); + if (target === unknownSymbol && compilerOptions.separateCompilation) { + return true; + } + return target !== unknownSymbol && target && target.flags & 107455 && !isConstEnumOrConstEnumOnlyModule(target); + } + function isConstEnumOrConstEnumOnlyModule(s) { + return isConstEnumSymbol(s) || s.constEnumOnlyModule; + } + function isReferencedAliasDeclaration(node, checkChildren) { + if (ts.isAliasSymbolDeclaration(node)) { + var symbol = getSymbolOfNode(node); + if (getSymbolLinks(symbol).referenced) { + return true; + } + } + if (checkChildren) { + return ts.forEachChild(node, function (node) { return isReferencedAliasDeclaration(node, checkChildren); }); + } + return false; + } + function isImplementationOfOverload(node) { + if (ts.nodeIsPresent(node.body)) { + var symbol = getSymbolOfNode(node); + var signaturesOfSymbol = getSignaturesOfSymbol(symbol); + return signaturesOfSymbol.length > 1 || + (signaturesOfSymbol.length === 1 && signaturesOfSymbol[0].declaration !== node); + } + return false; + } + function getNodeCheckFlags(node) { + return getNodeLinks(node).flags; + } + function getEnumMemberValue(node) { + computeEnumMemberValues(node.parent); + return getNodeLinks(node).enumMemberValue; + } + function getConstantValue(node) { + if (node.kind === 226) { + return getEnumMemberValue(node); + } + var symbol = getNodeLinks(node).resolvedSymbol; + if (symbol && (symbol.flags & 8)) { + if (ts.isConstEnumDeclaration(symbol.valueDeclaration.parent)) { + return getEnumMemberValue(symbol.valueDeclaration); + } + } + return undefined; + } + function serializeEntityName(node, getGeneratedNameForNode, fallbackPath) { + if (node.kind === 65) { + var substitution = getExpressionNameSubstitution(node, getGeneratedNameForNode); + var text = substitution || node.text; + if (fallbackPath) { + fallbackPath.push(text); + } + else { + return text; + } + } + else { + var left = serializeEntityName(node.left, getGeneratedNameForNode, fallbackPath); + var right = serializeEntityName(node.right, getGeneratedNameForNode, fallbackPath); + if (!fallbackPath) { + return left + "." + right; + } + } + } + function serializeTypeReferenceNode(node, getGeneratedNameForNode) { + var type = getTypeFromTypeReference(node); + if (type.flags & 16) { + return "void 0"; + } + else if (type.flags & 8) { + return "Boolean"; + } + else if (type.flags & 132) { + return "Number"; + } + else if (type.flags & 258) { + return "String"; + } + else if (type.flags & 8192) { + return "Array"; + } + else if (type.flags & 1048576) { + return "Symbol"; + } + else if (type === unknownType) { + var fallbackPath = []; + serializeEntityName(node.typeName, getGeneratedNameForNode, fallbackPath); + return fallbackPath; + } + else if (type.symbol && type.symbol.valueDeclaration) { + return serializeEntityName(node.typeName, getGeneratedNameForNode); + } + else if (typeHasCallOrConstructSignatures(type)) { + return "Function"; + } + return "Object"; + } + function serializeTypeNode(node, getGeneratedNameForNode) { + if (node) { + switch (node.kind) { + case 99: + return "void 0"; + case 149: + return serializeTypeNode(node.type, getGeneratedNameForNode); + case 142: + case 143: + return "Function"; + case 146: + case 147: + return "Array"; + case 113: + return "Boolean"; + case 121: + case 8: + return "String"; + case 119: + return "Number"; + case 141: + return serializeTypeReferenceNode(node, getGeneratedNameForNode); + case 144: + case 145: + case 148: + case 112: + break; + default: + ts.Debug.fail("Cannot serialize unexpected type node."); + break; + } + } + return "Object"; + } + function serializeTypeOfNode(node, getGeneratedNameForNode) { + switch (node.kind) { + case 201: return "Function"; + case 132: return serializeTypeNode(node.type, getGeneratedNameForNode); + case 129: return serializeTypeNode(node.type, getGeneratedNameForNode); + case 136: return serializeTypeNode(node.type, getGeneratedNameForNode); + case 137: return serializeTypeNode(getSetAccessorTypeAnnotationNode(node), getGeneratedNameForNode); + } + if (ts.isFunctionLike(node)) { + return "Function"; + } + return "void 0"; + } + function serializeParameterTypesOfNode(node, getGeneratedNameForNode) { + if (node) { + var valueDeclaration; + if (node.kind === 201) { + valueDeclaration = ts.getFirstConstructorWithBody(node); + } + else if (ts.isFunctionLike(node) && ts.nodeIsPresent(node.body)) { + valueDeclaration = node; + } + if (valueDeclaration) { + var result; + var parameters = valueDeclaration.parameters; + var parameterCount = parameters.length; + if (parameterCount > 0) { + result = new Array(parameterCount); + for (var i = 0; i < parameterCount; i++) { + if (parameters[i].dotDotDotToken) { + var parameterType = parameters[i].type; + if (parameterType.kind === 146) { + parameterType = parameterType.elementType; + } + else if (parameterType.kind === 141 && parameterType.typeArguments && parameterType.typeArguments.length === 1) { + parameterType = parameterType.typeArguments[0]; + } + else { + parameterType = undefined; + } + result[i] = serializeTypeNode(parameterType, getGeneratedNameForNode); + } + else { + result[i] = serializeTypeOfNode(parameters[i], getGeneratedNameForNode); + } + } + return result; + } + } + } + return emptyArray; + } + function serializeReturnTypeOfNode(node, getGeneratedNameForNode) { + if (node && ts.isFunctionLike(node)) { + return serializeTypeNode(node.type, getGeneratedNameForNode); + } + return "void 0"; + } + function writeTypeOfDeclaration(declaration, enclosingDeclaration, flags, writer) { + var symbol = getSymbolOfNode(declaration); + var type = symbol && !(symbol.flags & (2048 | 131072)) + ? getTypeOfSymbol(symbol) + : unknownType; + getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); + } + function writeReturnTypeOfSignatureDeclaration(signatureDeclaration, enclosingDeclaration, flags, writer) { + var signature = getSignatureFromDeclaration(signatureDeclaration); + getSymbolDisplayBuilder().buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags); + } + function writeTypeOfExpression(expr, enclosingDeclaration, flags, writer) { + var type = getTypeOfExpression(expr); + getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); + } + function hasGlobalName(name) { + return ts.hasProperty(globals, name); + } + function resolvesToSomeValue(location, name) { + ts.Debug.assert(!ts.nodeIsSynthesized(location), "resolvesToSomeValue called with a synthesized location"); + return !!resolveName(location, name, 107455, undefined, undefined); + } + function getBlockScopedVariableId(n) { + ts.Debug.assert(!ts.nodeIsSynthesized(n)); + var isVariableDeclarationOrBindingElement = n.parent.kind === 152 || (n.parent.kind === 198 && n.parent.name === n); + var symbol = (isVariableDeclarationOrBindingElement ? getSymbolOfNode(n.parent) : undefined) || + getNodeLinks(n).resolvedSymbol || + resolveName(n, n.text, 107455 | 8388608, undefined, undefined); + var isLetOrConst = symbol && + (symbol.flags & 2) && + symbol.valueDeclaration.parent.kind !== 223; + if (isLetOrConst) { + getSymbolLinks(symbol); + return symbol.id; + } + return undefined; + } + function instantiateSingleCallFunctionType(functionType, typeArguments) { + if (functionType === unknownType) { + return unknownType; + } + var signature = getSingleCallSignature(functionType); + if (!signature) { + return unknownType; + } + var instantiatedSignature = getSignatureInstantiation(signature, typeArguments); + return getOrCreateTypeFromSignature(instantiatedSignature); + } + function createResolver() { + return { + getExpressionNameSubstitution: getExpressionNameSubstitution, + isValueAliasDeclaration: isValueAliasDeclaration, + hasGlobalName: hasGlobalName, + isReferencedAliasDeclaration: isReferencedAliasDeclaration, + getNodeCheckFlags: getNodeCheckFlags, + isTopLevelValueImportEqualsWithEntityName: isTopLevelValueImportEqualsWithEntityName, + isDeclarationVisible: isDeclarationVisible, + isImplementationOfOverload: isImplementationOfOverload, + writeTypeOfDeclaration: writeTypeOfDeclaration, + writeReturnTypeOfSignatureDeclaration: writeReturnTypeOfSignatureDeclaration, + writeTypeOfExpression: writeTypeOfExpression, + isSymbolAccessible: isSymbolAccessible, + isEntityNameVisible: isEntityNameVisible, + getConstantValue: getConstantValue, + resolvesToSomeValue: resolvesToSomeValue, + collectLinkedAliases: collectLinkedAliases, + getBlockScopedVariableId: getBlockScopedVariableId, + serializeTypeOfNode: serializeTypeOfNode, + serializeParameterTypesOfNode: serializeParameterTypesOfNode, + serializeReturnTypeOfNode: serializeReturnTypeOfNode, + }; + } + function initializeTypeChecker() { + ts.forEach(host.getSourceFiles(), function (file) { + ts.bindSourceFile(file); + }); + ts.forEach(host.getSourceFiles(), function (file) { + if (!ts.isExternalModule(file)) { + mergeSymbolTable(globals, file.locals); + } + }); + getSymbolLinks(undefinedSymbol).type = undefinedType; + getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments"); + getSymbolLinks(unknownSymbol).type = unknownType; + globals[undefinedSymbol.name] = undefinedSymbol; + globalArraySymbol = getGlobalTypeSymbol("Array"); + globalArrayType = getTypeOfGlobalSymbol(globalArraySymbol, 1); + globalObjectType = getGlobalType("Object"); + globalFunctionType = getGlobalType("Function"); + globalStringType = getGlobalType("String"); + globalNumberType = getGlobalType("Number"); + globalBooleanType = getGlobalType("Boolean"); + globalRegExpType = getGlobalType("RegExp"); + getGlobalClassDecoratorType = ts.memoize(function () { return getGlobalType("ClassDecorator"); }); + getGlobalPropertyDecoratorType = ts.memoize(function () { return getGlobalType("PropertyDecorator"); }); + getGlobalMethodDecoratorType = ts.memoize(function () { return getGlobalType("MethodDecorator"); }); + getGlobalParameterDecoratorType = ts.memoize(function () { return getGlobalType("ParameterDecorator"); }); + if (languageVersion >= 2) { + globalTemplateStringsArrayType = getGlobalType("TemplateStringsArray"); + globalESSymbolType = getGlobalType("Symbol"); + globalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol"); + globalIterableType = getGlobalType("Iterable", 1); + } + else { + globalTemplateStringsArrayType = unknownType; + globalESSymbolType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + globalESSymbolConstructorSymbol = undefined; + } + anyArrayType = createArrayType(anyType); + } + function isReservedWordInStrictMode(node) { + return (node.parserContextFlags & 1) && + (102 <= node.originalKeywordKind && node.originalKeywordKind <= 110); + } + function reportStrictModeGrammarErrorInClassDeclaration(identifier, message, arg0, arg1, arg2) { + if (ts.getAncestor(identifier, 201) || ts.getAncestor(identifier, 174)) { + return grammarErrorOnNode(identifier, message, arg0); + } + return false; + } + function checkGrammarImportDeclarationNameInStrictMode(node) { + if (node.importClause) { + var impotClause = node.importClause; + if (impotClause.namedBindings) { + var nameBindings = impotClause.namedBindings; + if (nameBindings.kind === 211) { + var name_8 = nameBindings.name; + if (isReservedWordInStrictMode(name_8)) { + var nameText = ts.declarationNameToString(name_8); + return grammarErrorOnNode(name_8, ts.Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + } + } + else if (nameBindings.kind === 212) { + var reportError = false; + for (var _i = 0, _a = nameBindings.elements; _i < _a.length; _i++) { + var element = _a[_i]; + var name_9 = element.name; + if (isReservedWordInStrictMode(name_9)) { + var nameText = ts.declarationNameToString(name_9); + reportError = reportError || grammarErrorOnNode(name_9, ts.Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + } + } + return reportError; + } + } + } + return false; + } + function checkGrammarDeclarationNameInStrictMode(node) { + var name = node.name; + if (name && name.kind === 65 && isReservedWordInStrictMode(name)) { + var nameText = ts.declarationNameToString(name); + switch (node.kind) { + case 129: + case 198: + case 200: + case 128: + case 152: + case 202: + case 203: + case 204: + return checkGrammarIdentifierInStrictMode(name); + case 201: + return grammarErrorOnNode(name, ts.Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode, nameText); + case 205: + return grammarErrorOnNode(name, ts.Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + case 208: + return grammarErrorOnNode(name, ts.Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + } + } + return false; + } + function checkGrammarTypeReferenceInStrictMode(typeName) { + if (typeName.kind === 65) { + checkGrammarTypeNameInStrictMode(typeName); + } + else if (typeName.kind === 126) { + checkGrammarTypeNameInStrictMode(typeName.right); + checkGrammarTypeReferenceInStrictMode(typeName.left); + } + } + function checkGrammarHeritageClauseElementInStrictMode(expression) { + if (expression && expression.kind === 65) { + return checkGrammarIdentifierInStrictMode(expression); + } + else if (expression && expression.kind === 155) { + checkGrammarHeritageClauseElementInStrictMode(expression.expression); + } + } + function checkGrammarIdentifierInStrictMode(node, nameText) { + if (node && node.kind === 65 && isReservedWordInStrictMode(node)) { + if (!nameText) { + nameText = ts.declarationNameToString(node); + } + var errorReport = reportStrictModeGrammarErrorInClassDeclaration(node, ts.Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode, nameText) || + grammarErrorOnNode(node, ts.Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + return errorReport; + } + return false; + } + function checkGrammarTypeNameInStrictMode(node) { + if (node && node.kind === 65 && isReservedWordInStrictMode(node)) { + var nameText = ts.declarationNameToString(node); + var errorReport = reportStrictModeGrammarErrorInClassDeclaration(node, ts.Diagnostics.Type_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode, nameText) || + grammarErrorOnNode(node, ts.Diagnostics.Type_expected_0_is_a_reserved_word_in_strict_mode, nameText); + return errorReport; + } + return false; + } + function checkGrammarDecorators(node) { + if (!node.decorators) { + return false; + } + if (!ts.nodeCanBeDecorated(node)) { + return grammarErrorOnFirstToken(node, ts.Diagnostics.Decorators_are_not_valid_here); + } + else if (languageVersion < 1) { + return grammarErrorOnFirstToken(node, ts.Diagnostics.Decorators_are_only_available_when_targeting_ECMAScript_5_and_higher); + } + else if (node.kind === 136 || node.kind === 137) { + var accessors = ts.getAllAccessorDeclarations(node.parent.members, node); + if (accessors.firstAccessor.decorators && node === accessors.secondAccessor) { + return grammarErrorOnFirstToken(node, ts.Diagnostics.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name); + } + } + return false; + } + function checkGrammarModifiers(node) { + switch (node.kind) { + case 136: + case 137: + case 135: + case 132: + case 131: + case 134: + case 133: + case 140: + case 201: + case 202: + case 205: + case 204: + case 180: + case 200: + case 203: + case 209: + case 208: + case 215: + case 214: + case 129: + break; + default: + return false; + } + if (!node.modifiers) { + return; + } + var lastStatic, lastPrivate, lastProtected, lastDeclare; + var flags = 0; + for (var _i = 0, _a = node.modifiers; _i < _a.length; _i++) { + var modifier = _a[_i]; + switch (modifier.kind) { + case 108: + case 107: + case 106: + var text = void 0; + if (modifier.kind === 108) { + text = "public"; + } + else if (modifier.kind === 107) { + text = "protected"; + lastProtected = modifier; + } + else { + text = "private"; + lastPrivate = modifier; + } + if (flags & 112) { + return grammarErrorOnNode(modifier, ts.Diagnostics.Accessibility_modifier_already_seen); + } + else if (flags & 128) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_must_precede_1_modifier, text, "static"); + } + else if (node.parent.kind === 206 || node.parent.kind === 227) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_cannot_appear_on_a_module_element, text); + } + flags |= ts.modifierToFlag(modifier.kind); + break; + case 109: + if (flags & 128) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_already_seen, "static"); + } + else if (node.parent.kind === 206 || node.parent.kind === 227) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_cannot_appear_on_a_module_element, "static"); + } + else if (node.kind === 129) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_cannot_appear_on_a_parameter, "static"); + } + flags |= 128; + lastStatic = modifier; + break; + case 78: + if (flags & 1) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_already_seen, "export"); + } + else if (flags & 2) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_must_precede_1_modifier, "export", "declare"); + } + else if (node.parent.kind === 201) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_cannot_appear_on_a_class_element, "export"); + } + else if (node.kind === 129) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_cannot_appear_on_a_parameter, "export"); + } + flags |= 1; + break; + case 115: + if (flags & 2) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_already_seen, "declare"); + } + else if (node.parent.kind === 201) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_cannot_appear_on_a_class_element, "declare"); + } + else if (node.kind === 129) { + return grammarErrorOnNode(modifier, ts.Diagnostics._0_modifier_cannot_appear_on_a_parameter, "declare"); + } + else if (ts.isInAmbientContext(node.parent) && node.parent.kind === 206) { + return grammarErrorOnNode(modifier, ts.Diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context); + } + flags |= 2; + lastDeclare = modifier; + break; + } + } + if (node.kind === 135) { + if (flags & 128) { + return grammarErrorOnNode(lastStatic, ts.Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "static"); + } + else if (flags & 64) { + return grammarErrorOnNode(lastProtected, ts.Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "protected"); + } + else if (flags & 32) { + return grammarErrorOnNode(lastPrivate, ts.Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "private"); + } + } + else if ((node.kind === 209 || node.kind === 208) && flags & 2) { + return grammarErrorOnNode(lastDeclare, ts.Diagnostics.A_declare_modifier_cannot_be_used_with_an_import_declaration, "declare"); + } + else if (node.kind === 202 && flags & 2) { + return grammarErrorOnNode(lastDeclare, ts.Diagnostics.A_declare_modifier_cannot_be_used_with_an_interface_declaration, "declare"); + } + else if (node.kind === 129 && (flags & 112) && ts.isBindingPattern(node.name)) { + return grammarErrorOnNode(node, ts.Diagnostics.A_parameter_property_may_not_be_a_binding_pattern); + } + } + function checkGrammarForDisallowedTrailingComma(list) { + if (list && list.hasTrailingComma) { + var start = list.end - ",".length; + var end = list.end; + var sourceFile = ts.getSourceFileOfNode(list[0]); + return grammarErrorAtPos(sourceFile, start, end - start, ts.Diagnostics.Trailing_comma_not_allowed); + } + } + function checkGrammarTypeParameterList(node, typeParameters, file) { + if (checkGrammarForDisallowedTrailingComma(typeParameters)) { + return true; + } + if (typeParameters && typeParameters.length === 0) { + var start = typeParameters.pos - "<".length; + var end = ts.skipTrivia(file.text, typeParameters.end) + ">".length; + return grammarErrorAtPos(file, start, end - start, ts.Diagnostics.Type_parameter_list_cannot_be_empty); + } + } + function checkGrammarParameterList(parameters) { + if (checkGrammarForDisallowedTrailingComma(parameters)) { + return true; + } + var seenOptionalParameter = false; + var parameterCount = parameters.length; + for (var i = 0; i < parameterCount; i++) { + var parameter = parameters[i]; + if (parameter.dotDotDotToken) { + if (i !== (parameterCount - 1)) { + return grammarErrorOnNode(parameter.dotDotDotToken, ts.Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); + } + if (ts.isBindingPattern(parameter.name)) { + return grammarErrorOnNode(parameter.name, ts.Diagnostics.A_rest_element_cannot_contain_a_binding_pattern); + } + if (parameter.questionToken) { + return grammarErrorOnNode(parameter.questionToken, ts.Diagnostics.A_rest_parameter_cannot_be_optional); + } + if (parameter.initializer) { + return grammarErrorOnNode(parameter.name, ts.Diagnostics.A_rest_parameter_cannot_have_an_initializer); + } + } + else if (parameter.questionToken || parameter.initializer) { + seenOptionalParameter = true; + if (parameter.questionToken && parameter.initializer) { + return grammarErrorOnNode(parameter.name, ts.Diagnostics.Parameter_cannot_have_question_mark_and_initializer); + } + } + else { + if (seenOptionalParameter) { + return grammarErrorOnNode(parameter.name, ts.Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter); + } + } + } + } + function checkGrammarFunctionLikeDeclaration(node) { + var file = ts.getSourceFileOfNode(node); + return checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarTypeParameterList(node, node.typeParameters, file) || + checkGrammarParameterList(node.parameters) || checkGrammarArrowFunction(node, file); + } + function checkGrammarArrowFunction(node, file) { + if (node.kind === 163) { + var arrowFunction = node; + var startLine = ts.getLineAndCharacterOfPosition(file, arrowFunction.equalsGreaterThanToken.pos).line; + var endLine = ts.getLineAndCharacterOfPosition(file, arrowFunction.equalsGreaterThanToken.end).line; + if (startLine !== endLine) { + return grammarErrorOnNode(arrowFunction.equalsGreaterThanToken, ts.Diagnostics.Line_terminator_not_permitted_before_arrow); + } + } + return false; + } + function checkGrammarIndexSignatureParameters(node) { + var parameter = node.parameters[0]; + if (node.parameters.length !== 1) { + if (parameter) { + return grammarErrorOnNode(parameter.name, ts.Diagnostics.An_index_signature_must_have_exactly_one_parameter); + } + else { + return grammarErrorOnNode(node, ts.Diagnostics.An_index_signature_must_have_exactly_one_parameter); + } + } + if (parameter.dotDotDotToken) { + return grammarErrorOnNode(parameter.dotDotDotToken, ts.Diagnostics.An_index_signature_cannot_have_a_rest_parameter); + } + if (parameter.flags & 499) { + return grammarErrorOnNode(parameter.name, ts.Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier); + } + if (parameter.questionToken) { + return grammarErrorOnNode(parameter.questionToken, ts.Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark); + } + if (parameter.initializer) { + return grammarErrorOnNode(parameter.name, ts.Diagnostics.An_index_signature_parameter_cannot_have_an_initializer); + } + if (!parameter.type) { + return grammarErrorOnNode(parameter.name, ts.Diagnostics.An_index_signature_parameter_must_have_a_type_annotation); + } + if (parameter.type.kind !== 121 && parameter.type.kind !== 119) { + return grammarErrorOnNode(parameter.name, ts.Diagnostics.An_index_signature_parameter_type_must_be_string_or_number); + } + if (!node.type) { + return grammarErrorOnNode(node, ts.Diagnostics.An_index_signature_must_have_a_type_annotation); + } + } + function checkGrammarForIndexSignatureModifier(node) { + if (node.flags & 499) { + grammarErrorOnFirstToken(node, ts.Diagnostics.Modifiers_not_permitted_on_index_signature_members); + } + } + function checkGrammarIndexSignature(node) { + return checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarIndexSignatureParameters(node) || checkGrammarForIndexSignatureModifier(node); + } + function checkGrammarForAtLeastOneTypeArgument(node, typeArguments) { + if (typeArguments && typeArguments.length === 0) { + var sourceFile = ts.getSourceFileOfNode(node); + var start = typeArguments.pos - "<".length; + var end = ts.skipTrivia(sourceFile.text, typeArguments.end) + ">".length; + return grammarErrorAtPos(sourceFile, start, end - start, ts.Diagnostics.Type_argument_list_cannot_be_empty); + } + } + function checkGrammarTypeArguments(node, typeArguments) { + return checkGrammarForDisallowedTrailingComma(typeArguments) || + checkGrammarForAtLeastOneTypeArgument(node, typeArguments); + } + function checkGrammarForOmittedArgument(node, arguments) { + if (arguments) { + var sourceFile = ts.getSourceFileOfNode(node); + for (var _i = 0; _i < arguments.length; _i++) { + var arg = arguments[_i]; + if (arg.kind === 175) { + return grammarErrorAtPos(sourceFile, arg.pos, 0, ts.Diagnostics.Argument_expression_expected); + } + } + } + } + function checkGrammarArguments(node, arguments) { + return checkGrammarForDisallowedTrailingComma(arguments) || + checkGrammarForOmittedArgument(node, arguments); + } + function checkGrammarHeritageClause(node) { + var types = node.types; + if (checkGrammarForDisallowedTrailingComma(types)) { + return true; + } + if (types && types.length === 0) { + var listType = ts.tokenToString(node.token); + var sourceFile = ts.getSourceFileOfNode(node); + return grammarErrorAtPos(sourceFile, types.pos, 0, ts.Diagnostics._0_list_cannot_be_empty, listType); + } + } + function checkGrammarClassDeclarationHeritageClauses(node) { + var seenExtendsClause = false; + var seenImplementsClause = false; + if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && node.heritageClauses) { + for (var _i = 0, _a = node.heritageClauses; _i < _a.length; _i++) { + var heritageClause = _a[_i]; + if (heritageClause.token === 79) { + if (seenExtendsClause) { + return grammarErrorOnFirstToken(heritageClause, ts.Diagnostics.extends_clause_already_seen); + } + if (seenImplementsClause) { + return grammarErrorOnFirstToken(heritageClause, ts.Diagnostics.extends_clause_must_precede_implements_clause); + } + if (heritageClause.types.length > 1) { + return grammarErrorOnFirstToken(heritageClause.types[1], ts.Diagnostics.Classes_can_only_extend_a_single_class); + } + seenExtendsClause = true; + } + else { + ts.Debug.assert(heritageClause.token === 102); + if (seenImplementsClause) { + return grammarErrorOnFirstToken(heritageClause, ts.Diagnostics.implements_clause_already_seen); + } + seenImplementsClause = true; + } + checkGrammarHeritageClause(heritageClause); + } + } + } + function checkGrammarInterfaceDeclaration(node) { + var seenExtendsClause = false; + if (node.heritageClauses) { + for (var _i = 0, _a = node.heritageClauses; _i < _a.length; _i++) { + var heritageClause = _a[_i]; + if (heritageClause.token === 79) { + if (seenExtendsClause) { + return grammarErrorOnFirstToken(heritageClause, ts.Diagnostics.extends_clause_already_seen); + } + seenExtendsClause = true; + } + else { + ts.Debug.assert(heritageClause.token === 102); + return grammarErrorOnFirstToken(heritageClause, ts.Diagnostics.Interface_declaration_cannot_have_implements_clause); + } + checkGrammarHeritageClause(heritageClause); + } + } + return false; + } + function checkGrammarComputedPropertyName(node) { + if (node.kind !== 127) { + return false; + } + var computedPropertyName = node; + if (computedPropertyName.expression.kind === 169 && computedPropertyName.expression.operatorToken.kind === 23) { + return grammarErrorOnNode(computedPropertyName.expression, ts.Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name); + } + } + function checkGrammarForGenerator(node) { + if (node.asteriskToken) { + return grammarErrorOnNode(node.asteriskToken, ts.Diagnostics.Generators_are_not_currently_supported); + } + } + function checkGrammarFunctionName(name) { + return checkGrammarEvalOrArgumentsInStrictMode(name, name); + } + function checkGrammarForInvalidQuestionMark(node, questionToken, message) { + if (questionToken) { + return grammarErrorOnNode(questionToken, message); + } + } + function checkGrammarObjectLiteralExpression(node) { + var seen = {}; + var Property = 1; + var GetAccessor = 2; + var SetAccesor = 4; + var GetOrSetAccessor = GetAccessor | SetAccesor; + var inStrictMode = (node.parserContextFlags & 1) !== 0; + for (var _i = 0, _a = node.properties; _i < _a.length; _i++) { + var prop = _a[_i]; + var name_10 = prop.name; + if (prop.kind === 175 || + name_10.kind === 127) { + checkGrammarComputedPropertyName(name_10); + continue; + } + var currentKind = void 0; + if (prop.kind === 224 || prop.kind === 225) { + checkGrammarForInvalidQuestionMark(prop, prop.questionToken, ts.Diagnostics.An_object_member_cannot_be_declared_optional); + if (name_10.kind === 7) { + checkGrammarNumericLiteral(name_10); + } + currentKind = Property; + } + else if (prop.kind === 134) { + currentKind = Property; + } + else if (prop.kind === 136) { + currentKind = GetAccessor; + } + else if (prop.kind === 137) { + currentKind = SetAccesor; + } + else { + ts.Debug.fail("Unexpected syntax kind:" + prop.kind); + } + if (!ts.hasProperty(seen, name_10.text)) { + seen[name_10.text] = currentKind; + } + else { + var existingKind = seen[name_10.text]; + if (currentKind === Property && existingKind === Property) { + if (inStrictMode) { + grammarErrorOnNode(name_10, ts.Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode); + } + } + else if ((currentKind & GetOrSetAccessor) && (existingKind & GetOrSetAccessor)) { + if (existingKind !== GetOrSetAccessor && currentKind !== existingKind) { + seen[name_10.text] = currentKind | existingKind; + } + else { + return grammarErrorOnNode(name_10, ts.Diagnostics.An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name); + } + } + else { + return grammarErrorOnNode(name_10, ts.Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name); + } + } + } + } + function checkGrammarForInOrForOfStatement(forInOrOfStatement) { + if (checkGrammarStatementInAmbientContext(forInOrOfStatement)) { + return true; + } + if (forInOrOfStatement.initializer.kind === 199) { + var variableList = forInOrOfStatement.initializer; + if (!checkGrammarVariableDeclarationList(variableList)) { + if (variableList.declarations.length > 1) { + var diagnostic = forInOrOfStatement.kind === 187 + ? ts.Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement + : ts.Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement; + return grammarErrorOnFirstToken(variableList.declarations[1], diagnostic); + } + var firstDeclaration = variableList.declarations[0]; + if (firstDeclaration.initializer) { + var diagnostic = forInOrOfStatement.kind === 187 + ? ts.Diagnostics.The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer + : ts.Diagnostics.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer; + return grammarErrorOnNode(firstDeclaration.name, diagnostic); + } + if (firstDeclaration.type) { + var diagnostic = forInOrOfStatement.kind === 187 + ? ts.Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation + : ts.Diagnostics.The_left_hand_side_of_a_for_of_statement_cannot_use_a_type_annotation; + return grammarErrorOnNode(firstDeclaration, diagnostic); + } + } + } + return false; + } + function checkGrammarAccessor(accessor) { + var kind = accessor.kind; + if (languageVersion < 1) { + return grammarErrorOnNode(accessor.name, ts.Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher); + } + else if (ts.isInAmbientContext(accessor)) { + return grammarErrorOnNode(accessor.name, ts.Diagnostics.An_accessor_cannot_be_declared_in_an_ambient_context); + } + else if (accessor.body === undefined) { + return grammarErrorAtPos(ts.getSourceFileOfNode(accessor), accessor.end - 1, ";".length, ts.Diagnostics._0_expected, "{"); + } + else if (accessor.typeParameters) { + return grammarErrorOnNode(accessor.name, ts.Diagnostics.An_accessor_cannot_have_type_parameters); + } + else if (kind === 136 && accessor.parameters.length) { + return grammarErrorOnNode(accessor.name, ts.Diagnostics.A_get_accessor_cannot_have_parameters); + } + else if (kind === 137) { + if (accessor.type) { + return grammarErrorOnNode(accessor.name, ts.Diagnostics.A_set_accessor_cannot_have_a_return_type_annotation); + } + else if (accessor.parameters.length !== 1) { + return grammarErrorOnNode(accessor.name, ts.Diagnostics.A_set_accessor_must_have_exactly_one_parameter); + } + else { + var parameter = accessor.parameters[0]; + if (parameter.dotDotDotToken) { + return grammarErrorOnNode(parameter.dotDotDotToken, ts.Diagnostics.A_set_accessor_cannot_have_rest_parameter); + } + else if (parameter.flags & 499) { + return grammarErrorOnNode(accessor.name, ts.Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); + } + else if (parameter.questionToken) { + return grammarErrorOnNode(parameter.questionToken, ts.Diagnostics.A_set_accessor_cannot_have_an_optional_parameter); + } + else if (parameter.initializer) { + return grammarErrorOnNode(accessor.name, ts.Diagnostics.A_set_accessor_parameter_cannot_have_an_initializer); + } + } + } + } + function checkGrammarForNonSymbolComputedProperty(node, message) { + if (node.kind === 127 && !ts.isWellKnownSymbolSyntactically(node.expression)) { + return grammarErrorOnNode(node, message); + } + } + function checkGrammarMethod(node) { + if (checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) || + checkGrammarFunctionLikeDeclaration(node) || + checkGrammarForGenerator(node)) { + return true; + } + if (node.parent.kind === 154) { + if (checkGrammarForInvalidQuestionMark(node, node.questionToken, ts.Diagnostics.A_class_member_cannot_be_declared_optional)) { + return true; + } + else if (node.body === undefined) { + return grammarErrorAtPos(getSourceFile(node), node.end - 1, ";".length, ts.Diagnostics._0_expected, "{"); + } + } + if (node.parent.kind === 201) { + if (checkGrammarForInvalidQuestionMark(node, node.questionToken, ts.Diagnostics.A_class_member_cannot_be_declared_optional)) { + return true; + } + if (ts.isInAmbientContext(node)) { + return checkGrammarForNonSymbolComputedProperty(node.name, ts.Diagnostics.A_computed_property_name_in_an_ambient_context_must_directly_refer_to_a_built_in_symbol); + } + else if (!node.body) { + return checkGrammarForNonSymbolComputedProperty(node.name, ts.Diagnostics.A_computed_property_name_in_a_method_overload_must_directly_refer_to_a_built_in_symbol); + } + } + else if (node.parent.kind === 202) { + return checkGrammarForNonSymbolComputedProperty(node.name, ts.Diagnostics.A_computed_property_name_in_an_interface_must_directly_refer_to_a_built_in_symbol); + } + else if (node.parent.kind === 145) { + return checkGrammarForNonSymbolComputedProperty(node.name, ts.Diagnostics.A_computed_property_name_in_a_type_literal_must_directly_refer_to_a_built_in_symbol); + } + } + function isIterationStatement(node, lookInLabeledStatements) { + switch (node.kind) { + case 186: + case 187: + case 188: + case 184: + case 185: + return true; + case 194: + return lookInLabeledStatements && isIterationStatement(node.statement, lookInLabeledStatements); + } + return false; + } + function checkGrammarBreakOrContinueStatement(node) { + var current = node; + while (current) { + if (ts.isFunctionLike(current)) { + return grammarErrorOnNode(node, ts.Diagnostics.Jump_target_cannot_cross_function_boundary); + } + switch (current.kind) { + case 194: + if (node.label && current.label.text === node.label.text) { + var isMisplacedContinueLabel = node.kind === 189 + && !isIterationStatement(current.statement, true); + if (isMisplacedContinueLabel) { + return grammarErrorOnNode(node, ts.Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement); + } + return false; + } + break; + case 193: + if (node.kind === 190 && !node.label) { + return false; + } + break; + default: + if (isIterationStatement(current, false) && !node.label) { + return false; + } + break; + } + current = current.parent; + } + if (node.label) { + var message = node.kind === 190 + ? ts.Diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement + : ts.Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement; + return grammarErrorOnNode(node, message); + } + else { + var message = node.kind === 190 + ? ts.Diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement + : ts.Diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement; + return grammarErrorOnNode(node, message); + } + } + function checkGrammarBindingElement(node) { + if (node.dotDotDotToken) { + var elements = node.parent.elements; + if (node !== elements[elements.length - 1]) { + return grammarErrorOnNode(node, ts.Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern); + } + if (node.name.kind === 151 || node.name.kind === 150) { + return grammarErrorOnNode(node.name, ts.Diagnostics.A_rest_element_cannot_contain_a_binding_pattern); + } + if (node.initializer) { + return grammarErrorAtPos(ts.getSourceFileOfNode(node), node.initializer.pos - 1, 1, ts.Diagnostics.A_rest_element_cannot_have_an_initializer); + } + } + return checkGrammarEvalOrArgumentsInStrictMode(node, node.name); + } + function checkGrammarVariableDeclaration(node) { + if (node.parent.parent.kind !== 187 && node.parent.parent.kind !== 188) { + if (ts.isInAmbientContext(node)) { + if (node.initializer) { + var equalsTokenLength = "=".length; + return grammarErrorAtPos(ts.getSourceFileOfNode(node), node.initializer.pos - equalsTokenLength, equalsTokenLength, ts.Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); + } + } + else if (!node.initializer) { + if (ts.isBindingPattern(node.name) && !ts.isBindingPattern(node.parent)) { + return grammarErrorOnNode(node, ts.Diagnostics.A_destructuring_declaration_must_have_an_initializer); + } + if (ts.isConst(node)) { + return grammarErrorOnNode(node, ts.Diagnostics.const_declarations_must_be_initialized); + } + } + } + var checkLetConstNames = languageVersion >= 2 && (ts.isLet(node) || ts.isConst(node)); + return (checkLetConstNames && checkGrammarNameInLetOrConstDeclarations(node.name)) || + checkGrammarEvalOrArgumentsInStrictMode(node, node.name); + } + function checkGrammarNameInLetOrConstDeclarations(name) { + if (name.kind === 65) { + if (name.text === "let") { + return grammarErrorOnNode(name, ts.Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations); + } + } + else { + var elements = name.elements; + for (var _i = 0; _i < elements.length; _i++) { + var element = elements[_i]; + if (element.kind !== 175) { + checkGrammarNameInLetOrConstDeclarations(element.name); + } + } + } + } + function checkGrammarVariableDeclarationList(declarationList) { + var declarations = declarationList.declarations; + if (checkGrammarForDisallowedTrailingComma(declarationList.declarations)) { + return true; + } + if (!declarationList.declarations.length) { + return grammarErrorAtPos(ts.getSourceFileOfNode(declarationList), declarations.pos, declarations.end - declarations.pos, ts.Diagnostics.Variable_declaration_list_cannot_be_empty); + } + } + function allowLetAndConstDeclarations(parent) { + switch (parent.kind) { + case 183: + case 184: + case 185: + case 192: + case 186: + case 187: + case 188: + return false; + case 194: + return allowLetAndConstDeclarations(parent.parent); + } + return true; + } + function checkGrammarForDisallowedLetOrConstStatement(node) { + if (!allowLetAndConstDeclarations(node.parent)) { + if (ts.isLet(node.declarationList)) { + return grammarErrorOnNode(node, ts.Diagnostics.let_declarations_can_only_be_declared_inside_a_block); + } + else if (ts.isConst(node.declarationList)) { + return grammarErrorOnNode(node, ts.Diagnostics.const_declarations_can_only_be_declared_inside_a_block); + } + } + } + function isIntegerLiteral(expression) { + if (expression.kind === 167) { + var unaryExpression = expression; + if (unaryExpression.operator === 33 || unaryExpression.operator === 34) { + expression = unaryExpression.operand; + } + } + if (expression.kind === 7) { + return /^[0-9]+([eE]\+?[0-9]+)?$/.test(expression.text); + } + return false; + } + function checkGrammarEnumDeclaration(enumDecl) { + var enumIsConst = (enumDecl.flags & 8192) !== 0; + var hasError = false; + if (!enumIsConst) { + var inConstantEnumMemberSection = true; + var inAmbientContext = ts.isInAmbientContext(enumDecl); + for (var _i = 0, _a = enumDecl.members; _i < _a.length; _i++) { + var node = _a[_i]; + if (node.name.kind === 127) { + hasError = grammarErrorOnNode(node.name, ts.Diagnostics.Computed_property_names_are_not_allowed_in_enums); + } + else if (inAmbientContext) { + if (node.initializer && !isIntegerLiteral(node.initializer)) { + hasError = grammarErrorOnNode(node.name, ts.Diagnostics.Ambient_enum_elements_can_only_have_integer_literal_initializers) || hasError; + } + } + else if (node.initializer) { + inConstantEnumMemberSection = isIntegerLiteral(node.initializer); + } + else if (!inConstantEnumMemberSection) { + hasError = grammarErrorOnNode(node.name, ts.Diagnostics.Enum_member_must_have_initializer) || hasError; + } + } + } + return hasError; + } + function hasParseDiagnostics(sourceFile) { + return sourceFile.parseDiagnostics.length > 0; + } + function grammarErrorOnFirstToken(node, message, arg0, arg1, arg2) { + var sourceFile = ts.getSourceFileOfNode(node); + if (!hasParseDiagnostics(sourceFile)) { + var span = ts.getSpanOfTokenAtPosition(sourceFile, node.pos); + diagnostics.add(ts.createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2)); + return true; + } + } + function grammarErrorAtPos(sourceFile, start, length, message, arg0, arg1, arg2) { + if (!hasParseDiagnostics(sourceFile)) { + diagnostics.add(ts.createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2)); + return true; + } + } + function grammarErrorOnNode(node, message, arg0, arg1, arg2) { + var sourceFile = ts.getSourceFileOfNode(node); + if (!hasParseDiagnostics(sourceFile)) { + diagnostics.add(ts.createDiagnosticForNode(node, message, arg0, arg1, arg2)); + return true; + } + } + function checkGrammarEvalOrArgumentsInStrictMode(contextNode, name) { + if (name && name.kind === 65) { + var identifier = name; + if (contextNode && (contextNode.parserContextFlags & 1) && isEvalOrArgumentsIdentifier(identifier)) { + var nameText = ts.declarationNameToString(identifier); + var reportErrorInClassDeclaration = reportStrictModeGrammarErrorInClassDeclaration(identifier, ts.Diagnostics.Invalid_use_of_0_Class_definitions_are_automatically_in_strict_mode, nameText); + if (!reportErrorInClassDeclaration) { + return grammarErrorOnNode(identifier, ts.Diagnostics.Invalid_use_of_0_in_strict_mode, nameText); + } + return reportErrorInClassDeclaration; + } + } + } + function isEvalOrArgumentsIdentifier(node) { + return node.kind === 65 && + (node.text === "eval" || node.text === "arguments"); + } + function checkGrammarConstructorTypeParameters(node) { + if (node.typeParameters) { + return grammarErrorAtPos(ts.getSourceFileOfNode(node), node.typeParameters.pos, node.typeParameters.end - node.typeParameters.pos, ts.Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration); + } + } + function checkGrammarConstructorTypeAnnotation(node) { + if (node.type) { + return grammarErrorOnNode(node.type, ts.Diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration); + } + } + function checkGrammarProperty(node) { + if (node.parent.kind === 201) { + if (checkGrammarForInvalidQuestionMark(node, node.questionToken, ts.Diagnostics.A_class_member_cannot_be_declared_optional) || + checkGrammarForNonSymbolComputedProperty(node.name, ts.Diagnostics.A_computed_property_name_in_a_class_property_declaration_must_directly_refer_to_a_built_in_symbol)) { + return true; + } + } + else if (node.parent.kind === 202) { + if (checkGrammarForNonSymbolComputedProperty(node.name, ts.Diagnostics.A_computed_property_name_in_an_interface_must_directly_refer_to_a_built_in_symbol)) { + return true; + } + } + else if (node.parent.kind === 145) { + if (checkGrammarForNonSymbolComputedProperty(node.name, ts.Diagnostics.A_computed_property_name_in_a_type_literal_must_directly_refer_to_a_built_in_symbol)) { + return true; + } + } + if (ts.isInAmbientContext(node) && node.initializer) { + return grammarErrorOnFirstToken(node.initializer, ts.Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); + } + } + function checkGrammarTopLevelElementForRequiredDeclareModifier(node) { + if (node.kind === 202 || + node.kind === 209 || + node.kind === 208 || + node.kind === 215 || + node.kind === 214 || + (node.flags & 2) || + (node.flags & (1 | 256))) { + return false; + } + return grammarErrorOnFirstToken(node, ts.Diagnostics.A_declare_modifier_is_required_for_a_top_level_declaration_in_a_d_ts_file); + } + function checkGrammarTopLevelElementsForRequiredDeclareModifier(file) { + for (var _i = 0, _a = file.statements; _i < _a.length; _i++) { + var decl = _a[_i]; + if (ts.isDeclaration(decl) || decl.kind === 180) { + if (checkGrammarTopLevelElementForRequiredDeclareModifier(decl)) { + return true; + } + } + } + } + function checkGrammarSourceFile(node) { + return ts.isInAmbientContext(node) && checkGrammarTopLevelElementsForRequiredDeclareModifier(node); + } + function checkGrammarStatementInAmbientContext(node) { + if (ts.isInAmbientContext(node)) { + if (isAccessor(node.parent.kind)) { + return getNodeLinks(node).hasReportedStatementInAmbientContext = true; + } + var links = getNodeLinks(node); + if (!links.hasReportedStatementInAmbientContext && ts.isFunctionLike(node.parent)) { + return getNodeLinks(node).hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, ts.Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts); + } + if (node.parent.kind === 179 || node.parent.kind === 206 || node.parent.kind === 227) { + var links_1 = getNodeLinks(node.parent); + if (!links_1.hasReportedStatementInAmbientContext) { + return links_1.hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, ts.Diagnostics.Statements_are_not_allowed_in_ambient_contexts); + } + } + else { + } + } + } + function checkGrammarNumericLiteral(node) { + if (node.flags & 16384) { + if (node.parserContextFlags & 1) { + return grammarErrorOnNode(node, ts.Diagnostics.Octal_literals_are_not_allowed_in_strict_mode); + } + else if (languageVersion >= 1) { + return grammarErrorOnNode(node, ts.Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher); + } + } + } + function grammarErrorAfterFirstToken(node, message, arg0, arg1, arg2) { + var sourceFile = ts.getSourceFileOfNode(node); + if (!hasParseDiagnostics(sourceFile)) { + var span = ts.getSpanOfTokenAtPosition(sourceFile, node.pos); + diagnostics.add(ts.createFileDiagnostic(sourceFile, ts.textSpanEnd(span), 0, message, arg0, arg1, arg2)); + return true; + } + } + initializeTypeChecker(); + return checker; + } + ts.createTypeChecker = createTypeChecker; +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/commandLineParser.js b/dist/typescript/compiler/commandLineParser.js new file mode 100644 index 000000000..831e1f3bc --- /dev/null +++ b/dist/typescript/compiler/commandLineParser.js @@ -0,0 +1,361 @@ +/// +/// +/// +/// +var ts; +(function (ts) { + ts.optionDeclarations = [ + { + name: "charset", + type: "string", + }, + { + name: "declaration", + shortName: "d", + type: "boolean", + description: ts.Diagnostics.Generates_corresponding_d_ts_file, + }, + { + name: "diagnostics", + type: "boolean", + }, + { + name: "emitBOM", + type: "boolean" + }, + { + name: "help", + shortName: "h", + type: "boolean", + description: ts.Diagnostics.Print_this_message, + }, + { + name: "listFiles", + type: "boolean", + }, + { + name: "locale", + type: "string", + }, + { + name: "mapRoot", + type: "string", + isFilePath: true, + description: ts.Diagnostics.Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations, + paramType: ts.Diagnostics.LOCATION, + }, + { + name: "module", + shortName: "m", + type: { + "commonjs": 1, + "amd": 2, + "umd": 3 + }, + description: ts.Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_or_umd, + paramType: ts.Diagnostics.KIND, + error: ts.Diagnostics.Argument_for_module_option_must_be_commonjs_amd_or_umd + }, + { + name: "noEmit", + type: "boolean", + description: ts.Diagnostics.Do_not_emit_outputs, + }, + { + name: "noEmitOnError", + type: "boolean", + description: ts.Diagnostics.Do_not_emit_outputs_if_any_type_checking_errors_were_reported, + }, + { + name: "noImplicitAny", + type: "boolean", + description: ts.Diagnostics.Raise_error_on_expressions_and_declarations_with_an_implied_any_type, + }, + { + name: "noLib", + type: "boolean", + }, + { + name: "noResolve", + type: "boolean", + }, + { + name: "out", + type: "string", + description: ts.Diagnostics.Concatenate_and_emit_output_to_single_file, + paramType: ts.Diagnostics.FILE, + }, + { + name: "outDir", + type: "string", + isFilePath: true, + description: ts.Diagnostics.Redirect_output_structure_to_the_directory, + paramType: ts.Diagnostics.DIRECTORY, + }, + { + name: "preserveConstEnums", + type: "boolean", + description: ts.Diagnostics.Do_not_erase_const_enum_declarations_in_generated_code + }, + { + name: "project", + shortName: "p", + type: "string", + isFilePath: true, + description: ts.Diagnostics.Compile_the_project_in_the_given_directory, + paramType: ts.Diagnostics.DIRECTORY + }, + { + name: "removeComments", + type: "boolean", + description: ts.Diagnostics.Do_not_emit_comments_to_output, + }, + { + name: "rootDir", + type: "string", + isFilePath: true, + description: ts.Diagnostics.Specifies_the_root_directory_of_input_files_Use_to_control_the_output_directory_structure_with_outDir, + paramType: ts.Diagnostics.LOCATION, + }, + { + name: "separateCompilation", + type: "boolean", + }, + { + name: "sourceMap", + type: "boolean", + description: ts.Diagnostics.Generates_corresponding_map_file, + }, + { + name: "sourceRoot", + type: "string", + isFilePath: true, + description: ts.Diagnostics.Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations, + paramType: ts.Diagnostics.LOCATION, + }, + { + name: "suppressImplicitAnyIndexErrors", + type: "boolean", + description: ts.Diagnostics.Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures, + }, + { + name: "stripInternal", + type: "boolean", + description: ts.Diagnostics.Do_not_emit_declarations_for_code_that_has_an_internal_annotation, + experimental: true + }, + { + name: "target", + shortName: "t", + type: { "es3": 0, "es5": 1, "es6": 2 }, + description: ts.Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES6_experimental, + paramType: ts.Diagnostics.VERSION, + error: ts.Diagnostics.Argument_for_target_option_must_be_ES3_ES5_or_ES6 + }, + { + name: "version", + shortName: "v", + type: "boolean", + description: ts.Diagnostics.Print_the_compiler_s_version, + }, + { + name: "watch", + shortName: "w", + type: "boolean", + description: ts.Diagnostics.Watch_input_files, + }, + { + name: "emitDecoratorMetadata", + type: "boolean", + experimental: true + } + ]; + function parseCommandLine(commandLine) { + var options = {}; + var fileNames = []; + var errors = []; + var shortOptionNames = {}; + var optionNameMap = {}; + ts.forEach(ts.optionDeclarations, function (option) { + optionNameMap[option.name.toLowerCase()] = option; + if (option.shortName) { + shortOptionNames[option.shortName] = option.name; + } + }); + parseStrings(commandLine); + return { + options: options, + fileNames: fileNames, + errors: errors + }; + function parseStrings(args) { + var i = 0; + while (i < args.length) { + var s = args[i++]; + if (s.charCodeAt(0) === 64) { + parseResponseFile(s.slice(1)); + } + else if (s.charCodeAt(0) === 45) { + s = s.slice(s.charCodeAt(1) === 45 ? 2 : 1).toLowerCase(); + if (ts.hasProperty(shortOptionNames, s)) { + s = shortOptionNames[s]; + } + if (ts.hasProperty(optionNameMap, s)) { + var opt = optionNameMap[s]; + if (!args[i] && opt.type !== "boolean") { + errors.push(ts.createCompilerDiagnostic(ts.Diagnostics.Compiler_option_0_expects_an_argument, opt.name)); + } + switch (opt.type) { + case "number": + options[opt.name] = parseInt(args[i++]); + break; + case "boolean": + options[opt.name] = true; + break; + case "string": + options[opt.name] = args[i++] || ""; + break; + default: + var map = opt.type; + var key = (args[i++] || "").toLowerCase(); + if (ts.hasProperty(map, key)) { + options[opt.name] = map[key]; + } + else { + errors.push(ts.createCompilerDiagnostic(opt.error)); + } + } + } + else { + errors.push(ts.createCompilerDiagnostic(ts.Diagnostics.Unknown_compiler_option_0, s)); + } + } + else { + fileNames.push(s); + } + } + } + function parseResponseFile(fileName) { + var text = ts.sys.readFile(fileName); + if (!text) { + errors.push(ts.createCompilerDiagnostic(ts.Diagnostics.File_0_not_found, fileName)); + return; + } + var args = []; + var pos = 0; + while (true) { + while (pos < text.length && text.charCodeAt(pos) <= 32) + pos++; + if (pos >= text.length) + break; + var start = pos; + if (text.charCodeAt(start) === 34) { + pos++; + while (pos < text.length && text.charCodeAt(pos) !== 34) + pos++; + if (pos < text.length) { + args.push(text.substring(start + 1, pos)); + pos++; + } + else { + errors.push(ts.createCompilerDiagnostic(ts.Diagnostics.Unterminated_quoted_string_in_response_file_0, fileName)); + } + } + else { + while (text.charCodeAt(pos) > 32) + pos++; + args.push(text.substring(start, pos)); + } + } + parseStrings(args); + } + } + ts.parseCommandLine = parseCommandLine; + function readConfigFile(fileName) { + try { + var text = ts.sys.readFile(fileName); + } + catch (e) { + return { error: ts.createCompilerDiagnostic(ts.Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message) }; + } + return parseConfigFileText(fileName, text); + } + ts.readConfigFile = readConfigFile; + function parseConfigFileText(fileName, jsonText) { + try { + return { config: /\S/.test(jsonText) ? JSON.parse(jsonText) : {} }; + } + catch (e) { + return { error: ts.createCompilerDiagnostic(ts.Diagnostics.Failed_to_parse_file_0_Colon_1, fileName, e.message) }; + } + } + ts.parseConfigFileText = parseConfigFileText; + function parseConfigFile(json, host, basePath) { + var errors = []; + return { + options: getCompilerOptions(), + fileNames: getFiles(), + errors: errors + }; + function getCompilerOptions() { + var options = {}; + var optionNameMap = {}; + ts.forEach(ts.optionDeclarations, function (option) { + optionNameMap[option.name] = option; + }); + var jsonOptions = json["compilerOptions"]; + if (jsonOptions) { + for (var id in jsonOptions) { + if (ts.hasProperty(optionNameMap, id)) { + var opt = optionNameMap[id]; + var optType = opt.type; + var value = jsonOptions[id]; + var expectedType = typeof optType === "string" ? optType : "string"; + if (typeof value === expectedType) { + if (typeof optType !== "string") { + var key = value.toLowerCase(); + if (ts.hasProperty(optType, key)) { + value = optType[key]; + } + else { + errors.push(ts.createCompilerDiagnostic(opt.error)); + value = 0; + } + } + if (opt.isFilePath) { + value = ts.normalizePath(ts.combinePaths(basePath, value)); + } + options[opt.name] = value; + } + else { + errors.push(ts.createCompilerDiagnostic(ts.Diagnostics.Compiler_option_0_requires_a_value_of_type_1, id, expectedType)); + } + } + else { + errors.push(ts.createCompilerDiagnostic(ts.Diagnostics.Unknown_compiler_option_0, id)); + } + } + } + return options; + } + function getFiles() { + var files = []; + if (ts.hasProperty(json, "files")) { + if (json["files"] instanceof Array) { + var files = ts.map(json["files"], function (s) { return ts.combinePaths(basePath, s); }); + } + } + else { + var sysFiles = host.readDirectory(basePath, ".ts"); + for (var i = 0; i < sysFiles.length; i++) { + var name = sysFiles[i]; + if (!ts.fileExtensionIs(name, ".d.ts") || !ts.contains(sysFiles, name.substr(0, name.length - 5) + ".ts")) { + files.push(name); + } + } + } + return files; + } + } + ts.parseConfigFile = parseConfigFile; +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/core.js b/dist/typescript/compiler/core.js new file mode 100644 index 000000000..a7758e3d9 --- /dev/null +++ b/dist/typescript/compiler/core.js @@ -0,0 +1,652 @@ +/// +var ts; +(function (ts) { + (function (Ternary) { + Ternary[Ternary["False"] = 0] = "False"; + Ternary[Ternary["Maybe"] = 1] = "Maybe"; + Ternary[Ternary["True"] = -1] = "True"; + })(ts.Ternary || (ts.Ternary = {})); + var Ternary = ts.Ternary; + (function (Comparison) { + Comparison[Comparison["LessThan"] = -1] = "LessThan"; + Comparison[Comparison["EqualTo"] = 0] = "EqualTo"; + Comparison[Comparison["GreaterThan"] = 1] = "GreaterThan"; + })(ts.Comparison || (ts.Comparison = {})); + var Comparison = ts.Comparison; + function forEach(array, callback) { + if (array) { + for (var i = 0, len = array.length; i < len; i++) { + var result = callback(array[i], i); + if (result) { + return result; + } + } + } + return undefined; + } + ts.forEach = forEach; + function contains(array, value) { + if (array) { + for (var _i = 0; _i < array.length; _i++) { + var v = array[_i]; + if (v === value) { + return true; + } + } + } + return false; + } + ts.contains = contains; + function indexOf(array, value) { + if (array) { + for (var i = 0, len = array.length; i < len; i++) { + if (array[i] === value) { + return i; + } + } + } + return -1; + } + ts.indexOf = indexOf; + function countWhere(array, predicate) { + var count = 0; + if (array) { + for (var _i = 0; _i < array.length; _i++) { + var v = array[_i]; + if (predicate(v)) { + count++; + } + } + } + return count; + } + ts.countWhere = countWhere; + function filter(array, f) { + var result; + if (array) { + result = []; + for (var _i = 0; _i < array.length; _i++) { + var item_1 = array[_i]; + if (f(item_1)) { + result.push(item_1); + } + } + } + return result; + } + ts.filter = filter; + function map(array, f) { + var result; + if (array) { + result = []; + for (var _i = 0; _i < array.length; _i++) { + var v = array[_i]; + result.push(f(v)); + } + } + return result; + } + ts.map = map; + function concatenate(array1, array2) { + if (!array2 || !array2.length) + return array1; + if (!array1 || !array1.length) + return array2; + return array1.concat(array2); + } + ts.concatenate = concatenate; + function deduplicate(array) { + var result; + if (array) { + result = []; + for (var _i = 0; _i < array.length; _i++) { + var item_2 = array[_i]; + if (!contains(result, item_2)) { + result.push(item_2); + } + } + } + return result; + } + ts.deduplicate = deduplicate; + function sum(array, prop) { + var result = 0; + for (var _i = 0; _i < array.length; _i++) { + var v = array[_i]; + result += v[prop]; + } + return result; + } + ts.sum = sum; + function addRange(to, from) { + if (to && from) { + for (var _i = 0; _i < from.length; _i++) { + var v = from[_i]; + to.push(v); + } + } + } + ts.addRange = addRange; + function lastOrUndefined(array) { + if (array.length === 0) { + return undefined; + } + return array[array.length - 1]; + } + ts.lastOrUndefined = lastOrUndefined; + function binarySearch(array, value) { + var low = 0; + var high = array.length - 1; + while (low <= high) { + var middle = low + ((high - low) >> 1); + var midValue = array[middle]; + if (midValue === value) { + return middle; + } + else if (midValue > value) { + high = middle - 1; + } + else { + low = middle + 1; + } + } + return ~low; + } + ts.binarySearch = binarySearch; + function reduceLeft(array, f, initial) { + if (array) { + var count = array.length; + if (count > 0) { + var pos = 0; + var result = arguments.length <= 2 ? array[pos++] : initial; + while (pos < count) { + result = f(result, array[pos++]); + } + return result; + } + } + return initial; + } + ts.reduceLeft = reduceLeft; + function reduceRight(array, f, initial) { + if (array) { + var pos = array.length - 1; + if (pos >= 0) { + var result = arguments.length <= 2 ? array[pos--] : initial; + while (pos >= 0) { + result = f(result, array[pos--]); + } + return result; + } + } + return initial; + } + ts.reduceRight = reduceRight; + var hasOwnProperty = Object.prototype.hasOwnProperty; + function hasProperty(map, key) { + return hasOwnProperty.call(map, key); + } + ts.hasProperty = hasProperty; + function getProperty(map, key) { + return hasOwnProperty.call(map, key) ? map[key] : undefined; + } + ts.getProperty = getProperty; + function isEmpty(map) { + for (var id in map) { + if (hasProperty(map, id)) { + return false; + } + } + return true; + } + ts.isEmpty = isEmpty; + function clone(object) { + var result = {}; + for (var id in object) { + result[id] = object[id]; + } + return result; + } + ts.clone = clone; + function extend(first, second) { + var result = {}; + for (var id in first) { + result[id] = first[id]; + } + for (var id in second) { + if (!hasProperty(result, id)) { + result[id] = second[id]; + } + } + return result; + } + ts.extend = extend; + function forEachValue(map, callback) { + var result; + for (var id in map) { + if (result = callback(map[id])) + break; + } + return result; + } + ts.forEachValue = forEachValue; + function forEachKey(map, callback) { + var result; + for (var id in map) { + if (result = callback(id)) + break; + } + return result; + } + ts.forEachKey = forEachKey; + function lookUp(map, key) { + return hasProperty(map, key) ? map[key] : undefined; + } + ts.lookUp = lookUp; + function copyMap(source, target) { + for (var p in source) { + target[p] = source[p]; + } + } + ts.copyMap = copyMap; + function arrayToMap(array, makeKey) { + var result = {}; + forEach(array, function (value) { + result[makeKey(value)] = value; + }); + return result; + } + ts.arrayToMap = arrayToMap; + function memoize(callback) { + var value; + return function () { + if (callback) { + value = callback(); + callback = undefined; + } + return value; + }; + } + ts.memoize = memoize; + function formatStringFromArgs(text, args, baseIndex) { + baseIndex = baseIndex || 0; + return text.replace(/{(\d+)}/g, function (match, index) { return args[+index + baseIndex]; }); + } + ts.localizedDiagnosticMessages = undefined; + function getLocaleSpecificMessage(message) { + return ts.localizedDiagnosticMessages && ts.localizedDiagnosticMessages[message] + ? ts.localizedDiagnosticMessages[message] + : message; + } + ts.getLocaleSpecificMessage = getLocaleSpecificMessage; + function createFileDiagnostic(file, start, length, message) { + var end = start + length; + Debug.assert(start >= 0, "start must be non-negative, is " + start); + Debug.assert(length >= 0, "length must be non-negative, is " + length); + Debug.assert(start <= file.text.length, "start must be within the bounds of the file. " + start + " > " + file.text.length); + Debug.assert(end <= file.text.length, "end must be the bounds of the file. " + end + " > " + file.text.length); + var text = getLocaleSpecificMessage(message.key); + if (arguments.length > 4) { + text = formatStringFromArgs(text, arguments, 4); + } + return { + file: file, + start: start, + length: length, + messageText: text, + category: message.category, + code: message.code, + }; + } + ts.createFileDiagnostic = createFileDiagnostic; + function createCompilerDiagnostic(message) { + var text = getLocaleSpecificMessage(message.key); + if (arguments.length > 1) { + text = formatStringFromArgs(text, arguments, 1); + } + return { + file: undefined, + start: undefined, + length: undefined, + messageText: text, + category: message.category, + code: message.code + }; + } + ts.createCompilerDiagnostic = createCompilerDiagnostic; + function chainDiagnosticMessages(details, message) { + var text = getLocaleSpecificMessage(message.key); + if (arguments.length > 2) { + text = formatStringFromArgs(text, arguments, 2); + } + return { + messageText: text, + category: message.category, + code: message.code, + next: details + }; + } + ts.chainDiagnosticMessages = chainDiagnosticMessages; + function concatenateDiagnosticMessageChains(headChain, tailChain) { + Debug.assert(!headChain.next); + headChain.next = tailChain; + return headChain; + } + ts.concatenateDiagnosticMessageChains = concatenateDiagnosticMessageChains; + function compareValues(a, b) { + if (a === b) + return 0; + if (a === undefined) + return -1; + if (b === undefined) + return 1; + return a < b ? -1 : 1; + } + ts.compareValues = compareValues; + function getDiagnosticFileName(diagnostic) { + return diagnostic.file ? diagnostic.file.fileName : undefined; + } + function compareDiagnostics(d1, d2) { + return compareValues(getDiagnosticFileName(d1), getDiagnosticFileName(d2)) || + compareValues(d1.start, d2.start) || + compareValues(d1.length, d2.length) || + compareValues(d1.code, d2.code) || + compareMessageText(d1.messageText, d2.messageText) || + 0; + } + ts.compareDiagnostics = compareDiagnostics; + function compareMessageText(text1, text2) { + while (text1 && text2) { + var string1 = typeof text1 === "string" ? text1 : text1.messageText; + var string2 = typeof text2 === "string" ? text2 : text2.messageText; + var res = compareValues(string1, string2); + if (res) { + return res; + } + text1 = typeof text1 === "string" ? undefined : text1.next; + text2 = typeof text2 === "string" ? undefined : text2.next; + } + if (!text1 && !text2) { + return 0; + } + return text1 ? 1 : -1; + } + function sortAndDeduplicateDiagnostics(diagnostics) { + return deduplicateSortedDiagnostics(diagnostics.sort(compareDiagnostics)); + } + ts.sortAndDeduplicateDiagnostics = sortAndDeduplicateDiagnostics; + function deduplicateSortedDiagnostics(diagnostics) { + if (diagnostics.length < 2) { + return diagnostics; + } + var newDiagnostics = [diagnostics[0]]; + var previousDiagnostic = diagnostics[0]; + for (var i = 1; i < diagnostics.length; i++) { + var currentDiagnostic = diagnostics[i]; + var isDupe = compareDiagnostics(currentDiagnostic, previousDiagnostic) === 0; + if (!isDupe) { + newDiagnostics.push(currentDiagnostic); + previousDiagnostic = currentDiagnostic; + } + } + return newDiagnostics; + } + ts.deduplicateSortedDiagnostics = deduplicateSortedDiagnostics; + function normalizeSlashes(path) { + return path.replace(/\\/g, "/"); + } + ts.normalizeSlashes = normalizeSlashes; + function getRootLength(path) { + if (path.charCodeAt(0) === 47) { + if (path.charCodeAt(1) !== 47) + return 1; + var p1 = path.indexOf("/", 2); + if (p1 < 0) + return 2; + var p2 = path.indexOf("/", p1 + 1); + if (p2 < 0) + return p1 + 1; + return p2 + 1; + } + if (path.charCodeAt(1) === 58) { + if (path.charCodeAt(2) === 47) + return 3; + return 2; + } + var idx = path.indexOf('://'); + if (idx !== -1) + return idx + 3; + return 0; + } + ts.getRootLength = getRootLength; + ts.directorySeparator = "/"; + function getNormalizedParts(normalizedSlashedPath, rootLength) { + var parts = normalizedSlashedPath.substr(rootLength).split(ts.directorySeparator); + var normalized = []; + for (var _i = 0; _i < parts.length; _i++) { + var part = parts[_i]; + if (part !== ".") { + if (part === ".." && normalized.length > 0 && normalized[normalized.length - 1] !== "..") { + normalized.pop(); + } + else { + if (part) { + normalized.push(part); + } + } + } + } + return normalized; + } + function normalizePath(path) { + path = normalizeSlashes(path); + var rootLength = getRootLength(path); + var normalized = getNormalizedParts(path, rootLength); + return path.substr(0, rootLength) + normalized.join(ts.directorySeparator); + } + ts.normalizePath = normalizePath; + function getDirectoryPath(path) { + return path.substr(0, Math.max(getRootLength(path), path.lastIndexOf(ts.directorySeparator))); + } + ts.getDirectoryPath = getDirectoryPath; + function isUrl(path) { + return path && !isRootedDiskPath(path) && path.indexOf("://") !== -1; + } + ts.isUrl = isUrl; + function isRootedDiskPath(path) { + return getRootLength(path) !== 0; + } + ts.isRootedDiskPath = isRootedDiskPath; + function normalizedPathComponents(path, rootLength) { + var normalizedParts = getNormalizedParts(path, rootLength); + return [path.substr(0, rootLength)].concat(normalizedParts); + } + function getNormalizedPathComponents(path, currentDirectory) { + path = normalizeSlashes(path); + var rootLength = getRootLength(path); + if (rootLength == 0) { + path = combinePaths(normalizeSlashes(currentDirectory), path); + rootLength = getRootLength(path); + } + return normalizedPathComponents(path, rootLength); + } + ts.getNormalizedPathComponents = getNormalizedPathComponents; + function getNormalizedAbsolutePath(fileName, currentDirectory) { + return getNormalizedPathFromPathComponents(getNormalizedPathComponents(fileName, currentDirectory)); + } + ts.getNormalizedAbsolutePath = getNormalizedAbsolutePath; + function getNormalizedPathFromPathComponents(pathComponents) { + if (pathComponents && pathComponents.length) { + return pathComponents[0] + pathComponents.slice(1).join(ts.directorySeparator); + } + } + ts.getNormalizedPathFromPathComponents = getNormalizedPathFromPathComponents; + function getNormalizedPathComponentsOfUrl(url) { + // Get root length of http://www.website.com/folder1/foler2/ + // In this example the root is: http://www.website.com/ + // normalized path components should be ["http://www.website.com/", "folder1", "folder2"] + var urlLength = url.length; + var rootLength = url.indexOf("://") + "://".length; + while (rootLength < urlLength) { + if (url.charCodeAt(rootLength) === 47) { + rootLength++; + } + else { + break; + } + } + if (rootLength === urlLength) { + return [url]; + } + var indexOfNextSlash = url.indexOf(ts.directorySeparator, rootLength); + if (indexOfNextSlash !== -1) { + rootLength = indexOfNextSlash + 1; + return normalizedPathComponents(url, rootLength); + } + else { + return [url + ts.directorySeparator]; + } + } + function getNormalizedPathOrUrlComponents(pathOrUrl, currentDirectory) { + if (isUrl(pathOrUrl)) { + return getNormalizedPathComponentsOfUrl(pathOrUrl); + } + else { + return getNormalizedPathComponents(pathOrUrl, currentDirectory); + } + } + function getRelativePathToDirectoryOrUrl(directoryPathOrUrl, relativeOrAbsolutePath, currentDirectory, getCanonicalFileName, isAbsolutePathAnUrl) { + var pathComponents = getNormalizedPathOrUrlComponents(relativeOrAbsolutePath, currentDirectory); + var directoryComponents = getNormalizedPathOrUrlComponents(directoryPathOrUrl, currentDirectory); + if (directoryComponents.length > 1 && directoryComponents[directoryComponents.length - 1] === "") { + directoryComponents.length--; + } + for (var joinStartIndex = 0; joinStartIndex < pathComponents.length && joinStartIndex < directoryComponents.length; joinStartIndex++) { + if (getCanonicalFileName(directoryComponents[joinStartIndex]) !== getCanonicalFileName(pathComponents[joinStartIndex])) { + break; + } + } + if (joinStartIndex) { + var relativePath = ""; + var relativePathComponents = pathComponents.slice(joinStartIndex, pathComponents.length); + for (; joinStartIndex < directoryComponents.length; joinStartIndex++) { + if (directoryComponents[joinStartIndex] !== "") { + relativePath = relativePath + ".." + ts.directorySeparator; + } + } + return relativePath + relativePathComponents.join(ts.directorySeparator); + } + var absolutePath = getNormalizedPathFromPathComponents(pathComponents); + if (isAbsolutePathAnUrl && isRootedDiskPath(absolutePath)) { + absolutePath = "file:///" + absolutePath; + } + return absolutePath; + } + ts.getRelativePathToDirectoryOrUrl = getRelativePathToDirectoryOrUrl; + function getBaseFileName(path) { + var i = path.lastIndexOf(ts.directorySeparator); + return i < 0 ? path : path.substring(i + 1); + } + ts.getBaseFileName = getBaseFileName; + function combinePaths(path1, path2) { + if (!(path1 && path1.length)) + return path2; + if (!(path2 && path2.length)) + return path1; + if (getRootLength(path2) !== 0) + return path2; + if (path1.charAt(path1.length - 1) === ts.directorySeparator) + return path1 + path2; + return path1 + ts.directorySeparator + path2; + } + ts.combinePaths = combinePaths; + function fileExtensionIs(path, extension) { + var pathLen = path.length; + var extLen = extension.length; + return pathLen > extLen && path.substr(pathLen - extLen, extLen) === extension; + } + ts.fileExtensionIs = fileExtensionIs; + var supportedExtensions = [".d.ts", ".ts", ".js"]; + function removeFileExtension(path) { + for (var _i = 0; _i < supportedExtensions.length; _i++) { + var ext = supportedExtensions[_i]; + if (fileExtensionIs(path, ext)) { + return path.substr(0, path.length - ext.length); + } + } + return path; + } + ts.removeFileExtension = removeFileExtension; + var backslashOrDoubleQuote = /[\"\\]/g; + var escapedCharsRegExp = /[\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g; + var escapedCharsMap = { + "\0": "\\0", + "\t": "\\t", + "\v": "\\v", + "\f": "\\f", + "\b": "\\b", + "\r": "\\r", + "\n": "\\n", + "\\": "\\\\", + "\"": "\\\"", + "\u2028": "\\u2028", + "\u2029": "\\u2029", + "\u0085": "\\u0085" + }; + function Symbol(flags, name) { + this.flags = flags; + this.name = name; + this.declarations = undefined; + } + function Type(checker, flags) { + this.flags = flags; + } + function Signature(checker) { + } + ts.objectAllocator = { + getNodeConstructor: function (kind) { + function Node() { + } + Node.prototype = { + kind: kind, + pos: 0, + end: 0, + flags: 0, + parent: undefined, + }; + return Node; + }, + getSymbolConstructor: function () { return Symbol; }, + getTypeConstructor: function () { return Type; }, + getSignatureConstructor: function () { return Signature; } + }; + (function (AssertionLevel) { + AssertionLevel[AssertionLevel["None"] = 0] = "None"; + AssertionLevel[AssertionLevel["Normal"] = 1] = "Normal"; + AssertionLevel[AssertionLevel["Aggressive"] = 2] = "Aggressive"; + AssertionLevel[AssertionLevel["VeryAggressive"] = 3] = "VeryAggressive"; + })(ts.AssertionLevel || (ts.AssertionLevel = {})); + var AssertionLevel = ts.AssertionLevel; + var Debug; + (function (Debug) { + var currentAssertionLevel = 0; + function shouldAssert(level) { + return currentAssertionLevel >= level; + } + Debug.shouldAssert = shouldAssert; + function assert(expression, message, verboseDebugInfo) { + if (!expression) { + var verboseDebugString = ""; + if (verboseDebugInfo) { + verboseDebugString = "\r\nVerbose Debug Information: " + verboseDebugInfo(); + } + throw new Error("Debug Failure. False expression: " + (message || "") + verboseDebugString); + } + } + Debug.assert = assert; + function fail(message) { + Debug.assert(false, message); + } + Debug.fail = fail; + })(Debug = ts.Debug || (ts.Debug = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/declarationEmitter.js b/dist/typescript/compiler/declarationEmitter.js new file mode 100644 index 000000000..f7f993023 --- /dev/null +++ b/dist/typescript/compiler/declarationEmitter.js @@ -0,0 +1,1300 @@ +/// +var ts; +(function (ts) { + function getDeclarationDiagnostics(host, resolver, targetSourceFile) { + var diagnostics = []; + var jsFilePath = ts.getOwnEmitOutputFilePath(targetSourceFile, host, ".js"); + emitDeclarations(host, resolver, diagnostics, jsFilePath, targetSourceFile); + return diagnostics; + } + ts.getDeclarationDiagnostics = getDeclarationDiagnostics; + function emitDeclarations(host, resolver, diagnostics, jsFilePath, root) { + var newLine = host.getNewLine(); + var compilerOptions = host.getCompilerOptions(); + var languageVersion = compilerOptions.target || 0; + var write; + var writeLine; + var increaseIndent; + var decreaseIndent; + var writeTextOfNode; + var writer = createAndSetNewTextWriterWithSymbolWriter(); + var enclosingDeclaration; + var currentSourceFile; + var reportedDeclarationError = false; + var emitJsDocComments = compilerOptions.removeComments ? function (declaration) { } : writeJsDocComments; + var emit = compilerOptions.stripInternal ? stripInternal : emitNode; + var moduleElementDeclarationEmitInfo = []; + var asynchronousSubModuleDeclarationEmitInfo; + var referencePathsOutput = ""; + if (root) { + if (!compilerOptions.noResolve) { + var addedGlobalFileReference = false; + ts.forEach(root.referencedFiles, function (fileReference) { + var referencedFile = ts.tryResolveScriptReference(host, root, fileReference); + if (referencedFile && ((referencedFile.flags & 2048) || + ts.shouldEmitToOwnFile(referencedFile, compilerOptions) || + !addedGlobalFileReference)) { + writeReferencePath(referencedFile); + if (!ts.isExternalModuleOrDeclarationFile(referencedFile)) { + addedGlobalFileReference = true; + } + } + }); + } + emitSourceFile(root); + if (moduleElementDeclarationEmitInfo.length) { + var oldWriter = writer; + ts.forEach(moduleElementDeclarationEmitInfo, function (aliasEmitInfo) { + if (aliasEmitInfo.isVisible) { + ts.Debug.assert(aliasEmitInfo.node.kind === 209); + createAndSetNewTextWriterWithSymbolWriter(); + ts.Debug.assert(aliasEmitInfo.indent === 0); + writeImportDeclaration(aliasEmitInfo.node); + aliasEmitInfo.asynchronousOutput = writer.getText(); + } + }); + setWriter(oldWriter); + } + } + else { + var emittedReferencedFiles = []; + ts.forEach(host.getSourceFiles(), function (sourceFile) { + if (!ts.isExternalModuleOrDeclarationFile(sourceFile)) { + if (!compilerOptions.noResolve) { + ts.forEach(sourceFile.referencedFiles, function (fileReference) { + var referencedFile = ts.tryResolveScriptReference(host, sourceFile, fileReference); + if (referencedFile && (ts.isExternalModuleOrDeclarationFile(referencedFile) && + !ts.contains(emittedReferencedFiles, referencedFile))) { + writeReferencePath(referencedFile); + emittedReferencedFiles.push(referencedFile); + } + }); + } + emitSourceFile(sourceFile); + } + }); + } + return { + reportedDeclarationError: reportedDeclarationError, + moduleElementDeclarationEmitInfo: moduleElementDeclarationEmitInfo, + synchronousDeclarationOutput: writer.getText(), + referencePathsOutput: referencePathsOutput, + }; + function hasInternalAnnotation(range) { + var text = currentSourceFile.text; + var comment = text.substring(range.pos, range.end); + return comment.indexOf("@internal") >= 0; + } + function stripInternal(node) { + if (node) { + var leadingCommentRanges = ts.getLeadingCommentRanges(currentSourceFile.text, node.pos); + if (ts.forEach(leadingCommentRanges, hasInternalAnnotation)) { + return; + } + emitNode(node); + } + } + function createAndSetNewTextWriterWithSymbolWriter() { + var writer = ts.createTextWriter(newLine); + writer.trackSymbol = trackSymbol; + writer.writeKeyword = writer.write; + writer.writeOperator = writer.write; + writer.writePunctuation = writer.write; + writer.writeSpace = writer.write; + writer.writeStringLiteral = writer.writeLiteral; + writer.writeParameter = writer.write; + writer.writeSymbol = writer.write; + setWriter(writer); + return writer; + } + function setWriter(newWriter) { + writer = newWriter; + write = newWriter.write; + writeTextOfNode = newWriter.writeTextOfNode; + writeLine = newWriter.writeLine; + increaseIndent = newWriter.increaseIndent; + decreaseIndent = newWriter.decreaseIndent; + } + function writeAsynchronousModuleElements(nodes) { + var oldWriter = writer; + ts.forEach(nodes, function (declaration) { + var nodeToCheck; + if (declaration.kind === 198) { + nodeToCheck = declaration.parent.parent; + } + else if (declaration.kind === 212 || declaration.kind === 213 || declaration.kind === 210) { + ts.Debug.fail("We should be getting ImportDeclaration instead to write"); + } + else { + nodeToCheck = declaration; + } + var moduleElementEmitInfo = ts.forEach(moduleElementDeclarationEmitInfo, function (declEmitInfo) { return declEmitInfo.node === nodeToCheck ? declEmitInfo : undefined; }); + if (!moduleElementEmitInfo && asynchronousSubModuleDeclarationEmitInfo) { + moduleElementEmitInfo = ts.forEach(asynchronousSubModuleDeclarationEmitInfo, function (declEmitInfo) { return declEmitInfo.node === nodeToCheck ? declEmitInfo : undefined; }); + } + if (moduleElementEmitInfo) { + if (moduleElementEmitInfo.node.kind === 209) { + moduleElementEmitInfo.isVisible = true; + } + else { + createAndSetNewTextWriterWithSymbolWriter(); + for (var declarationIndent = moduleElementEmitInfo.indent; declarationIndent; declarationIndent--) { + increaseIndent(); + } + if (nodeToCheck.kind === 205) { + ts.Debug.assert(asynchronousSubModuleDeclarationEmitInfo === undefined); + asynchronousSubModuleDeclarationEmitInfo = []; + } + writeModuleElement(nodeToCheck); + if (nodeToCheck.kind === 205) { + moduleElementEmitInfo.subModuleElementDeclarationEmitInfo = asynchronousSubModuleDeclarationEmitInfo; + asynchronousSubModuleDeclarationEmitInfo = undefined; + } + moduleElementEmitInfo.asynchronousOutput = writer.getText(); + } + } + }); + setWriter(oldWriter); + } + function handleSymbolAccessibilityError(symbolAccesibilityResult) { + if (symbolAccesibilityResult.accessibility === 0) { + if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) { + writeAsynchronousModuleElements(symbolAccesibilityResult.aliasesToMakeVisible); + } + } + else { + reportedDeclarationError = true; + var errorInfo = writer.getSymbolAccessibilityDiagnostic(symbolAccesibilityResult); + if (errorInfo) { + if (errorInfo.typeName) { + diagnostics.push(ts.createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode, errorInfo.diagnosticMessage, ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, errorInfo.typeName), symbolAccesibilityResult.errorSymbolName, symbolAccesibilityResult.errorModuleName)); + } + else { + diagnostics.push(ts.createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode, errorInfo.diagnosticMessage, symbolAccesibilityResult.errorSymbolName, symbolAccesibilityResult.errorModuleName)); + } + } + } + } + function trackSymbol(symbol, enclosingDeclaration, meaning) { + handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning)); + } + function writeTypeOfDeclaration(declaration, type, getSymbolAccessibilityDiagnostic) { + writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic; + write(": "); + if (type) { + emitType(type); + } + else { + resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, 2, writer); + } + } + function writeReturnTypeAtSignature(signature, getSymbolAccessibilityDiagnostic) { + writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic; + write(": "); + if (signature.type) { + emitType(signature.type); + } + else { + resolver.writeReturnTypeOfSignatureDeclaration(signature, enclosingDeclaration, 2, writer); + } + } + function emitLines(nodes) { + for (var _i = 0; _i < nodes.length; _i++) { + var node = nodes[_i]; + emit(node); + } + } + function emitSeparatedList(nodes, separator, eachNodeEmitFn, canEmitFn) { + var currentWriterPos = writer.getTextPos(); + for (var _i = 0; _i < nodes.length; _i++) { + var node = nodes[_i]; + if (!canEmitFn || canEmitFn(node)) { + if (currentWriterPos !== writer.getTextPos()) { + write(separator); + } + currentWriterPos = writer.getTextPos(); + eachNodeEmitFn(node); + } + } + } + function emitCommaList(nodes, eachNodeEmitFn, canEmitFn) { + emitSeparatedList(nodes, ", ", eachNodeEmitFn, canEmitFn); + } + function writeJsDocComments(declaration) { + if (declaration) { + var jsDocComments = ts.getJsDocComments(declaration, currentSourceFile); + ts.emitNewLineBeforeLeadingComments(currentSourceFile, writer, declaration, jsDocComments); + ts.emitComments(currentSourceFile, writer, jsDocComments, true, newLine, ts.writeCommentRange); + } + } + function emitTypeWithNewGetSymbolAccessibilityDiagnostic(type, getSymbolAccessibilityDiagnostic) { + writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic; + emitType(type); + } + function emitType(type) { + switch (type.kind) { + case 112: + case 121: + case 119: + case 113: + case 122: + case 99: + case 8: + return writeTextOfNode(currentSourceFile, type); + case 177: + return emitHeritageClauseElement(type); + case 141: + return emitTypeReference(type); + case 144: + return emitTypeQuery(type); + case 146: + return emitArrayType(type); + case 147: + return emitTupleType(type); + case 148: + return emitUnionType(type); + case 149: + return emitParenType(type); + case 142: + case 143: + return emitSignatureDeclarationWithJsDocComments(type); + case 145: + return emitTypeLiteral(type); + case 65: + return emitEntityName(type); + case 126: + return emitEntityName(type); + } + function emitEntityName(entityName) { + var visibilityResult = resolver.isEntityNameVisible(entityName, entityName.parent.kind === 208 ? entityName.parent : enclosingDeclaration); + handleSymbolAccessibilityError(visibilityResult); + writeEntityName(entityName); + function writeEntityName(entityName) { + if (entityName.kind === 65) { + writeTextOfNode(currentSourceFile, entityName); + } + else { + var left = entityName.kind === 126 ? entityName.left : entityName.expression; + var right = entityName.kind === 126 ? entityName.right : entityName.name; + writeEntityName(left); + write("."); + writeTextOfNode(currentSourceFile, right); + } + } + } + function emitHeritageClauseElement(node) { + if (ts.isSupportedHeritageClauseElement(node)) { + ts.Debug.assert(node.expression.kind === 65 || node.expression.kind === 155); + emitEntityName(node.expression); + if (node.typeArguments) { + write("<"); + emitCommaList(node.typeArguments, emitType); + write(">"); + } + } + } + function emitTypeReference(type) { + emitEntityName(type.typeName); + if (type.typeArguments) { + write("<"); + emitCommaList(type.typeArguments, emitType); + write(">"); + } + } + function emitTypeQuery(type) { + write("typeof "); + emitEntityName(type.exprName); + } + function emitArrayType(type) { + emitType(type.elementType); + write("[]"); + } + function emitTupleType(type) { + write("["); + emitCommaList(type.elementTypes, emitType); + write("]"); + } + function emitUnionType(type) { + emitSeparatedList(type.types, " | ", emitType); + } + function emitParenType(type) { + write("("); + emitType(type.type); + write(")"); + } + function emitTypeLiteral(type) { + write("{"); + if (type.members.length) { + writeLine(); + increaseIndent(); + emitLines(type.members); + decreaseIndent(); + } + write("}"); + } + } + function emitSourceFile(node) { + currentSourceFile = node; + enclosingDeclaration = node; + emitLines(node.statements); + } + function getExportDefaultTempVariableName() { + var baseName = "_default"; + if (!ts.hasProperty(currentSourceFile.identifiers, baseName)) { + return baseName; + } + var count = 0; + while (true) { + var name_1 = baseName + "_" + (++count); + if (!ts.hasProperty(currentSourceFile.identifiers, name_1)) { + return name_1; + } + } + } + function emitExportAssignment(node) { + if (node.expression.kind === 65) { + write(node.isExportEquals ? "export = " : "export default "); + writeTextOfNode(currentSourceFile, node.expression); + } + else { + var tempVarName = getExportDefaultTempVariableName(); + write("declare var "); + write(tempVarName); + write(": "); + writer.getSymbolAccessibilityDiagnostic = getDefaultExportAccessibilityDiagnostic; + resolver.writeTypeOfExpression(node.expression, enclosingDeclaration, 2, writer); + write(";"); + writeLine(); + write(node.isExportEquals ? "export = " : "export default "); + write(tempVarName); + } + write(";"); + writeLine(); + if (node.expression.kind === 65) { + var nodes = resolver.collectLinkedAliases(node.expression); + writeAsynchronousModuleElements(nodes); + } + function getDefaultExportAccessibilityDiagnostic(diagnostic) { + return { + diagnosticMessage: ts.Diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0, + errorNode: node + }; + } + } + function isModuleElementVisible(node) { + return resolver.isDeclarationVisible(node); + } + function emitModuleElement(node, isModuleElementVisible) { + if (isModuleElementVisible) { + writeModuleElement(node); + } + else if (node.kind === 208 || + (node.parent.kind === 227 && ts.isExternalModule(currentSourceFile))) { + var isVisible; + if (asynchronousSubModuleDeclarationEmitInfo && node.parent.kind !== 227) { + asynchronousSubModuleDeclarationEmitInfo.push({ + node: node, + outputPos: writer.getTextPos(), + indent: writer.getIndent(), + isVisible: isVisible + }); + } + else { + if (node.kind === 209) { + var importDeclaration = node; + if (importDeclaration.importClause) { + isVisible = (importDeclaration.importClause.name && resolver.isDeclarationVisible(importDeclaration.importClause)) || + isVisibleNamedBinding(importDeclaration.importClause.namedBindings); + } + } + moduleElementDeclarationEmitInfo.push({ + node: node, + outputPos: writer.getTextPos(), + indent: writer.getIndent(), + isVisible: isVisible + }); + } + } + } + function writeModuleElement(node) { + switch (node.kind) { + case 200: + return writeFunctionDeclaration(node); + case 180: + return writeVariableStatement(node); + case 202: + return writeInterfaceDeclaration(node); + case 201: + return writeClassDeclaration(node); + case 203: + return writeTypeAliasDeclaration(node); + case 204: + return writeEnumDeclaration(node); + case 205: + return writeModuleDeclaration(node); + case 208: + return writeImportEqualsDeclaration(node); + case 209: + return writeImportDeclaration(node); + default: + ts.Debug.fail("Unknown symbol kind"); + } + } + function emitModuleElementDeclarationFlags(node) { + if (node.parent === currentSourceFile) { + if (node.flags & 1) { + write("export "); + } + if (node.flags & 256) { + write("default "); + } + else if (node.kind !== 202) { + write("declare "); + } + } + } + function emitClassMemberDeclarationFlags(node) { + if (node.flags & 32) { + write("private "); + } + else if (node.flags & 64) { + write("protected "); + } + if (node.flags & 128) { + write("static "); + } + } + function writeImportEqualsDeclaration(node) { + emitJsDocComments(node); + if (node.flags & 1) { + write("export "); + } + write("import "); + writeTextOfNode(currentSourceFile, node.name); + write(" = "); + if (ts.isInternalModuleImportEqualsDeclaration(node)) { + emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.moduleReference, getImportEntityNameVisibilityError); + write(";"); + } + else { + write("require("); + writeTextOfNode(currentSourceFile, ts.getExternalModuleImportEqualsDeclarationExpression(node)); + write(");"); + } + writer.writeLine(); + function getImportEntityNameVisibilityError(symbolAccesibilityResult) { + return { + diagnosticMessage: ts.Diagnostics.Import_declaration_0_is_using_private_name_1, + errorNode: node, + typeName: node.name + }; + } + } + function isVisibleNamedBinding(namedBindings) { + if (namedBindings) { + if (namedBindings.kind === 211) { + return resolver.isDeclarationVisible(namedBindings); + } + else { + return ts.forEach(namedBindings.elements, function (namedImport) { return resolver.isDeclarationVisible(namedImport); }); + } + } + } + function writeImportDeclaration(node) { + if (!node.importClause && !(node.flags & 1)) { + return; + } + emitJsDocComments(node); + if (node.flags & 1) { + write("export "); + } + write("import "); + if (node.importClause) { + var currentWriterPos = writer.getTextPos(); + if (node.importClause.name && resolver.isDeclarationVisible(node.importClause)) { + writeTextOfNode(currentSourceFile, node.importClause.name); + } + if (node.importClause.namedBindings && isVisibleNamedBinding(node.importClause.namedBindings)) { + if (currentWriterPos !== writer.getTextPos()) { + write(", "); + } + if (node.importClause.namedBindings.kind === 211) { + write("* as "); + writeTextOfNode(currentSourceFile, node.importClause.namedBindings.name); + } + else { + write("{ "); + emitCommaList(node.importClause.namedBindings.elements, emitImportOrExportSpecifier, resolver.isDeclarationVisible); + write(" }"); + } + } + write(" from "); + } + writeTextOfNode(currentSourceFile, node.moduleSpecifier); + write(";"); + writer.writeLine(); + } + function emitImportOrExportSpecifier(node) { + if (node.propertyName) { + writeTextOfNode(currentSourceFile, node.propertyName); + write(" as "); + } + writeTextOfNode(currentSourceFile, node.name); + } + function emitExportSpecifier(node) { + emitImportOrExportSpecifier(node); + var nodes = resolver.collectLinkedAliases(node.propertyName || node.name); + writeAsynchronousModuleElements(nodes); + } + function emitExportDeclaration(node) { + emitJsDocComments(node); + write("export "); + if (node.exportClause) { + write("{ "); + emitCommaList(node.exportClause.elements, emitExportSpecifier); + write(" }"); + } + else { + write("*"); + } + if (node.moduleSpecifier) { + write(" from "); + writeTextOfNode(currentSourceFile, node.moduleSpecifier); + } + write(";"); + writer.writeLine(); + } + function writeModuleDeclaration(node) { + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + write("module "); + writeTextOfNode(currentSourceFile, node.name); + while (node.body.kind !== 206) { + node = node.body; + write("."); + writeTextOfNode(currentSourceFile, node.name); + } + var prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = node; + write(" {"); + writeLine(); + increaseIndent(); + emitLines(node.body.statements); + decreaseIndent(); + write("}"); + writeLine(); + enclosingDeclaration = prevEnclosingDeclaration; + } + function writeTypeAliasDeclaration(node) { + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + write("type "); + writeTextOfNode(currentSourceFile, node.name); + write(" = "); + emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.type, getTypeAliasDeclarationVisibilityError); + write(";"); + writeLine(); + function getTypeAliasDeclarationVisibilityError(symbolAccesibilityResult) { + return { + diagnosticMessage: ts.Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1, + errorNode: node.type, + typeName: node.name + }; + } + } + function writeEnumDeclaration(node) { + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + if (ts.isConst(node)) { + write("const "); + } + write("enum "); + writeTextOfNode(currentSourceFile, node.name); + write(" {"); + writeLine(); + increaseIndent(); + emitLines(node.members); + decreaseIndent(); + write("}"); + writeLine(); + } + function emitEnumMemberDeclaration(node) { + emitJsDocComments(node); + writeTextOfNode(currentSourceFile, node.name); + var enumMemberValue = resolver.getConstantValue(node); + if (enumMemberValue !== undefined) { + write(" = "); + write(enumMemberValue.toString()); + } + write(","); + writeLine(); + } + function isPrivateMethodTypeParameter(node) { + return node.parent.kind === 134 && (node.parent.flags & 32); + } + function emitTypeParameters(typeParameters) { + function emitTypeParameter(node) { + increaseIndent(); + emitJsDocComments(node); + decreaseIndent(); + writeTextOfNode(currentSourceFile, node.name); + if (node.constraint && !isPrivateMethodTypeParameter(node)) { + write(" extends "); + if (node.parent.kind === 142 || + node.parent.kind === 143 || + (node.parent.parent && node.parent.parent.kind === 145)) { + ts.Debug.assert(node.parent.kind === 134 || + node.parent.kind === 133 || + node.parent.kind === 142 || + node.parent.kind === 143 || + node.parent.kind === 138 || + node.parent.kind === 139); + emitType(node.constraint); + } + else { + emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.constraint, getTypeParameterConstraintVisibilityError); + } + } + function getTypeParameterConstraintVisibilityError(symbolAccesibilityResult) { + var diagnosticMessage; + switch (node.parent.kind) { + case 201: + diagnosticMessage = ts.Diagnostics.Type_parameter_0_of_exported_class_has_or_is_using_private_name_1; + break; + case 202: + diagnosticMessage = ts.Diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1; + break; + case 139: + diagnosticMessage = ts.Diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; + break; + case 138: + diagnosticMessage = ts.Diagnostics.Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; + break; + case 134: + case 133: + if (node.parent.flags & 128) { + diagnosticMessage = ts.Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; + } + else if (node.parent.parent.kind === 201) { + diagnosticMessage = ts.Diagnostics.Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; + } + else { + diagnosticMessage = ts.Diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; + } + break; + case 200: + diagnosticMessage = ts.Diagnostics.Type_parameter_0_of_exported_function_has_or_is_using_private_name_1; + break; + default: + ts.Debug.fail("This is unknown parent for type parameter: " + node.parent.kind); + } + return { + diagnosticMessage: diagnosticMessage, + errorNode: node, + typeName: node.name + }; + } + } + if (typeParameters) { + write("<"); + emitCommaList(typeParameters, emitTypeParameter); + write(">"); + } + } + function emitHeritageClause(typeReferences, isImplementsList) { + if (typeReferences) { + write(isImplementsList ? " implements " : " extends "); + emitCommaList(typeReferences, emitTypeOfTypeReference); + } + function emitTypeOfTypeReference(node) { + if (ts.isSupportedHeritageClauseElement(node)) { + emitTypeWithNewGetSymbolAccessibilityDiagnostic(node, getHeritageClauseVisibilityError); + } + function getHeritageClauseVisibilityError(symbolAccesibilityResult) { + var diagnosticMessage; + if (node.parent.parent.kind === 201) { + diagnosticMessage = isImplementsList ? + ts.Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 : + ts.Diagnostics.Extends_clause_of_exported_class_0_has_or_is_using_private_name_1; + } + else { + diagnosticMessage = ts.Diagnostics.Extends_clause_of_exported_interface_0_has_or_is_using_private_name_1; + } + return { + diagnosticMessage: diagnosticMessage, + errorNode: node, + typeName: node.parent.parent.name + }; + } + } + } + function writeClassDeclaration(node) { + function emitParameterProperties(constructorDeclaration) { + if (constructorDeclaration) { + ts.forEach(constructorDeclaration.parameters, function (param) { + if (param.flags & 112) { + emitPropertyDeclaration(param); + } + }); + } + } + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + write("class "); + writeTextOfNode(currentSourceFile, node.name); + var prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = node; + emitTypeParameters(node.typeParameters); + var baseTypeNode = ts.getClassExtendsHeritageClauseElement(node); + if (baseTypeNode) { + emitHeritageClause([baseTypeNode], false); + } + emitHeritageClause(ts.getClassImplementsHeritageClauseElements(node), true); + write(" {"); + writeLine(); + increaseIndent(); + emitParameterProperties(ts.getFirstConstructorWithBody(node)); + emitLines(node.members); + decreaseIndent(); + write("}"); + writeLine(); + enclosingDeclaration = prevEnclosingDeclaration; + } + function writeInterfaceDeclaration(node) { + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + write("interface "); + writeTextOfNode(currentSourceFile, node.name); + var prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = node; + emitTypeParameters(node.typeParameters); + emitHeritageClause(ts.getInterfaceBaseTypeNodes(node), false); + write(" {"); + writeLine(); + increaseIndent(); + emitLines(node.members); + decreaseIndent(); + write("}"); + writeLine(); + enclosingDeclaration = prevEnclosingDeclaration; + } + function emitPropertyDeclaration(node) { + if (ts.hasDynamicName(node)) { + return; + } + emitJsDocComments(node); + emitClassMemberDeclarationFlags(node); + emitVariableDeclaration(node); + write(";"); + writeLine(); + } + function emitVariableDeclaration(node) { + if (node.kind !== 198 || resolver.isDeclarationVisible(node)) { + if (ts.isBindingPattern(node.name)) { + emitBindingPattern(node.name); + } + else { + writeTextOfNode(currentSourceFile, node.name); + if ((node.kind === 132 || node.kind === 131) && ts.hasQuestionToken(node)) { + write("?"); + } + if ((node.kind === 132 || node.kind === 131) && node.parent.kind === 145) { + emitTypeOfVariableDeclarationFromTypeLiteral(node); + } + else if (!(node.flags & 32)) { + writeTypeOfDeclaration(node, node.type, getVariableDeclarationTypeVisibilityError); + } + } + } + function getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult) { + if (node.kind === 198) { + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + ts.Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Exported_variable_0_has_or_is_using_private_name_1; + } + else if (node.kind === 132 || node.kind === 131) { + if (node.flags & 128) { + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + ts.Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1; + } + else if (node.parent.kind === 201) { + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + ts.Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1; + } + else { + return symbolAccesibilityResult.errorModuleName ? + ts.Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1; + } + } + } + function getVariableDeclarationTypeVisibilityError(symbolAccesibilityResult) { + var diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult); + return diagnosticMessage !== undefined ? { + diagnosticMessage: diagnosticMessage, + errorNode: node, + typeName: node.name + } : undefined; + } + function emitBindingPattern(bindingPattern) { + var elements = []; + for (var _i = 0, _a = bindingPattern.elements; _i < _a.length; _i++) { + var element = _a[_i]; + if (element.kind !== 175) { + elements.push(element); + } + } + emitCommaList(elements, emitBindingElement); + } + function emitBindingElement(bindingElement) { + function getBindingElementTypeVisibilityError(symbolAccesibilityResult) { + var diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult); + return diagnosticMessage !== undefined ? { + diagnosticMessage: diagnosticMessage, + errorNode: bindingElement, + typeName: bindingElement.name + } : undefined; + } + if (bindingElement.name) { + if (ts.isBindingPattern(bindingElement.name)) { + emitBindingPattern(bindingElement.name); + } + else { + writeTextOfNode(currentSourceFile, bindingElement.name); + writeTypeOfDeclaration(bindingElement, undefined, getBindingElementTypeVisibilityError); + } + } + } + } + function emitTypeOfVariableDeclarationFromTypeLiteral(node) { + if (node.type) { + write(": "); + emitType(node.type); + } + } + function isVariableStatementVisible(node) { + return ts.forEach(node.declarationList.declarations, function (varDeclaration) { return resolver.isDeclarationVisible(varDeclaration); }); + } + function writeVariableStatement(node) { + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + if (ts.isLet(node.declarationList)) { + write("let "); + } + else if (ts.isConst(node.declarationList)) { + write("const "); + } + else { + write("var "); + } + emitCommaList(node.declarationList.declarations, emitVariableDeclaration, resolver.isDeclarationVisible); + write(";"); + writeLine(); + } + function emitAccessorDeclaration(node) { + if (ts.hasDynamicName(node)) { + return; + } + var accessors = ts.getAllAccessorDeclarations(node.parent.members, node); + var accessorWithTypeAnnotation; + if (node === accessors.firstAccessor) { + emitJsDocComments(accessors.getAccessor); + emitJsDocComments(accessors.setAccessor); + emitClassMemberDeclarationFlags(node); + writeTextOfNode(currentSourceFile, node.name); + if (!(node.flags & 32)) { + accessorWithTypeAnnotation = node; + var type = getTypeAnnotationFromAccessor(node); + if (!type) { + var anotherAccessor = node.kind === 136 ? accessors.setAccessor : accessors.getAccessor; + type = getTypeAnnotationFromAccessor(anotherAccessor); + if (type) { + accessorWithTypeAnnotation = anotherAccessor; + } + } + writeTypeOfDeclaration(node, type, getAccessorDeclarationTypeVisibilityError); + } + write(";"); + writeLine(); + } + function getTypeAnnotationFromAccessor(accessor) { + if (accessor) { + return accessor.kind === 136 + ? accessor.type + : accessor.parameters.length > 0 + ? accessor.parameters[0].type + : undefined; + } + } + function getAccessorDeclarationTypeVisibilityError(symbolAccesibilityResult) { + var diagnosticMessage; + if (accessorWithTypeAnnotation.kind === 137) { + if (accessorWithTypeAnnotation.parent.flags & 128) { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + ts.Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1; + } + else { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + ts.Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_name_1; + } + return { + diagnosticMessage: diagnosticMessage, + errorNode: accessorWithTypeAnnotation.parameters[0], + typeName: accessorWithTypeAnnotation.name + }; + } + else { + if (accessorWithTypeAnnotation.flags & 128) { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : + ts.Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 : + ts.Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_name_0; + } + else { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : + ts.Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 : + ts.Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_name_0; + } + return { + diagnosticMessage: diagnosticMessage, + errorNode: accessorWithTypeAnnotation.name, + typeName: undefined + }; + } + } + } + function writeFunctionDeclaration(node) { + if (ts.hasDynamicName(node)) { + return; + } + if (!resolver.isImplementationOfOverload(node)) { + emitJsDocComments(node); + if (node.kind === 200) { + emitModuleElementDeclarationFlags(node); + } + else if (node.kind === 134) { + emitClassMemberDeclarationFlags(node); + } + if (node.kind === 200) { + write("function "); + writeTextOfNode(currentSourceFile, node.name); + } + else if (node.kind === 135) { + write("constructor"); + } + else { + writeTextOfNode(currentSourceFile, node.name); + if (ts.hasQuestionToken(node)) { + write("?"); + } + } + emitSignatureDeclaration(node); + } + } + function emitSignatureDeclarationWithJsDocComments(node) { + emitJsDocComments(node); + emitSignatureDeclaration(node); + } + function emitSignatureDeclaration(node) { + if (node.kind === 139 || node.kind === 143) { + write("new "); + } + emitTypeParameters(node.typeParameters); + if (node.kind === 140) { + write("["); + } + else { + write("("); + } + var prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = node; + emitCommaList(node.parameters, emitParameterDeclaration); + if (node.kind === 140) { + write("]"); + } + else { + write(")"); + } + var isFunctionTypeOrConstructorType = node.kind === 142 || node.kind === 143; + if (isFunctionTypeOrConstructorType || node.parent.kind === 145) { + if (node.type) { + write(isFunctionTypeOrConstructorType ? " => " : ": "); + emitType(node.type); + } + } + else if (node.kind !== 135 && !(node.flags & 32)) { + writeReturnTypeAtSignature(node, getReturnTypeVisibilityError); + } + enclosingDeclaration = prevEnclosingDeclaration; + if (!isFunctionTypeOrConstructorType) { + write(";"); + writeLine(); + } + function getReturnTypeVisibilityError(symbolAccesibilityResult) { + var diagnosticMessage; + switch (node.kind) { + case 139: + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + ts.Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : + ts.Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0; + break; + case 138: + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + ts.Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : + ts.Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0; + break; + case 140: + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + ts.Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : + ts.Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0; + break; + case 134: + case 133: + if (node.flags & 128) { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : + ts.Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 : + ts.Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0; + } + else if (node.parent.kind === 201) { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : + ts.Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 : + ts.Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0; + } + else { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + ts.Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : + ts.Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0; + } + break; + case 200: + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : + ts.Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1 : + ts.Diagnostics.Return_type_of_exported_function_has_or_is_using_private_name_0; + break; + default: + ts.Debug.fail("This is unknown kind for signature: " + node.kind); + } + return { + diagnosticMessage: diagnosticMessage, + errorNode: node.name || node, + }; + } + } + function emitParameterDeclaration(node) { + increaseIndent(); + emitJsDocComments(node); + if (node.dotDotDotToken) { + write("..."); + } + if (ts.isBindingPattern(node.name)) { + emitBindingPattern(node.name); + } + else { + writeTextOfNode(currentSourceFile, node.name); + } + if (node.initializer || ts.hasQuestionToken(node)) { + write("?"); + } + decreaseIndent(); + if (node.parent.kind === 142 || + node.parent.kind === 143 || + node.parent.parent.kind === 145) { + emitTypeOfVariableDeclarationFromTypeLiteral(node); + } + else if (!(node.parent.flags & 32)) { + writeTypeOfDeclaration(node, node.type, getParameterDeclarationTypeVisibilityError); + } + function getParameterDeclarationTypeVisibilityError(symbolAccesibilityResult) { + var diagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult); + return diagnosticMessage !== undefined ? { + diagnosticMessage: diagnosticMessage, + errorNode: node, + typeName: node.name + } : undefined; + } + function getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult) { + switch (node.parent.kind) { + case 135: + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + ts.Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1; + case 139: + return symbolAccesibilityResult.errorModuleName ? + ts.Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; + case 138: + return symbolAccesibilityResult.errorModuleName ? + ts.Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; + case 134: + case 133: + if (node.parent.flags & 128) { + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + ts.Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; + } + else if (node.parent.parent.kind === 201) { + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + ts.Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; + } + else { + return symbolAccesibilityResult.errorModuleName ? + ts.Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; + } + case 200: + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === 2 ? + ts.Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + ts.Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 : + ts.Diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1; + default: + ts.Debug.fail("This is unknown parent for parameter: " + node.parent.kind); + } + } + function emitBindingPattern(bindingPattern) { + if (bindingPattern.kind === 150) { + write("{"); + emitCommaList(bindingPattern.elements, emitBindingElement); + write("}"); + } + else if (bindingPattern.kind === 151) { + write("["); + var elements = bindingPattern.elements; + emitCommaList(elements, emitBindingElement); + if (elements && elements.hasTrailingComma) { + write(", "); + } + write("]"); + } + } + function emitBindingElement(bindingElement) { + function getBindingElementTypeVisibilityError(symbolAccesibilityResult) { + var diagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult); + return diagnosticMessage !== undefined ? { + diagnosticMessage: diagnosticMessage, + errorNode: bindingElement, + typeName: bindingElement.name + } : undefined; + } + if (bindingElement.kind === 175) { + write(" "); + } + else if (bindingElement.kind === 152) { + if (bindingElement.propertyName) { + writeTextOfNode(currentSourceFile, bindingElement.propertyName); + write(": "); + emitBindingPattern(bindingElement.name); + } + else if (bindingElement.name) { + if (ts.isBindingPattern(bindingElement.name)) { + emitBindingPattern(bindingElement.name); + } + else { + ts.Debug.assert(bindingElement.name.kind === 65); + if (bindingElement.dotDotDotToken) { + write("..."); + } + writeTextOfNode(currentSourceFile, bindingElement.name); + } + } + } + } + } + function emitNode(node) { + switch (node.kind) { + case 200: + case 205: + case 208: + case 202: + case 201: + case 203: + case 204: + return emitModuleElement(node, isModuleElementVisible(node)); + case 180: + return emitModuleElement(node, isVariableStatementVisible(node)); + case 209: + return emitModuleElement(node, !node.importClause); + case 215: + return emitExportDeclaration(node); + case 135: + case 134: + case 133: + return writeFunctionDeclaration(node); + case 139: + case 138: + case 140: + return emitSignatureDeclarationWithJsDocComments(node); + case 136: + case 137: + return emitAccessorDeclaration(node); + case 132: + case 131: + return emitPropertyDeclaration(node); + case 226: + return emitEnumMemberDeclaration(node); + case 214: + return emitExportAssignment(node); + case 227: + return emitSourceFile(node); + } + } + function writeReferencePath(referencedFile) { + var declFileName = referencedFile.flags & 2048 + ? referencedFile.fileName + : ts.shouldEmitToOwnFile(referencedFile, compilerOptions) + ? ts.getOwnEmitOutputFilePath(referencedFile, host, ".d.ts") + : ts.removeFileExtension(compilerOptions.out) + ".d.ts"; + declFileName = ts.getRelativePathToDirectoryOrUrl(ts.getDirectoryPath(ts.normalizeSlashes(jsFilePath)), declFileName, host.getCurrentDirectory(), host.getCanonicalFileName, false); + referencePathsOutput += "/// " + newLine; + } + } + function writeDeclarationFile(jsFilePath, sourceFile, host, resolver, diagnostics) { + var emitDeclarationResult = emitDeclarations(host, resolver, diagnostics, jsFilePath, sourceFile); + if (!emitDeclarationResult.reportedDeclarationError) { + var declarationOutput = emitDeclarationResult.referencePathsOutput + + getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo); + ts.writeFile(host, diagnostics, ts.removeFileExtension(jsFilePath) + ".d.ts", declarationOutput, host.getCompilerOptions().emitBOM); + } + function getDeclarationOutput(synchronousDeclarationOutput, moduleElementDeclarationEmitInfo) { + var appliedSyncOutputPos = 0; + var declarationOutput = ""; + ts.forEach(moduleElementDeclarationEmitInfo, function (aliasEmitInfo) { + if (aliasEmitInfo.asynchronousOutput) { + declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos, aliasEmitInfo.outputPos); + declarationOutput += getDeclarationOutput(aliasEmitInfo.asynchronousOutput, aliasEmitInfo.subModuleElementDeclarationEmitInfo); + appliedSyncOutputPos = aliasEmitInfo.outputPos; + } + }); + declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos); + return declarationOutput; + } + } + ts.writeDeclarationFile = writeDeclarationFile; +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/diagnosticInformationMap.generated.js b/dist/typescript/compiler/diagnosticInformationMap.generated.js new file mode 100644 index 000000000..1d25c0864 --- /dev/null +++ b/dist/typescript/compiler/diagnosticInformationMap.generated.js @@ -0,0 +1,541 @@ +/// +var ts; +(function (ts) { + ts.Diagnostics = { + Unterminated_string_literal: { code: 1002, category: ts.DiagnosticCategory.Error, key: "Unterminated string literal." }, + Identifier_expected: { code: 1003, category: ts.DiagnosticCategory.Error, key: "Identifier expected." }, + _0_expected: { code: 1005, category: ts.DiagnosticCategory.Error, key: "'{0}' expected." }, + A_file_cannot_have_a_reference_to_itself: { code: 1006, category: ts.DiagnosticCategory.Error, key: "A file cannot have a reference to itself." }, + Trailing_comma_not_allowed: { code: 1009, category: ts.DiagnosticCategory.Error, key: "Trailing comma not allowed." }, + Asterisk_Slash_expected: { code: 1010, category: ts.DiagnosticCategory.Error, key: "'*/' expected." }, + Unexpected_token: { code: 1012, category: ts.DiagnosticCategory.Error, key: "Unexpected token." }, + A_rest_parameter_must_be_last_in_a_parameter_list: { code: 1014, category: ts.DiagnosticCategory.Error, key: "A rest parameter must be last in a parameter list." }, + Parameter_cannot_have_question_mark_and_initializer: { code: 1015, category: ts.DiagnosticCategory.Error, key: "Parameter cannot have question mark and initializer." }, + A_required_parameter_cannot_follow_an_optional_parameter: { code: 1016, category: ts.DiagnosticCategory.Error, key: "A required parameter cannot follow an optional parameter." }, + An_index_signature_cannot_have_a_rest_parameter: { code: 1017, category: ts.DiagnosticCategory.Error, key: "An index signature cannot have a rest parameter." }, + An_index_signature_parameter_cannot_have_an_accessibility_modifier: { code: 1018, category: ts.DiagnosticCategory.Error, key: "An index signature parameter cannot have an accessibility modifier." }, + An_index_signature_parameter_cannot_have_a_question_mark: { code: 1019, category: ts.DiagnosticCategory.Error, key: "An index signature parameter cannot have a question mark." }, + An_index_signature_parameter_cannot_have_an_initializer: { code: 1020, category: ts.DiagnosticCategory.Error, key: "An index signature parameter cannot have an initializer." }, + An_index_signature_must_have_a_type_annotation: { code: 1021, category: ts.DiagnosticCategory.Error, key: "An index signature must have a type annotation." }, + An_index_signature_parameter_must_have_a_type_annotation: { code: 1022, category: ts.DiagnosticCategory.Error, key: "An index signature parameter must have a type annotation." }, + An_index_signature_parameter_type_must_be_string_or_number: { code: 1023, category: ts.DiagnosticCategory.Error, key: "An index signature parameter type must be 'string' or 'number'." }, + A_class_or_interface_declaration_can_only_have_one_extends_clause: { code: 1024, category: ts.DiagnosticCategory.Error, key: "A class or interface declaration can only have one 'extends' clause." }, + An_extends_clause_must_precede_an_implements_clause: { code: 1025, category: ts.DiagnosticCategory.Error, key: "An 'extends' clause must precede an 'implements' clause." }, + A_class_can_only_extend_a_single_class: { code: 1026, category: ts.DiagnosticCategory.Error, key: "A class can only extend a single class." }, + A_class_declaration_can_only_have_one_implements_clause: { code: 1027, category: ts.DiagnosticCategory.Error, key: "A class declaration can only have one 'implements' clause." }, + Accessibility_modifier_already_seen: { code: 1028, category: ts.DiagnosticCategory.Error, key: "Accessibility modifier already seen." }, + _0_modifier_must_precede_1_modifier: { code: 1029, category: ts.DiagnosticCategory.Error, key: "'{0}' modifier must precede '{1}' modifier." }, + _0_modifier_already_seen: { code: 1030, category: ts.DiagnosticCategory.Error, key: "'{0}' modifier already seen." }, + _0_modifier_cannot_appear_on_a_class_element: { code: 1031, category: ts.DiagnosticCategory.Error, key: "'{0}' modifier cannot appear on a class element." }, + An_interface_declaration_cannot_have_an_implements_clause: { code: 1032, category: ts.DiagnosticCategory.Error, key: "An interface declaration cannot have an 'implements' clause." }, + super_must_be_followed_by_an_argument_list_or_member_access: { code: 1034, category: ts.DiagnosticCategory.Error, key: "'super' must be followed by an argument list or member access." }, + Only_ambient_modules_can_use_quoted_names: { code: 1035, category: ts.DiagnosticCategory.Error, key: "Only ambient modules can use quoted names." }, + Statements_are_not_allowed_in_ambient_contexts: { code: 1036, category: ts.DiagnosticCategory.Error, key: "Statements are not allowed in ambient contexts." }, + A_declare_modifier_cannot_be_used_in_an_already_ambient_context: { code: 1038, category: ts.DiagnosticCategory.Error, key: "A 'declare' modifier cannot be used in an already ambient context." }, + Initializers_are_not_allowed_in_ambient_contexts: { code: 1039, category: ts.DiagnosticCategory.Error, key: "Initializers are not allowed in ambient contexts." }, + _0_modifier_cannot_appear_on_a_module_element: { code: 1044, category: ts.DiagnosticCategory.Error, key: "'{0}' modifier cannot appear on a module element." }, + A_declare_modifier_cannot_be_used_with_an_interface_declaration: { code: 1045, category: ts.DiagnosticCategory.Error, key: "A 'declare' modifier cannot be used with an interface declaration." }, + A_declare_modifier_is_required_for_a_top_level_declaration_in_a_d_ts_file: { code: 1046, category: ts.DiagnosticCategory.Error, key: "A 'declare' modifier is required for a top level declaration in a .d.ts file." }, + A_rest_parameter_cannot_be_optional: { code: 1047, category: ts.DiagnosticCategory.Error, key: "A rest parameter cannot be optional." }, + A_rest_parameter_cannot_have_an_initializer: { code: 1048, category: ts.DiagnosticCategory.Error, key: "A rest parameter cannot have an initializer." }, + A_set_accessor_must_have_exactly_one_parameter: { code: 1049, category: ts.DiagnosticCategory.Error, key: "A 'set' accessor must have exactly one parameter." }, + A_set_accessor_cannot_have_an_optional_parameter: { code: 1051, category: ts.DiagnosticCategory.Error, key: "A 'set' accessor cannot have an optional parameter." }, + A_set_accessor_parameter_cannot_have_an_initializer: { code: 1052, category: ts.DiagnosticCategory.Error, key: "A 'set' accessor parameter cannot have an initializer." }, + A_set_accessor_cannot_have_rest_parameter: { code: 1053, category: ts.DiagnosticCategory.Error, key: "A 'set' accessor cannot have rest parameter." }, + A_get_accessor_cannot_have_parameters: { code: 1054, category: ts.DiagnosticCategory.Error, key: "A 'get' accessor cannot have parameters." }, + Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher: { code: 1056, category: ts.DiagnosticCategory.Error, key: "Accessors are only available when targeting ECMAScript 5 and higher." }, + Enum_member_must_have_initializer: { code: 1061, category: ts.DiagnosticCategory.Error, key: "Enum member must have initializer." }, + An_export_assignment_cannot_be_used_in_an_internal_module: { code: 1063, category: ts.DiagnosticCategory.Error, key: "An export assignment cannot be used in an internal module." }, + Ambient_enum_elements_can_only_have_integer_literal_initializers: { code: 1066, category: ts.DiagnosticCategory.Error, key: "Ambient enum elements can only have integer literal initializers." }, + Unexpected_token_A_constructor_method_accessor_or_property_was_expected: { code: 1068, category: ts.DiagnosticCategory.Error, key: "Unexpected token. A constructor, method, accessor, or property was expected." }, + A_declare_modifier_cannot_be_used_with_an_import_declaration: { code: 1079, category: ts.DiagnosticCategory.Error, key: "A 'declare' modifier cannot be used with an import declaration." }, + Invalid_reference_directive_syntax: { code: 1084, category: ts.DiagnosticCategory.Error, key: "Invalid 'reference' directive syntax." }, + Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher: { code: 1085, category: ts.DiagnosticCategory.Error, key: "Octal literals are not available when targeting ECMAScript 5 and higher." }, + An_accessor_cannot_be_declared_in_an_ambient_context: { code: 1086, category: ts.DiagnosticCategory.Error, key: "An accessor cannot be declared in an ambient context." }, + _0_modifier_cannot_appear_on_a_constructor_declaration: { code: 1089, category: ts.DiagnosticCategory.Error, key: "'{0}' modifier cannot appear on a constructor declaration." }, + _0_modifier_cannot_appear_on_a_parameter: { code: 1090, category: ts.DiagnosticCategory.Error, key: "'{0}' modifier cannot appear on a parameter." }, + Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement: { code: 1091, category: ts.DiagnosticCategory.Error, key: "Only a single variable declaration is allowed in a 'for...in' statement." }, + Type_parameters_cannot_appear_on_a_constructor_declaration: { code: 1092, category: ts.DiagnosticCategory.Error, key: "Type parameters cannot appear on a constructor declaration." }, + Type_annotation_cannot_appear_on_a_constructor_declaration: { code: 1093, category: ts.DiagnosticCategory.Error, key: "Type annotation cannot appear on a constructor declaration." }, + An_accessor_cannot_have_type_parameters: { code: 1094, category: ts.DiagnosticCategory.Error, key: "An accessor cannot have type parameters." }, + A_set_accessor_cannot_have_a_return_type_annotation: { code: 1095, category: ts.DiagnosticCategory.Error, key: "A 'set' accessor cannot have a return type annotation." }, + An_index_signature_must_have_exactly_one_parameter: { code: 1096, category: ts.DiagnosticCategory.Error, key: "An index signature must have exactly one parameter." }, + _0_list_cannot_be_empty: { code: 1097, category: ts.DiagnosticCategory.Error, key: "'{0}' list cannot be empty." }, + Type_parameter_list_cannot_be_empty: { code: 1098, category: ts.DiagnosticCategory.Error, key: "Type parameter list cannot be empty." }, + Type_argument_list_cannot_be_empty: { code: 1099, category: ts.DiagnosticCategory.Error, key: "Type argument list cannot be empty." }, + Invalid_use_of_0_in_strict_mode: { code: 1100, category: ts.DiagnosticCategory.Error, key: "Invalid use of '{0}' in strict mode." }, + with_statements_are_not_allowed_in_strict_mode: { code: 1101, category: ts.DiagnosticCategory.Error, key: "'with' statements are not allowed in strict mode." }, + delete_cannot_be_called_on_an_identifier_in_strict_mode: { code: 1102, category: ts.DiagnosticCategory.Error, key: "'delete' cannot be called on an identifier in strict mode." }, + A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement: { code: 1104, category: ts.DiagnosticCategory.Error, key: "A 'continue' statement can only be used within an enclosing iteration statement." }, + A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement: { code: 1105, category: ts.DiagnosticCategory.Error, key: "A 'break' statement can only be used within an enclosing iteration or switch statement." }, + Jump_target_cannot_cross_function_boundary: { code: 1107, category: ts.DiagnosticCategory.Error, key: "Jump target cannot cross function boundary." }, + A_return_statement_can_only_be_used_within_a_function_body: { code: 1108, category: ts.DiagnosticCategory.Error, key: "A 'return' statement can only be used within a function body." }, + Expression_expected: { code: 1109, category: ts.DiagnosticCategory.Error, key: "Expression expected." }, + Type_expected: { code: 1110, category: ts.DiagnosticCategory.Error, key: "Type expected." }, + A_class_member_cannot_be_declared_optional: { code: 1112, category: ts.DiagnosticCategory.Error, key: "A class member cannot be declared optional." }, + A_default_clause_cannot_appear_more_than_once_in_a_switch_statement: { code: 1113, category: ts.DiagnosticCategory.Error, key: "A 'default' clause cannot appear more than once in a 'switch' statement." }, + Duplicate_label_0: { code: 1114, category: ts.DiagnosticCategory.Error, key: "Duplicate label '{0}'" }, + A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement: { code: 1115, category: ts.DiagnosticCategory.Error, key: "A 'continue' statement can only jump to a label of an enclosing iteration statement." }, + A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement: { code: 1116, category: ts.DiagnosticCategory.Error, key: "A 'break' statement can only jump to a label of an enclosing statement." }, + An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode: { code: 1117, category: ts.DiagnosticCategory.Error, key: "An object literal cannot have multiple properties with the same name in strict mode." }, + An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name: { code: 1118, category: ts.DiagnosticCategory.Error, key: "An object literal cannot have multiple get/set accessors with the same name." }, + An_object_literal_cannot_have_property_and_accessor_with_the_same_name: { code: 1119, category: ts.DiagnosticCategory.Error, key: "An object literal cannot have property and accessor with the same name." }, + An_export_assignment_cannot_have_modifiers: { code: 1120, category: ts.DiagnosticCategory.Error, key: "An export assignment cannot have modifiers." }, + Octal_literals_are_not_allowed_in_strict_mode: { code: 1121, category: ts.DiagnosticCategory.Error, key: "Octal literals are not allowed in strict mode." }, + A_tuple_type_element_list_cannot_be_empty: { code: 1122, category: ts.DiagnosticCategory.Error, key: "A tuple type element list cannot be empty." }, + Variable_declaration_list_cannot_be_empty: { code: 1123, category: ts.DiagnosticCategory.Error, key: "Variable declaration list cannot be empty." }, + Digit_expected: { code: 1124, category: ts.DiagnosticCategory.Error, key: "Digit expected." }, + Hexadecimal_digit_expected: { code: 1125, category: ts.DiagnosticCategory.Error, key: "Hexadecimal digit expected." }, + Unexpected_end_of_text: { code: 1126, category: ts.DiagnosticCategory.Error, key: "Unexpected end of text." }, + Invalid_character: { code: 1127, category: ts.DiagnosticCategory.Error, key: "Invalid character." }, + Declaration_or_statement_expected: { code: 1128, category: ts.DiagnosticCategory.Error, key: "Declaration or statement expected." }, + Statement_expected: { code: 1129, category: ts.DiagnosticCategory.Error, key: "Statement expected." }, + case_or_default_expected: { code: 1130, category: ts.DiagnosticCategory.Error, key: "'case' or 'default' expected." }, + Property_or_signature_expected: { code: 1131, category: ts.DiagnosticCategory.Error, key: "Property or signature expected." }, + Enum_member_expected: { code: 1132, category: ts.DiagnosticCategory.Error, key: "Enum member expected." }, + Type_reference_expected: { code: 1133, category: ts.DiagnosticCategory.Error, key: "Type reference expected." }, + Variable_declaration_expected: { code: 1134, category: ts.DiagnosticCategory.Error, key: "Variable declaration expected." }, + Argument_expression_expected: { code: 1135, category: ts.DiagnosticCategory.Error, key: "Argument expression expected." }, + Property_assignment_expected: { code: 1136, category: ts.DiagnosticCategory.Error, key: "Property assignment expected." }, + Expression_or_comma_expected: { code: 1137, category: ts.DiagnosticCategory.Error, key: "Expression or comma expected." }, + Parameter_declaration_expected: { code: 1138, category: ts.DiagnosticCategory.Error, key: "Parameter declaration expected." }, + Type_parameter_declaration_expected: { code: 1139, category: ts.DiagnosticCategory.Error, key: "Type parameter declaration expected." }, + Type_argument_expected: { code: 1140, category: ts.DiagnosticCategory.Error, key: "Type argument expected." }, + String_literal_expected: { code: 1141, category: ts.DiagnosticCategory.Error, key: "String literal expected." }, + Line_break_not_permitted_here: { code: 1142, category: ts.DiagnosticCategory.Error, key: "Line break not permitted here." }, + or_expected: { code: 1144, category: ts.DiagnosticCategory.Error, key: "'{' or ';' expected." }, + Modifiers_not_permitted_on_index_signature_members: { code: 1145, category: ts.DiagnosticCategory.Error, key: "Modifiers not permitted on index signature members." }, + Declaration_expected: { code: 1146, category: ts.DiagnosticCategory.Error, key: "Declaration expected." }, + Import_declarations_in_an_internal_module_cannot_reference_an_external_module: { code: 1147, category: ts.DiagnosticCategory.Error, key: "Import declarations in an internal module cannot reference an external module." }, + Cannot_compile_external_modules_unless_the_module_flag_is_provided: { code: 1148, category: ts.DiagnosticCategory.Error, key: "Cannot compile external modules unless the '--module' flag is provided." }, + File_name_0_differs_from_already_included_file_name_1_only_in_casing: { code: 1149, category: ts.DiagnosticCategory.Error, key: "File name '{0}' differs from already included file name '{1}' only in casing" }, + new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 1150, category: ts.DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array()' instead." }, + var_let_or_const_expected: { code: 1152, category: ts.DiagnosticCategory.Error, key: "'var', 'let' or 'const' expected." }, + let_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1153, category: ts.DiagnosticCategory.Error, key: "'let' declarations are only available when targeting ECMAScript 6 and higher." }, + const_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1154, category: ts.DiagnosticCategory.Error, key: "'const' declarations are only available when targeting ECMAScript 6 and higher." }, + const_declarations_must_be_initialized: { code: 1155, category: ts.DiagnosticCategory.Error, key: "'const' declarations must be initialized" }, + const_declarations_can_only_be_declared_inside_a_block: { code: 1156, category: ts.DiagnosticCategory.Error, key: "'const' declarations can only be declared inside a block." }, + let_declarations_can_only_be_declared_inside_a_block: { code: 1157, category: ts.DiagnosticCategory.Error, key: "'let' declarations can only be declared inside a block." }, + Unterminated_template_literal: { code: 1160, category: ts.DiagnosticCategory.Error, key: "Unterminated template literal." }, + Unterminated_regular_expression_literal: { code: 1161, category: ts.DiagnosticCategory.Error, key: "Unterminated regular expression literal." }, + An_object_member_cannot_be_declared_optional: { code: 1162, category: ts.DiagnosticCategory.Error, key: "An object member cannot be declared optional." }, + yield_expression_must_be_contained_within_a_generator_declaration: { code: 1163, category: ts.DiagnosticCategory.Error, key: "'yield' expression must be contained_within a generator declaration." }, + Computed_property_names_are_not_allowed_in_enums: { code: 1164, category: ts.DiagnosticCategory.Error, key: "Computed property names are not allowed in enums." }, + A_computed_property_name_in_an_ambient_context_must_directly_refer_to_a_built_in_symbol: { code: 1165, category: ts.DiagnosticCategory.Error, key: "A computed property name in an ambient context must directly refer to a built-in symbol." }, + A_computed_property_name_in_a_class_property_declaration_must_directly_refer_to_a_built_in_symbol: { code: 1166, category: ts.DiagnosticCategory.Error, key: "A computed property name in a class property declaration must directly refer to a built-in symbol." }, + Computed_property_names_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1167, category: ts.DiagnosticCategory.Error, key: "Computed property names are only available when targeting ECMAScript 6 and higher." }, + A_computed_property_name_in_a_method_overload_must_directly_refer_to_a_built_in_symbol: { code: 1168, category: ts.DiagnosticCategory.Error, key: "A computed property name in a method overload must directly refer to a built-in symbol." }, + A_computed_property_name_in_an_interface_must_directly_refer_to_a_built_in_symbol: { code: 1169, category: ts.DiagnosticCategory.Error, key: "A computed property name in an interface must directly refer to a built-in symbol." }, + A_computed_property_name_in_a_type_literal_must_directly_refer_to_a_built_in_symbol: { code: 1170, category: ts.DiagnosticCategory.Error, key: "A computed property name in a type literal must directly refer to a built-in symbol." }, + A_comma_expression_is_not_allowed_in_a_computed_property_name: { code: 1171, category: ts.DiagnosticCategory.Error, key: "A comma expression is not allowed in a computed property name." }, + extends_clause_already_seen: { code: 1172, category: ts.DiagnosticCategory.Error, key: "'extends' clause already seen." }, + extends_clause_must_precede_implements_clause: { code: 1173, category: ts.DiagnosticCategory.Error, key: "'extends' clause must precede 'implements' clause." }, + Classes_can_only_extend_a_single_class: { code: 1174, category: ts.DiagnosticCategory.Error, key: "Classes can only extend a single class." }, + implements_clause_already_seen: { code: 1175, category: ts.DiagnosticCategory.Error, key: "'implements' clause already seen." }, + Interface_declaration_cannot_have_implements_clause: { code: 1176, category: ts.DiagnosticCategory.Error, key: "Interface declaration cannot have 'implements' clause." }, + Binary_digit_expected: { code: 1177, category: ts.DiagnosticCategory.Error, key: "Binary digit expected." }, + Octal_digit_expected: { code: 1178, category: ts.DiagnosticCategory.Error, key: "Octal digit expected." }, + Unexpected_token_expected: { code: 1179, category: ts.DiagnosticCategory.Error, key: "Unexpected token. '{' expected." }, + Property_destructuring_pattern_expected: { code: 1180, category: ts.DiagnosticCategory.Error, key: "Property destructuring pattern expected." }, + Array_element_destructuring_pattern_expected: { code: 1181, category: ts.DiagnosticCategory.Error, key: "Array element destructuring pattern expected." }, + A_destructuring_declaration_must_have_an_initializer: { code: 1182, category: ts.DiagnosticCategory.Error, key: "A destructuring declaration must have an initializer." }, + Destructuring_declarations_are_not_allowed_in_ambient_contexts: { code: 1183, category: ts.DiagnosticCategory.Error, key: "Destructuring declarations are not allowed in ambient contexts." }, + An_implementation_cannot_be_declared_in_ambient_contexts: { code: 1184, category: ts.DiagnosticCategory.Error, key: "An implementation cannot be declared in ambient contexts." }, + Modifiers_cannot_appear_here: { code: 1184, category: ts.DiagnosticCategory.Error, key: "Modifiers cannot appear here." }, + Merge_conflict_marker_encountered: { code: 1185, category: ts.DiagnosticCategory.Error, key: "Merge conflict marker encountered." }, + A_rest_element_cannot_have_an_initializer: { code: 1186, category: ts.DiagnosticCategory.Error, key: "A rest element cannot have an initializer." }, + A_parameter_property_may_not_be_a_binding_pattern: { code: 1187, category: ts.DiagnosticCategory.Error, key: "A parameter property may not be a binding pattern." }, + Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement: { code: 1188, category: ts.DiagnosticCategory.Error, key: "Only a single variable declaration is allowed in a 'for...of' statement." }, + The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer: { code: 1189, category: ts.DiagnosticCategory.Error, key: "The variable declaration of a 'for...in' statement cannot have an initializer." }, + The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer: { code: 1190, category: ts.DiagnosticCategory.Error, key: "The variable declaration of a 'for...of' statement cannot have an initializer." }, + An_import_declaration_cannot_have_modifiers: { code: 1191, category: ts.DiagnosticCategory.Error, key: "An import declaration cannot have modifiers." }, + External_module_0_has_no_default_export: { code: 1192, category: ts.DiagnosticCategory.Error, key: "External module '{0}' has no default export." }, + An_export_declaration_cannot_have_modifiers: { code: 1193, category: ts.DiagnosticCategory.Error, key: "An export declaration cannot have modifiers." }, + Export_declarations_are_not_permitted_in_an_internal_module: { code: 1194, category: ts.DiagnosticCategory.Error, key: "Export declarations are not permitted in an internal module." }, + Catch_clause_variable_name_must_be_an_identifier: { code: 1195, category: ts.DiagnosticCategory.Error, key: "Catch clause variable name must be an identifier." }, + Catch_clause_variable_cannot_have_a_type_annotation: { code: 1196, category: ts.DiagnosticCategory.Error, key: "Catch clause variable cannot have a type annotation." }, + Catch_clause_variable_cannot_have_an_initializer: { code: 1197, category: ts.DiagnosticCategory.Error, key: "Catch clause variable cannot have an initializer." }, + An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive: { code: 1198, category: ts.DiagnosticCategory.Error, key: "An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive." }, + Unterminated_Unicode_escape_sequence: { code: 1199, category: ts.DiagnosticCategory.Error, key: "Unterminated Unicode escape sequence." }, + Line_terminator_not_permitted_before_arrow: { code: 1200, category: ts.DiagnosticCategory.Error, key: "Line terminator not permitted before arrow." }, + Import_assignment_cannot_be_used_when_targeting_ECMAScript_6_or_higher_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_or_import_d_from_mod_instead: { code: 1202, category: ts.DiagnosticCategory.Error, key: "Import assignment cannot be used when targeting ECMAScript 6 or higher. Consider using 'import * as ns from \"mod\"', 'import {a} from \"mod\"' or 'import d from \"mod\"' instead." }, + Export_assignment_cannot_be_used_when_targeting_ECMAScript_6_or_higher_Consider_using_export_default_instead: { code: 1203, category: ts.DiagnosticCategory.Error, key: "Export assignment cannot be used when targeting ECMAScript 6 or higher. Consider using 'export default' instead." }, + Cannot_compile_external_modules_into_amd_commonjs_or_umd_when_targeting_ES6_or_higher: { code: 1204, category: ts.DiagnosticCategory.Error, key: "Cannot compile external modules into 'amd', 'commonjs' or 'umd' when targeting 'ES6' or higher." }, + Decorators_are_only_available_when_targeting_ECMAScript_5_and_higher: { code: 1205, category: ts.DiagnosticCategory.Error, key: "Decorators are only available when targeting ECMAScript 5 and higher." }, + Decorators_are_not_valid_here: { code: 1206, category: ts.DiagnosticCategory.Error, key: "Decorators are not valid here." }, + Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name: { code: 1207, category: ts.DiagnosticCategory.Error, key: "Decorators cannot be applied to multiple get/set accessors of the same name." }, + Cannot_compile_non_external_modules_when_the_separateCompilation_flag_is_provided: { code: 1208, category: ts.DiagnosticCategory.Error, key: "Cannot compile non-external modules when the '--separateCompilation' flag is provided." }, + Ambient_const_enums_are_not_allowed_when_the_separateCompilation_flag_is_provided: { code: 1209, category: ts.DiagnosticCategory.Error, key: "Ambient const enums are not allowed when the '--separateCompilation' flag is provided." }, + Invalid_use_of_0_Class_definitions_are_automatically_in_strict_mode: { code: 1210, category: ts.DiagnosticCategory.Error, key: "Invalid use of '{0}'. Class definitions are automatically in strict mode." }, + A_class_declaration_without_the_default_modifier_must_have_a_name: { code: 1211, category: ts.DiagnosticCategory.Error, key: "A class declaration without the 'default' modifier must have a name" }, + Identifier_expected_0_is_a_reserved_word_in_strict_mode: { code: 1212, category: ts.DiagnosticCategory.Error, key: "Identifier expected. '{0}' is a reserved word in strict mode" }, + Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode: { code: 1213, category: ts.DiagnosticCategory.Error, key: "Identifier expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode." }, + Identifier_expected_0_is_a_reserved_word_in_strict_mode_External_Module_is_automatically_in_strict_mode: { code: 1214, category: ts.DiagnosticCategory.Error, key: "Identifier expected. '{0}' is a reserved word in strict mode. External Module is automatically in strict mode." }, + Type_expected_0_is_a_reserved_word_in_strict_mode: { code: 1215, category: ts.DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode" }, + Type_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode: { code: 1216, category: ts.DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode." }, + Type_expected_0_is_a_reserved_word_in_strict_mode_Module_is_automatically_in_strict_mode: { code: 1217, category: ts.DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode. Module is automatically in strict mode." }, + Duplicate_identifier_0: { code: 2300, category: ts.DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, + Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: ts.DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, + Static_members_cannot_reference_class_type_parameters: { code: 2302, category: ts.DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, + Circular_definition_of_import_alias_0: { code: 2303, category: ts.DiagnosticCategory.Error, key: "Circular definition of import alias '{0}'." }, + Cannot_find_name_0: { code: 2304, category: ts.DiagnosticCategory.Error, key: "Cannot find name '{0}'." }, + Module_0_has_no_exported_member_1: { code: 2305, category: ts.DiagnosticCategory.Error, key: "Module '{0}' has no exported member '{1}'." }, + File_0_is_not_an_external_module: { code: 2306, category: ts.DiagnosticCategory.Error, key: "File '{0}' is not an external module." }, + Cannot_find_external_module_0: { code: 2307, category: ts.DiagnosticCategory.Error, key: "Cannot find external module '{0}'." }, + A_module_cannot_have_more_than_one_export_assignment: { code: 2308, category: ts.DiagnosticCategory.Error, key: "A module cannot have more than one export assignment." }, + An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements: { code: 2309, category: ts.DiagnosticCategory.Error, key: "An export assignment cannot be used in a module with other exported elements." }, + Type_0_recursively_references_itself_as_a_base_type: { code: 2310, category: ts.DiagnosticCategory.Error, key: "Type '{0}' recursively references itself as a base type." }, + A_class_may_only_extend_another_class: { code: 2311, category: ts.DiagnosticCategory.Error, key: "A class may only extend another class." }, + An_interface_may_only_extend_a_class_or_another_interface: { code: 2312, category: ts.DiagnosticCategory.Error, key: "An interface may only extend a class or another interface." }, + Constraint_of_a_type_parameter_cannot_reference_any_type_parameter_from_the_same_type_parameter_list: { code: 2313, category: ts.DiagnosticCategory.Error, key: "Constraint of a type parameter cannot reference any type parameter from the same type parameter list." }, + Generic_type_0_requires_1_type_argument_s: { code: 2314, category: ts.DiagnosticCategory.Error, key: "Generic type '{0}' requires {1} type argument(s)." }, + Type_0_is_not_generic: { code: 2315, category: ts.DiagnosticCategory.Error, key: "Type '{0}' is not generic." }, + Global_type_0_must_be_a_class_or_interface_type: { code: 2316, category: ts.DiagnosticCategory.Error, key: "Global type '{0}' must be a class or interface type." }, + Global_type_0_must_have_1_type_parameter_s: { code: 2317, category: ts.DiagnosticCategory.Error, key: "Global type '{0}' must have {1} type parameter(s)." }, + Cannot_find_global_type_0: { code: 2318, category: ts.DiagnosticCategory.Error, key: "Cannot find global type '{0}'." }, + Named_property_0_of_types_1_and_2_are_not_identical: { code: 2319, category: ts.DiagnosticCategory.Error, key: "Named property '{0}' of types '{1}' and '{2}' are not identical." }, + Interface_0_cannot_simultaneously_extend_types_1_and_2: { code: 2320, category: ts.DiagnosticCategory.Error, key: "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}'." }, + Excessive_stack_depth_comparing_types_0_and_1: { code: 2321, category: ts.DiagnosticCategory.Error, key: "Excessive stack depth comparing types '{0}' and '{1}'." }, + Type_0_is_not_assignable_to_type_1: { code: 2322, category: ts.DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}'." }, + Property_0_is_missing_in_type_1: { code: 2324, category: ts.DiagnosticCategory.Error, key: "Property '{0}' is missing in type '{1}'." }, + Property_0_is_private_in_type_1_but_not_in_type_2: { code: 2325, category: ts.DiagnosticCategory.Error, key: "Property '{0}' is private in type '{1}' but not in type '{2}'." }, + Types_of_property_0_are_incompatible: { code: 2326, category: ts.DiagnosticCategory.Error, key: "Types of property '{0}' are incompatible." }, + Property_0_is_optional_in_type_1_but_required_in_type_2: { code: 2327, category: ts.DiagnosticCategory.Error, key: "Property '{0}' is optional in type '{1}' but required in type '{2}'." }, + Types_of_parameters_0_and_1_are_incompatible: { code: 2328, category: ts.DiagnosticCategory.Error, key: "Types of parameters '{0}' and '{1}' are incompatible." }, + Index_signature_is_missing_in_type_0: { code: 2329, category: ts.DiagnosticCategory.Error, key: "Index signature is missing in type '{0}'." }, + Index_signatures_are_incompatible: { code: 2330, category: ts.DiagnosticCategory.Error, key: "Index signatures are incompatible." }, + this_cannot_be_referenced_in_a_module_body: { code: 2331, category: ts.DiagnosticCategory.Error, key: "'this' cannot be referenced in a module body." }, + this_cannot_be_referenced_in_current_location: { code: 2332, category: ts.DiagnosticCategory.Error, key: "'this' cannot be referenced in current location." }, + this_cannot_be_referenced_in_constructor_arguments: { code: 2333, category: ts.DiagnosticCategory.Error, key: "'this' cannot be referenced in constructor arguments." }, + this_cannot_be_referenced_in_a_static_property_initializer: { code: 2334, category: ts.DiagnosticCategory.Error, key: "'this' cannot be referenced in a static property initializer." }, + super_can_only_be_referenced_in_a_derived_class: { code: 2335, category: ts.DiagnosticCategory.Error, key: "'super' can only be referenced in a derived class." }, + super_cannot_be_referenced_in_constructor_arguments: { code: 2336, category: ts.DiagnosticCategory.Error, key: "'super' cannot be referenced in constructor arguments." }, + Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors: { code: 2337, category: ts.DiagnosticCategory.Error, key: "Super calls are not permitted outside constructors or in nested functions inside constructors" }, + super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class: { code: 2338, category: ts.DiagnosticCategory.Error, key: "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class" }, + Property_0_does_not_exist_on_type_1: { code: 2339, category: ts.DiagnosticCategory.Error, key: "Property '{0}' does not exist on type '{1}'." }, + Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword: { code: 2340, category: ts.DiagnosticCategory.Error, key: "Only public and protected methods of the base class are accessible via the 'super' keyword" }, + Property_0_is_private_and_only_accessible_within_class_1: { code: 2341, category: ts.DiagnosticCategory.Error, key: "Property '{0}' is private and only accessible within class '{1}'." }, + An_index_expression_argument_must_be_of_type_string_number_symbol_or_any: { code: 2342, category: ts.DiagnosticCategory.Error, key: "An index expression argument must be of type 'string', 'number', 'symbol, or 'any'." }, + Type_0_does_not_satisfy_the_constraint_1: { code: 2344, category: ts.DiagnosticCategory.Error, key: "Type '{0}' does not satisfy the constraint '{1}'." }, + Argument_of_type_0_is_not_assignable_to_parameter_of_type_1: { code: 2345, category: ts.DiagnosticCategory.Error, key: "Argument of type '{0}' is not assignable to parameter of type '{1}'." }, + Supplied_parameters_do_not_match_any_signature_of_call_target: { code: 2346, category: ts.DiagnosticCategory.Error, key: "Supplied parameters do not match any signature of call target." }, + Untyped_function_calls_may_not_accept_type_arguments: { code: 2347, category: ts.DiagnosticCategory.Error, key: "Untyped function calls may not accept type arguments." }, + Value_of_type_0_is_not_callable_Did_you_mean_to_include_new: { code: 2348, category: ts.DiagnosticCategory.Error, key: "Value of type '{0}' is not callable. Did you mean to include 'new'?" }, + Cannot_invoke_an_expression_whose_type_lacks_a_call_signature: { code: 2349, category: ts.DiagnosticCategory.Error, key: "Cannot invoke an expression whose type lacks a call signature." }, + Only_a_void_function_can_be_called_with_the_new_keyword: { code: 2350, category: ts.DiagnosticCategory.Error, key: "Only a void function can be called with the 'new' keyword." }, + Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature: { code: 2351, category: ts.DiagnosticCategory.Error, key: "Cannot use 'new' with an expression whose type lacks a call or construct signature." }, + Neither_type_0_nor_type_1_is_assignable_to_the_other: { code: 2352, category: ts.DiagnosticCategory.Error, key: "Neither type '{0}' nor type '{1}' is assignable to the other." }, + No_best_common_type_exists_among_return_expressions: { code: 2354, category: ts.DiagnosticCategory.Error, key: "No best common type exists among return expressions." }, + A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value_or_consist_of_a_single_throw_statement: { code: 2355, category: ts.DiagnosticCategory.Error, key: "A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement." }, + An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type: { code: 2356, category: ts.DiagnosticCategory.Error, key: "An arithmetic operand must be of type 'any', 'number' or an enum type." }, + The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_property_or_indexer: { code: 2357, category: ts.DiagnosticCategory.Error, key: "The operand of an increment or decrement operator must be a variable, property or indexer." }, + The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: { code: 2358, category: ts.DiagnosticCategory.Error, key: "The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter." }, + The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type: { code: 2359, category: ts.DiagnosticCategory.Error, key: "The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type." }, + The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol: { code: 2360, category: ts.DiagnosticCategory.Error, key: "The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'." }, + The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: { code: 2361, category: ts.DiagnosticCategory.Error, key: "The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter" }, + The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type: { code: 2362, category: ts.DiagnosticCategory.Error, key: "The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type." }, + The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type: { code: 2363, category: ts.DiagnosticCategory.Error, key: "The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type." }, + Invalid_left_hand_side_of_assignment_expression: { code: 2364, category: ts.DiagnosticCategory.Error, key: "Invalid left-hand side of assignment expression." }, + Operator_0_cannot_be_applied_to_types_1_and_2: { code: 2365, category: ts.DiagnosticCategory.Error, key: "Operator '{0}' cannot be applied to types '{1}' and '{2}'." }, + Type_parameter_name_cannot_be_0: { code: 2368, category: ts.DiagnosticCategory.Error, key: "Type parameter name cannot be '{0}'" }, + A_parameter_property_is_only_allowed_in_a_constructor_implementation: { code: 2369, category: ts.DiagnosticCategory.Error, key: "A parameter property is only allowed in a constructor implementation." }, + A_rest_parameter_must_be_of_an_array_type: { code: 2370, category: ts.DiagnosticCategory.Error, key: "A rest parameter must be of an array type." }, + A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation: { code: 2371, category: ts.DiagnosticCategory.Error, key: "A parameter initializer is only allowed in a function or constructor implementation." }, + Parameter_0_cannot_be_referenced_in_its_initializer: { code: 2372, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' cannot be referenced in its initializer." }, + Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it: { code: 2373, category: ts.DiagnosticCategory.Error, key: "Initializer of parameter '{0}' cannot reference identifier '{1}' declared after it." }, + Duplicate_string_index_signature: { code: 2374, category: ts.DiagnosticCategory.Error, key: "Duplicate string index signature." }, + Duplicate_number_index_signature: { code: 2375, category: ts.DiagnosticCategory.Error, key: "Duplicate number index signature." }, + A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties: { code: 2376, category: ts.DiagnosticCategory.Error, key: "A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties." }, + Constructors_for_derived_classes_must_contain_a_super_call: { code: 2377, category: ts.DiagnosticCategory.Error, key: "Constructors for derived classes must contain a 'super' call." }, + A_get_accessor_must_return_a_value_or_consist_of_a_single_throw_statement: { code: 2378, category: ts.DiagnosticCategory.Error, key: "A 'get' accessor must return a value or consist of a single 'throw' statement." }, + Getter_and_setter_accessors_do_not_agree_in_visibility: { code: 2379, category: ts.DiagnosticCategory.Error, key: "Getter and setter accessors do not agree in visibility." }, + get_and_set_accessor_must_have_the_same_type: { code: 2380, category: ts.DiagnosticCategory.Error, key: "'get' and 'set' accessor must have the same type." }, + A_signature_with_an_implementation_cannot_use_a_string_literal_type: { code: 2381, category: ts.DiagnosticCategory.Error, key: "A signature with an implementation cannot use a string literal type." }, + Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature: { code: 2382, category: ts.DiagnosticCategory.Error, key: "Specialized overload signature is not assignable to any non-specialized signature." }, + Overload_signatures_must_all_be_exported_or_not_exported: { code: 2383, category: ts.DiagnosticCategory.Error, key: "Overload signatures must all be exported or not exported." }, + Overload_signatures_must_all_be_ambient_or_non_ambient: { code: 2384, category: ts.DiagnosticCategory.Error, key: "Overload signatures must all be ambient or non-ambient." }, + Overload_signatures_must_all_be_public_private_or_protected: { code: 2385, category: ts.DiagnosticCategory.Error, key: "Overload signatures must all be public, private or protected." }, + Overload_signatures_must_all_be_optional_or_required: { code: 2386, category: ts.DiagnosticCategory.Error, key: "Overload signatures must all be optional or required." }, + Function_overload_must_be_static: { code: 2387, category: ts.DiagnosticCategory.Error, key: "Function overload must be static." }, + Function_overload_must_not_be_static: { code: 2388, category: ts.DiagnosticCategory.Error, key: "Function overload must not be static." }, + Function_implementation_name_must_be_0: { code: 2389, category: ts.DiagnosticCategory.Error, key: "Function implementation name must be '{0}'." }, + Constructor_implementation_is_missing: { code: 2390, category: ts.DiagnosticCategory.Error, key: "Constructor implementation is missing." }, + Function_implementation_is_missing_or_not_immediately_following_the_declaration: { code: 2391, category: ts.DiagnosticCategory.Error, key: "Function implementation is missing or not immediately following the declaration." }, + Multiple_constructor_implementations_are_not_allowed: { code: 2392, category: ts.DiagnosticCategory.Error, key: "Multiple constructor implementations are not allowed." }, + Duplicate_function_implementation: { code: 2393, category: ts.DiagnosticCategory.Error, key: "Duplicate function implementation." }, + Overload_signature_is_not_compatible_with_function_implementation: { code: 2394, category: ts.DiagnosticCategory.Error, key: "Overload signature is not compatible with function implementation." }, + Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local: { code: 2395, category: ts.DiagnosticCategory.Error, key: "Individual declarations in merged declaration {0} must be all exported or all local." }, + Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters: { code: 2396, category: ts.DiagnosticCategory.Error, key: "Duplicate identifier 'arguments'. Compiler uses 'arguments' to initialize rest parameters." }, + Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference: { code: 2399, category: ts.DiagnosticCategory.Error, key: "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference." }, + Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference: { code: 2400, category: ts.DiagnosticCategory.Error, key: "Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference." }, + Duplicate_identifier_super_Compiler_uses_super_to_capture_base_class_reference: { code: 2401, category: ts.DiagnosticCategory.Error, key: "Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference." }, + Expression_resolves_to_super_that_compiler_uses_to_capture_base_class_reference: { code: 2402, category: ts.DiagnosticCategory.Error, key: "Expression resolves to '_super' that compiler uses to capture base class reference." }, + Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2: { code: 2403, category: ts.DiagnosticCategory.Error, key: "Subsequent variable declarations must have the same type. Variable '{0}' must be of type '{1}', but here has type '{2}'." }, + The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation: { code: 2404, category: ts.DiagnosticCategory.Error, key: "The left-hand side of a 'for...in' statement cannot use a type annotation." }, + The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any: { code: 2405, category: ts.DiagnosticCategory.Error, key: "The left-hand side of a 'for...in' statement must be of type 'string' or 'any'." }, + Invalid_left_hand_side_in_for_in_statement: { code: 2406, category: ts.DiagnosticCategory.Error, key: "Invalid left-hand side in 'for...in' statement." }, + The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter: { code: 2407, category: ts.DiagnosticCategory.Error, key: "The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter." }, + Setters_cannot_return_a_value: { code: 2408, category: ts.DiagnosticCategory.Error, key: "Setters cannot return a value." }, + Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class: { code: 2409, category: ts.DiagnosticCategory.Error, key: "Return type of constructor signature must be assignable to the instance type of the class" }, + All_symbols_within_a_with_block_will_be_resolved_to_any: { code: 2410, category: ts.DiagnosticCategory.Error, key: "All symbols within a 'with' block will be resolved to 'any'." }, + Property_0_of_type_1_is_not_assignable_to_string_index_type_2: { code: 2411, category: ts.DiagnosticCategory.Error, key: "Property '{0}' of type '{1}' is not assignable to string index type '{2}'." }, + Property_0_of_type_1_is_not_assignable_to_numeric_index_type_2: { code: 2412, category: ts.DiagnosticCategory.Error, key: "Property '{0}' of type '{1}' is not assignable to numeric index type '{2}'." }, + Numeric_index_type_0_is_not_assignable_to_string_index_type_1: { code: 2413, category: ts.DiagnosticCategory.Error, key: "Numeric index type '{0}' is not assignable to string index type '{1}'." }, + Class_name_cannot_be_0: { code: 2414, category: ts.DiagnosticCategory.Error, key: "Class name cannot be '{0}'" }, + Class_0_incorrectly_extends_base_class_1: { code: 2415, category: ts.DiagnosticCategory.Error, key: "Class '{0}' incorrectly extends base class '{1}'." }, + Class_static_side_0_incorrectly_extends_base_class_static_side_1: { code: 2417, category: ts.DiagnosticCategory.Error, key: "Class static side '{0}' incorrectly extends base class static side '{1}'." }, + Type_name_0_in_extends_clause_does_not_reference_constructor_function_for_0: { code: 2419, category: ts.DiagnosticCategory.Error, key: "Type name '{0}' in extends clause does not reference constructor function for '{0}'." }, + Class_0_incorrectly_implements_interface_1: { code: 2420, category: ts.DiagnosticCategory.Error, key: "Class '{0}' incorrectly implements interface '{1}'." }, + A_class_may_only_implement_another_class_or_interface: { code: 2422, category: ts.DiagnosticCategory.Error, key: "A class may only implement another class or interface." }, + Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor: { code: 2423, category: ts.DiagnosticCategory.Error, key: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member accessor." }, + Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property: { code: 2424, category: ts.DiagnosticCategory.Error, key: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member property." }, + Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function: { code: 2425, category: ts.DiagnosticCategory.Error, key: "Class '{0}' defines instance member property '{1}', but extended class '{2}' defines it as instance member function." }, + Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function: { code: 2426, category: ts.DiagnosticCategory.Error, key: "Class '{0}' defines instance member accessor '{1}', but extended class '{2}' defines it as instance member function." }, + Interface_name_cannot_be_0: { code: 2427, category: ts.DiagnosticCategory.Error, key: "Interface name cannot be '{0}'" }, + All_declarations_of_an_interface_must_have_identical_type_parameters: { code: 2428, category: ts.DiagnosticCategory.Error, key: "All declarations of an interface must have identical type parameters." }, + Interface_0_incorrectly_extends_interface_1: { code: 2430, category: ts.DiagnosticCategory.Error, key: "Interface '{0}' incorrectly extends interface '{1}'." }, + Enum_name_cannot_be_0: { code: 2431, category: ts.DiagnosticCategory.Error, key: "Enum name cannot be '{0}'" }, + In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element: { code: 2432, category: ts.DiagnosticCategory.Error, key: "In an enum with multiple declarations, only one declaration can omit an initializer for its first enum element." }, + A_module_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged: { code: 2433, category: ts.DiagnosticCategory.Error, key: "A module declaration cannot be in a different file from a class or function with which it is merged" }, + A_module_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged: { code: 2434, category: ts.DiagnosticCategory.Error, key: "A module declaration cannot be located prior to a class or function with which it is merged" }, + Ambient_external_modules_cannot_be_nested_in_other_modules: { code: 2435, category: ts.DiagnosticCategory.Error, key: "Ambient external modules cannot be nested in other modules." }, + Ambient_external_module_declaration_cannot_specify_relative_module_name: { code: 2436, category: ts.DiagnosticCategory.Error, key: "Ambient external module declaration cannot specify relative module name." }, + Module_0_is_hidden_by_a_local_declaration_with_the_same_name: { code: 2437, category: ts.DiagnosticCategory.Error, key: "Module '{0}' is hidden by a local declaration with the same name" }, + Import_name_cannot_be_0: { code: 2438, category: ts.DiagnosticCategory.Error, key: "Import name cannot be '{0}'" }, + Import_or_export_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name: { code: 2439, category: ts.DiagnosticCategory.Error, key: "Import or export declaration in an ambient external module declaration cannot reference external module through relative external module name." }, + Import_declaration_conflicts_with_local_declaration_of_0: { code: 2440, category: ts.DiagnosticCategory.Error, key: "Import declaration conflicts with local declaration of '{0}'" }, + Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_an_external_module: { code: 2441, category: ts.DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of an external module." }, + Types_have_separate_declarations_of_a_private_property_0: { code: 2442, category: ts.DiagnosticCategory.Error, key: "Types have separate declarations of a private property '{0}'." }, + Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2: { code: 2443, category: ts.DiagnosticCategory.Error, key: "Property '{0}' is protected but type '{1}' is not a class derived from '{2}'." }, + Property_0_is_protected_in_type_1_but_public_in_type_2: { code: 2444, category: ts.DiagnosticCategory.Error, key: "Property '{0}' is protected in type '{1}' but public in type '{2}'." }, + Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses: { code: 2445, category: ts.DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible within class '{1}' and its subclasses." }, + Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1: { code: 2446, category: ts.DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible through an instance of class '{1}'." }, + The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead: { code: 2447, category: ts.DiagnosticCategory.Error, key: "The '{0}' operator is not allowed for boolean types. Consider using '{1}' instead." }, + Block_scoped_variable_0_used_before_its_declaration: { code: 2448, category: ts.DiagnosticCategory.Error, key: "Block-scoped variable '{0}' used before its declaration." }, + The_operand_of_an_increment_or_decrement_operator_cannot_be_a_constant: { code: 2449, category: ts.DiagnosticCategory.Error, key: "The operand of an increment or decrement operator cannot be a constant." }, + Left_hand_side_of_assignment_expression_cannot_be_a_constant: { code: 2450, category: ts.DiagnosticCategory.Error, key: "Left-hand side of assignment expression cannot be a constant." }, + Cannot_redeclare_block_scoped_variable_0: { code: 2451, category: ts.DiagnosticCategory.Error, key: "Cannot redeclare block-scoped variable '{0}'." }, + An_enum_member_cannot_have_a_numeric_name: { code: 2452, category: ts.DiagnosticCategory.Error, key: "An enum member cannot have a numeric name." }, + The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly: { code: 2453, category: ts.DiagnosticCategory.Error, key: "The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly." }, + Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0: { code: 2455, category: ts.DiagnosticCategory.Error, key: "Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'." }, + Type_alias_0_circularly_references_itself: { code: 2456, category: ts.DiagnosticCategory.Error, key: "Type alias '{0}' circularly references itself." }, + Type_alias_name_cannot_be_0: { code: 2457, category: ts.DiagnosticCategory.Error, key: "Type alias name cannot be '{0}'" }, + An_AMD_module_cannot_have_multiple_name_assignments: { code: 2458, category: ts.DiagnosticCategory.Error, key: "An AMD module cannot have multiple name assignments." }, + Type_0_has_no_property_1_and_no_string_index_signature: { code: 2459, category: ts.DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}' and no string index signature." }, + Type_0_has_no_property_1: { code: 2460, category: ts.DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}'." }, + Type_0_is_not_an_array_type: { code: 2461, category: ts.DiagnosticCategory.Error, key: "Type '{0}' is not an array type." }, + A_rest_element_must_be_last_in_an_array_destructuring_pattern: { code: 2462, category: ts.DiagnosticCategory.Error, key: "A rest element must be last in an array destructuring pattern" }, + A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature: { code: 2463, category: ts.DiagnosticCategory.Error, key: "A binding pattern parameter cannot be optional in an implementation signature." }, + A_computed_property_name_must_be_of_type_string_number_symbol_or_any: { code: 2464, category: ts.DiagnosticCategory.Error, key: "A computed property name must be of type 'string', 'number', 'symbol', or 'any'." }, + this_cannot_be_referenced_in_a_computed_property_name: { code: 2465, category: ts.DiagnosticCategory.Error, key: "'this' cannot be referenced in a computed property name." }, + super_cannot_be_referenced_in_a_computed_property_name: { code: 2466, category: ts.DiagnosticCategory.Error, key: "'super' cannot be referenced in a computed property name." }, + A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type: { code: 2467, category: ts.DiagnosticCategory.Error, key: "A computed property name cannot reference a type parameter from its containing type." }, + Cannot_find_global_value_0: { code: 2468, category: ts.DiagnosticCategory.Error, key: "Cannot find global value '{0}'." }, + The_0_operator_cannot_be_applied_to_type_symbol: { code: 2469, category: ts.DiagnosticCategory.Error, key: "The '{0}' operator cannot be applied to type 'symbol'." }, + Symbol_reference_does_not_refer_to_the_global_Symbol_constructor_object: { code: 2470, category: ts.DiagnosticCategory.Error, key: "'Symbol' reference does not refer to the global Symbol constructor object." }, + A_computed_property_name_of_the_form_0_must_be_of_type_symbol: { code: 2471, category: ts.DiagnosticCategory.Error, key: "A computed property name of the form '{0}' must be of type 'symbol'." }, + Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_6_and_higher: { code: 2472, category: ts.DiagnosticCategory.Error, key: "Spread operator in 'new' expressions is only available when targeting ECMAScript 6 and higher." }, + Enum_declarations_must_all_be_const_or_non_const: { code: 2473, category: ts.DiagnosticCategory.Error, key: "Enum declarations must all be const or non-const." }, + In_const_enum_declarations_member_initializer_must_be_constant_expression: { code: 2474, category: ts.DiagnosticCategory.Error, key: "In 'const' enum declarations member initializer must be constant expression." }, + const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment: { code: 2475, category: ts.DiagnosticCategory.Error, key: "'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment." }, + A_const_enum_member_can_only_be_accessed_using_a_string_literal: { code: 2476, category: ts.DiagnosticCategory.Error, key: "A const enum member can only be accessed using a string literal." }, + const_enum_member_initializer_was_evaluated_to_a_non_finite_value: { code: 2477, category: ts.DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to a non-finite value." }, + const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN: { code: 2478, category: ts.DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to disallowed value 'NaN'." }, + Property_0_does_not_exist_on_const_enum_1: { code: 2479, category: ts.DiagnosticCategory.Error, key: "Property '{0}' does not exist on 'const' enum '{1}'." }, + let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations: { code: 2480, category: ts.DiagnosticCategory.Error, key: "'let' is not allowed to be used as a name in 'let' or 'const' declarations." }, + Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1: { code: 2481, category: ts.DiagnosticCategory.Error, key: "Cannot initialize outer scoped variable '{0}' in the same scope as block scoped declaration '{1}'." }, + The_left_hand_side_of_a_for_of_statement_cannot_use_a_type_annotation: { code: 2483, category: ts.DiagnosticCategory.Error, key: "The left-hand side of a 'for...of' statement cannot use a type annotation." }, + Export_declaration_conflicts_with_exported_declaration_of_0: { code: 2484, category: ts.DiagnosticCategory.Error, key: "Export declaration conflicts with exported declaration of '{0}'" }, + The_left_hand_side_of_a_for_of_statement_cannot_be_a_previously_defined_constant: { code: 2485, category: ts.DiagnosticCategory.Error, key: "The left-hand side of a 'for...of' statement cannot be a previously defined constant." }, + The_left_hand_side_of_a_for_in_statement_cannot_be_a_previously_defined_constant: { code: 2486, category: ts.DiagnosticCategory.Error, key: "The left-hand side of a 'for...in' statement cannot be a previously defined constant." }, + Invalid_left_hand_side_in_for_of_statement: { code: 2487, category: ts.DiagnosticCategory.Error, key: "Invalid left-hand side in 'for...of' statement." }, + Type_must_have_a_Symbol_iterator_method_that_returns_an_iterator: { code: 2488, category: ts.DiagnosticCategory.Error, key: "Type must have a '[Symbol.iterator]()' method that returns an iterator." }, + An_iterator_must_have_a_next_method: { code: 2489, category: ts.DiagnosticCategory.Error, key: "An iterator must have a 'next()' method." }, + The_type_returned_by_the_next_method_of_an_iterator_must_have_a_value_property: { code: 2490, category: ts.DiagnosticCategory.Error, key: "The type returned by the 'next()' method of an iterator must have a 'value' property." }, + The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern: { code: 2491, category: ts.DiagnosticCategory.Error, key: "The left-hand side of a 'for...in' statement cannot be a destructuring pattern." }, + Cannot_redeclare_identifier_0_in_catch_clause: { code: 2492, category: ts.DiagnosticCategory.Error, key: "Cannot redeclare identifier '{0}' in catch clause" }, + Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2: { code: 2493, category: ts.DiagnosticCategory.Error, key: "Tuple type '{0}' with length '{1}' cannot be assigned to tuple with length '{2}'." }, + Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher: { code: 2494, category: ts.DiagnosticCategory.Error, key: "Using a string in a 'for...of' statement is only supported in ECMAScript 5 and higher." }, + Type_0_is_not_an_array_type_or_a_string_type: { code: 2495, category: ts.DiagnosticCategory.Error, key: "Type '{0}' is not an array type or a string type." }, + The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression: { code: 2496, category: ts.DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an arrow function in ES3 and ES5. Consider using a standard function expression." }, + External_module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct: { code: 2497, category: ts.DiagnosticCategory.Error, key: "External module '{0}' resolves to a non-module entity and cannot be imported using this construct." }, + External_module_0_uses_export_and_cannot_be_used_with_export_Asterisk: { code: 2498, category: ts.DiagnosticCategory.Error, key: "External module '{0}' uses 'export =' and cannot be used with 'export *'." }, + An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments: { code: 2499, category: ts.DiagnosticCategory.Error, key: "An interface can only extend an identifier/qualified-name with optional type arguments." }, + A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments: { code: 2500, category: ts.DiagnosticCategory.Error, key: "A class can only implement an identifier/qualified-name with optional type arguments." }, + A_rest_element_cannot_contain_a_binding_pattern: { code: 2501, category: ts.DiagnosticCategory.Error, key: "A rest element cannot contain a binding pattern." }, + Import_declaration_0_is_using_private_name_1: { code: 4000, category: ts.DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." }, + Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: ts.DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." }, + Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: ts.DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." }, + Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 4006, category: ts.DiagnosticCategory.Error, key: "Type parameter '{0}' of constructor signature from exported interface has or is using private name '{1}'." }, + Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 4008, category: ts.DiagnosticCategory.Error, key: "Type parameter '{0}' of call signature from exported interface has or is using private name '{1}'." }, + Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1: { code: 4010, category: ts.DiagnosticCategory.Error, key: "Type parameter '{0}' of public static method from exported class has or is using private name '{1}'." }, + Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1: { code: 4012, category: ts.DiagnosticCategory.Error, key: "Type parameter '{0}' of public method from exported class has or is using private name '{1}'." }, + Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1: { code: 4014, category: ts.DiagnosticCategory.Error, key: "Type parameter '{0}' of method from exported interface has or is using private name '{1}'." }, + Type_parameter_0_of_exported_function_has_or_is_using_private_name_1: { code: 4016, category: ts.DiagnosticCategory.Error, key: "Type parameter '{0}' of exported function has or is using private name '{1}'." }, + Implements_clause_of_exported_class_0_has_or_is_using_private_name_1: { code: 4019, category: ts.DiagnosticCategory.Error, key: "Implements clause of exported class '{0}' has or is using private name '{1}'." }, + Extends_clause_of_exported_class_0_has_or_is_using_private_name_1: { code: 4020, category: ts.DiagnosticCategory.Error, key: "Extends clause of exported class '{0}' has or is using private name '{1}'." }, + Extends_clause_of_exported_interface_0_has_or_is_using_private_name_1: { code: 4022, category: ts.DiagnosticCategory.Error, key: "Extends clause of exported interface '{0}' has or is using private name '{1}'." }, + Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4023, category: ts.DiagnosticCategory.Error, key: "Exported variable '{0}' has or is using name '{1}' from external module {2} but cannot be named." }, + Exported_variable_0_has_or_is_using_name_1_from_private_module_2: { code: 4024, category: ts.DiagnosticCategory.Error, key: "Exported variable '{0}' has or is using name '{1}' from private module '{2}'." }, + Exported_variable_0_has_or_is_using_private_name_1: { code: 4025, category: ts.DiagnosticCategory.Error, key: "Exported variable '{0}' has or is using private name '{1}'." }, + Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4026, category: ts.DiagnosticCategory.Error, key: "Public static property '{0}' of exported class has or is using name '{1}' from external module {2} but cannot be named." }, + Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4027, category: ts.DiagnosticCategory.Error, key: "Public static property '{0}' of exported class has or is using name '{1}' from private module '{2}'." }, + Public_static_property_0_of_exported_class_has_or_is_using_private_name_1: { code: 4028, category: ts.DiagnosticCategory.Error, key: "Public static property '{0}' of exported class has or is using private name '{1}'." }, + Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4029, category: ts.DiagnosticCategory.Error, key: "Public property '{0}' of exported class has or is using name '{1}' from external module {2} but cannot be named." }, + Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4030, category: ts.DiagnosticCategory.Error, key: "Public property '{0}' of exported class has or is using name '{1}' from private module '{2}'." }, + Public_property_0_of_exported_class_has_or_is_using_private_name_1: { code: 4031, category: ts.DiagnosticCategory.Error, key: "Public property '{0}' of exported class has or is using private name '{1}'." }, + Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4032, category: ts.DiagnosticCategory.Error, key: "Property '{0}' of exported interface has or is using name '{1}' from private module '{2}'." }, + Property_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4033, category: ts.DiagnosticCategory.Error, key: "Property '{0}' of exported interface has or is using private name '{1}'." }, + Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4034, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of public static property setter from exported class has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1: { code: 4035, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of public static property setter from exported class has or is using private name '{1}'." }, + Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4036, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of public property setter from exported class has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_name_1: { code: 4037, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of public property setter from exported class has or is using private name '{1}'." }, + Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named: { code: 4038, category: ts.DiagnosticCategory.Error, key: "Return type of public static property getter from exported class has or is using name '{0}' from external module {1} but cannot be named." }, + Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1: { code: 4039, category: ts.DiagnosticCategory.Error, key: "Return type of public static property getter from exported class has or is using name '{0}' from private module '{1}'." }, + Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_name_0: { code: 4040, category: ts.DiagnosticCategory.Error, key: "Return type of public static property getter from exported class has or is using private name '{0}'." }, + Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named: { code: 4041, category: ts.DiagnosticCategory.Error, key: "Return type of public property getter from exported class has or is using name '{0}' from external module {1} but cannot be named." }, + Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1: { code: 4042, category: ts.DiagnosticCategory.Error, key: "Return type of public property getter from exported class has or is using name '{0}' from private module '{1}'." }, + Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_name_0: { code: 4043, category: ts.DiagnosticCategory.Error, key: "Return type of public property getter from exported class has or is using private name '{0}'." }, + Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1: { code: 4044, category: ts.DiagnosticCategory.Error, key: "Return type of constructor signature from exported interface has or is using name '{0}' from private module '{1}'." }, + Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0: { code: 4045, category: ts.DiagnosticCategory.Error, key: "Return type of constructor signature from exported interface has or is using private name '{0}'." }, + Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1: { code: 4046, category: ts.DiagnosticCategory.Error, key: "Return type of call signature from exported interface has or is using name '{0}' from private module '{1}'." }, + Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0: { code: 4047, category: ts.DiagnosticCategory.Error, key: "Return type of call signature from exported interface has or is using private name '{0}'." }, + Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1: { code: 4048, category: ts.DiagnosticCategory.Error, key: "Return type of index signature from exported interface has or is using name '{0}' from private module '{1}'." }, + Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0: { code: 4049, category: ts.DiagnosticCategory.Error, key: "Return type of index signature from exported interface has or is using private name '{0}'." }, + Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named: { code: 4050, category: ts.DiagnosticCategory.Error, key: "Return type of public static method from exported class has or is using name '{0}' from external module {1} but cannot be named." }, + Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1: { code: 4051, category: ts.DiagnosticCategory.Error, key: "Return type of public static method from exported class has or is using name '{0}' from private module '{1}'." }, + Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0: { code: 4052, category: ts.DiagnosticCategory.Error, key: "Return type of public static method from exported class has or is using private name '{0}'." }, + Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named: { code: 4053, category: ts.DiagnosticCategory.Error, key: "Return type of public method from exported class has or is using name '{0}' from external module {1} but cannot be named." }, + Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1: { code: 4054, category: ts.DiagnosticCategory.Error, key: "Return type of public method from exported class has or is using name '{0}' from private module '{1}'." }, + Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0: { code: 4055, category: ts.DiagnosticCategory.Error, key: "Return type of public method from exported class has or is using private name '{0}'." }, + Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1: { code: 4056, category: ts.DiagnosticCategory.Error, key: "Return type of method from exported interface has or is using name '{0}' from private module '{1}'." }, + Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0: { code: 4057, category: ts.DiagnosticCategory.Error, key: "Return type of method from exported interface has or is using private name '{0}'." }, + Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named: { code: 4058, category: ts.DiagnosticCategory.Error, key: "Return type of exported function has or is using name '{0}' from external module {1} but cannot be named." }, + Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1: { code: 4059, category: ts.DiagnosticCategory.Error, key: "Return type of exported function has or is using name '{0}' from private module '{1}'." }, + Return_type_of_exported_function_has_or_is_using_private_name_0: { code: 4060, category: ts.DiagnosticCategory.Error, key: "Return type of exported function has or is using private name '{0}'." }, + Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4061, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of constructor from exported class has or is using name '{1}' from external module {2} but cannot be named." }, + Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4062, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of constructor from exported class has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1: { code: 4063, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of constructor from exported class has or is using private name '{1}'." }, + Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4064, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of constructor signature from exported interface has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 4065, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of constructor signature from exported interface has or is using private name '{1}'." }, + Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4066, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of call signature from exported interface has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 4067, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of call signature from exported interface has or is using private name '{1}'." }, + Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4068, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of public static method from exported class has or is using name '{1}' from external module {2} but cannot be named." }, + Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4069, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of public static method from exported class has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1: { code: 4070, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of public static method from exported class has or is using private name '{1}'." }, + Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4071, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of public method from exported class has or is using name '{1}' from external module {2} but cannot be named." }, + Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4072, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of public method from exported class has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1: { code: 4073, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of public method from exported class has or is using private name '{1}'." }, + Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4074, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of method from exported interface has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1: { code: 4075, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of method from exported interface has or is using private name '{1}'." }, + Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4076, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from external module {2} but cannot be named." }, + Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2: { code: 4077, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_exported_function_has_or_is_using_private_name_1: { code: 4078, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using private name '{1}'." }, + Exported_type_alias_0_has_or_is_using_private_name_1: { code: 4081, category: ts.DiagnosticCategory.Error, key: "Exported type alias '{0}' has or is using private name '{1}'." }, + Default_export_of_the_module_has_or_is_using_private_name_0: { code: 4082, category: ts.DiagnosticCategory.Error, key: "Default export of the module has or is using private name '{0}'." }, + Loop_contains_block_scoped_variable_0_referenced_by_a_function_in_the_loop_This_is_only_supported_in_ECMAScript_6_or_higher: { code: 4091, category: ts.DiagnosticCategory.Error, key: "Loop contains block-scoped variable '{0}' referenced by a function in the loop. This is only supported in ECMAScript 6 or higher." }, + The_current_host_does_not_support_the_0_option: { code: 5001, category: ts.DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." }, + Cannot_find_the_common_subdirectory_path_for_the_input_files: { code: 5009, category: ts.DiagnosticCategory.Error, key: "Cannot find the common subdirectory path for the input files." }, + Cannot_read_file_0_Colon_1: { code: 5012, category: ts.DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" }, + Unsupported_file_encoding: { code: 5013, category: ts.DiagnosticCategory.Error, key: "Unsupported file encoding." }, + Failed_to_parse_file_0_Colon_1: { code: 5014, category: ts.DiagnosticCategory.Error, key: "Failed to parse file '{0}': {1}." }, + Unknown_compiler_option_0: { code: 5023, category: ts.DiagnosticCategory.Error, key: "Unknown compiler option '{0}'." }, + Compiler_option_0_requires_a_value_of_type_1: { code: 5024, category: ts.DiagnosticCategory.Error, key: "Compiler option '{0}' requires a value of type {1}." }, + Could_not_write_file_0_Colon_1: { code: 5033, category: ts.DiagnosticCategory.Error, key: "Could not write file '{0}': {1}" }, + Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option: { code: 5038, category: ts.DiagnosticCategory.Error, key: "Option 'mapRoot' cannot be specified without specifying 'sourcemap' option." }, + Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option: { code: 5039, category: ts.DiagnosticCategory.Error, key: "Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option." }, + Option_noEmit_cannot_be_specified_with_option_out_or_outDir: { code: 5040, category: ts.DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'out' or 'outDir'." }, + Option_noEmit_cannot_be_specified_with_option_declaration: { code: 5041, category: ts.DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'declaration'." }, + Option_project_cannot_be_mixed_with_source_files_on_a_command_line: { code: 5042, category: ts.DiagnosticCategory.Error, key: "Option 'project' cannot be mixed with source files on a command line." }, + Option_sourceMap_cannot_be_specified_with_option_separateCompilation: { code: 5043, category: ts.DiagnosticCategory.Error, key: "Option 'sourceMap' cannot be specified with option 'separateCompilation'." }, + Option_declaration_cannot_be_specified_with_option_separateCompilation: { code: 5044, category: ts.DiagnosticCategory.Error, key: "Option 'declaration' cannot be specified with option 'separateCompilation'." }, + Option_noEmitOnError_cannot_be_specified_with_option_separateCompilation: { code: 5045, category: ts.DiagnosticCategory.Error, key: "Option 'noEmitOnError' cannot be specified with option 'separateCompilation'." }, + Option_out_cannot_be_specified_with_option_separateCompilation: { code: 5046, category: ts.DiagnosticCategory.Error, key: "Option 'out' cannot be specified with option 'separateCompilation'." }, + Option_separateCompilation_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES6_or_higher: { code: 5047, category: ts.DiagnosticCategory.Error, key: "Option 'separateCompilation' can only be used when either option'--module' is provided or option 'target' is 'ES6' or higher." }, + Concatenate_and_emit_output_to_single_file: { code: 6001, category: ts.DiagnosticCategory.Message, key: "Concatenate and emit output to single file." }, + Generates_corresponding_d_ts_file: { code: 6002, category: ts.DiagnosticCategory.Message, key: "Generates corresponding '.d.ts' file." }, + Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations: { code: 6003, category: ts.DiagnosticCategory.Message, key: "Specifies the location where debugger should locate map files instead of generated locations." }, + Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations: { code: 6004, category: ts.DiagnosticCategory.Message, key: "Specifies the location where debugger should locate TypeScript files instead of source locations." }, + Watch_input_files: { code: 6005, category: ts.DiagnosticCategory.Message, key: "Watch input files." }, + Redirect_output_structure_to_the_directory: { code: 6006, category: ts.DiagnosticCategory.Message, key: "Redirect output structure to the directory." }, + Do_not_erase_const_enum_declarations_in_generated_code: { code: 6007, category: ts.DiagnosticCategory.Message, key: "Do not erase const enum declarations in generated code." }, + Do_not_emit_outputs_if_any_type_checking_errors_were_reported: { code: 6008, category: ts.DiagnosticCategory.Message, key: "Do not emit outputs if any type checking errors were reported." }, + Do_not_emit_comments_to_output: { code: 6009, category: ts.DiagnosticCategory.Message, key: "Do not emit comments to output." }, + Do_not_emit_outputs: { code: 6010, category: ts.DiagnosticCategory.Message, key: "Do not emit outputs." }, + Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES6_experimental: { code: 6015, category: ts.DiagnosticCategory.Message, key: "Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES6' (experimental)" }, + Specify_module_code_generation_Colon_commonjs_amd_or_umd: { code: 6016, category: ts.DiagnosticCategory.Message, key: "Specify module code generation: 'commonjs', 'amd', or 'umd'." }, + Print_this_message: { code: 6017, category: ts.DiagnosticCategory.Message, key: "Print this message." }, + Print_the_compiler_s_version: { code: 6019, category: ts.DiagnosticCategory.Message, key: "Print the compiler's version." }, + Compile_the_project_in_the_given_directory: { code: 6020, category: ts.DiagnosticCategory.Message, key: "Compile the project in the given directory." }, + Syntax_Colon_0: { code: 6023, category: ts.DiagnosticCategory.Message, key: "Syntax: {0}" }, + options: { code: 6024, category: ts.DiagnosticCategory.Message, key: "options" }, + file: { code: 6025, category: ts.DiagnosticCategory.Message, key: "file" }, + Examples_Colon_0: { code: 6026, category: ts.DiagnosticCategory.Message, key: "Examples: {0}" }, + Options_Colon: { code: 6027, category: ts.DiagnosticCategory.Message, key: "Options:" }, + Version_0: { code: 6029, category: ts.DiagnosticCategory.Message, key: "Version {0}" }, + Insert_command_line_options_and_files_from_a_file: { code: 6030, category: ts.DiagnosticCategory.Message, key: "Insert command line options and files from a file." }, + File_change_detected_Starting_incremental_compilation: { code: 6032, category: ts.DiagnosticCategory.Message, key: "File change detected. Starting incremental compilation..." }, + KIND: { code: 6034, category: ts.DiagnosticCategory.Message, key: "KIND" }, + FILE: { code: 6035, category: ts.DiagnosticCategory.Message, key: "FILE" }, + VERSION: { code: 6036, category: ts.DiagnosticCategory.Message, key: "VERSION" }, + LOCATION: { code: 6037, category: ts.DiagnosticCategory.Message, key: "LOCATION" }, + DIRECTORY: { code: 6038, category: ts.DiagnosticCategory.Message, key: "DIRECTORY" }, + Compilation_complete_Watching_for_file_changes: { code: 6042, category: ts.DiagnosticCategory.Message, key: "Compilation complete. Watching for file changes." }, + Generates_corresponding_map_file: { code: 6043, category: ts.DiagnosticCategory.Message, key: "Generates corresponding '.map' file." }, + Compiler_option_0_expects_an_argument: { code: 6044, category: ts.DiagnosticCategory.Error, key: "Compiler option '{0}' expects an argument." }, + Unterminated_quoted_string_in_response_file_0: { code: 6045, category: ts.DiagnosticCategory.Error, key: "Unterminated quoted string in response file '{0}'." }, + Argument_for_module_option_must_be_commonjs_amd_or_umd: { code: 6046, category: ts.DiagnosticCategory.Error, key: "Argument for '--module' option must be 'commonjs', 'amd', or 'umd'." }, + Argument_for_target_option_must_be_ES3_ES5_or_ES6: { code: 6047, category: ts.DiagnosticCategory.Error, key: "Argument for '--target' option must be 'ES3', 'ES5', or 'ES6'." }, + Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1: { code: 6048, category: ts.DiagnosticCategory.Error, key: "Locale must be of the form or -. For example '{0}' or '{1}'." }, + Unsupported_locale_0: { code: 6049, category: ts.DiagnosticCategory.Error, key: "Unsupported locale '{0}'." }, + Unable_to_open_file_0: { code: 6050, category: ts.DiagnosticCategory.Error, key: "Unable to open file '{0}'." }, + Corrupted_locale_file_0: { code: 6051, category: ts.DiagnosticCategory.Error, key: "Corrupted locale file {0}." }, + Raise_error_on_expressions_and_declarations_with_an_implied_any_type: { code: 6052, category: ts.DiagnosticCategory.Message, key: "Raise error on expressions and declarations with an implied 'any' type." }, + File_0_not_found: { code: 6053, category: ts.DiagnosticCategory.Error, key: "File '{0}' not found." }, + File_0_must_have_extension_ts_or_d_ts: { code: 6054, category: ts.DiagnosticCategory.Error, key: "File '{0}' must have extension '.ts' or '.d.ts'." }, + Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures: { code: 6055, category: ts.DiagnosticCategory.Message, key: "Suppress noImplicitAny errors for indexing objects lacking index signatures." }, + Do_not_emit_declarations_for_code_that_has_an_internal_annotation: { code: 6056, category: ts.DiagnosticCategory.Message, key: "Do not emit declarations for code that has an '@internal' annotation." }, + Preserve_new_lines_when_emitting_code: { code: 6057, category: ts.DiagnosticCategory.Message, key: "Preserve new-lines when emitting code." }, + Specifies_the_root_directory_of_input_files_Use_to_control_the_output_directory_structure_with_outDir: { code: 6058, category: ts.DiagnosticCategory.Message, key: "Specifies the root directory of input files. Use to control the output directory structure with --outDir." }, + File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files: { code: 6059, category: ts.DiagnosticCategory.Error, key: "File '{0}' is not under 'rootDir' '{1}'. 'rootDir' is expected to contain all source files." }, + Variable_0_implicitly_has_an_1_type: { code: 7005, category: ts.DiagnosticCategory.Error, key: "Variable '{0}' implicitly has an '{1}' type." }, + Parameter_0_implicitly_has_an_1_type: { code: 7006, category: ts.DiagnosticCategory.Error, key: "Parameter '{0}' implicitly has an '{1}' type." }, + Member_0_implicitly_has_an_1_type: { code: 7008, category: ts.DiagnosticCategory.Error, key: "Member '{0}' implicitly has an '{1}' type." }, + new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type: { code: 7009, category: ts.DiagnosticCategory.Error, key: "'new' expression, whose target lacks a construct signature, implicitly has an 'any' type." }, + _0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type: { code: 7010, category: ts.DiagnosticCategory.Error, key: "'{0}', which lacks return-type annotation, implicitly has an '{1}' return type." }, + Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type: { code: 7011, category: ts.DiagnosticCategory.Error, key: "Function expression, which lacks return-type annotation, implicitly has an '{0}' return type." }, + Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: { code: 7013, category: ts.DiagnosticCategory.Error, key: "Construct signature, which lacks return-type annotation, implicitly has an 'any' return type." }, + Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation: { code: 7016, category: ts.DiagnosticCategory.Error, key: "Property '{0}' implicitly has type 'any', because its 'set' accessor lacks a type annotation." }, + Index_signature_of_object_type_implicitly_has_an_any_type: { code: 7017, category: ts.DiagnosticCategory.Error, key: "Index signature of object type implicitly has an 'any' type." }, + Object_literal_s_property_0_implicitly_has_an_1_type: { code: 7018, category: ts.DiagnosticCategory.Error, key: "Object literal's property '{0}' implicitly has an '{1}' type." }, + Rest_parameter_0_implicitly_has_an_any_type: { code: 7019, category: ts.DiagnosticCategory.Error, key: "Rest parameter '{0}' implicitly has an 'any[]' type." }, + Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: { code: 7020, category: ts.DiagnosticCategory.Error, key: "Call signature, which lacks return-type annotation, implicitly has an 'any' return type." }, + _0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation: { code: 7021, category: ts.DiagnosticCategory.Error, key: "'{0}' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation." }, + _0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer: { code: 7022, category: ts.DiagnosticCategory.Error, key: "'{0}' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer." }, + _0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7023, category: ts.DiagnosticCategory.Error, key: "'{0}' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." }, + Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7024, category: ts.DiagnosticCategory.Error, key: "Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." }, + You_cannot_rename_this_element: { code: 8000, category: ts.DiagnosticCategory.Error, key: "You cannot rename this element." }, + You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library: { code: 8001, category: ts.DiagnosticCategory.Error, key: "You cannot rename elements that are defined in the standard TypeScript library." }, + import_can_only_be_used_in_a_ts_file: { code: 8002, category: ts.DiagnosticCategory.Error, key: "'import ... =' can only be used in a .ts file." }, + export_can_only_be_used_in_a_ts_file: { code: 8003, category: ts.DiagnosticCategory.Error, key: "'export=' can only be used in a .ts file." }, + type_parameter_declarations_can_only_be_used_in_a_ts_file: { code: 8004, category: ts.DiagnosticCategory.Error, key: "'type parameter declarations' can only be used in a .ts file." }, + implements_clauses_can_only_be_used_in_a_ts_file: { code: 8005, category: ts.DiagnosticCategory.Error, key: "'implements clauses' can only be used in a .ts file." }, + interface_declarations_can_only_be_used_in_a_ts_file: { code: 8006, category: ts.DiagnosticCategory.Error, key: "'interface declarations' can only be used in a .ts file." }, + module_declarations_can_only_be_used_in_a_ts_file: { code: 8007, category: ts.DiagnosticCategory.Error, key: "'module declarations' can only be used in a .ts file." }, + type_aliases_can_only_be_used_in_a_ts_file: { code: 8008, category: ts.DiagnosticCategory.Error, key: "'type aliases' can only be used in a .ts file." }, + _0_can_only_be_used_in_a_ts_file: { code: 8009, category: ts.DiagnosticCategory.Error, key: "'{0}' can only be used in a .ts file." }, + types_can_only_be_used_in_a_ts_file: { code: 8010, category: ts.DiagnosticCategory.Error, key: "'types' can only be used in a .ts file." }, + type_arguments_can_only_be_used_in_a_ts_file: { code: 8011, category: ts.DiagnosticCategory.Error, key: "'type arguments' can only be used in a .ts file." }, + parameter_modifiers_can_only_be_used_in_a_ts_file: { code: 8012, category: ts.DiagnosticCategory.Error, key: "'parameter modifiers' can only be used in a .ts file." }, + can_only_be_used_in_a_ts_file: { code: 8013, category: ts.DiagnosticCategory.Error, key: "'?' can only be used in a .ts file." }, + property_declarations_can_only_be_used_in_a_ts_file: { code: 8014, category: ts.DiagnosticCategory.Error, key: "'property declarations' can only be used in a .ts file." }, + enum_declarations_can_only_be_used_in_a_ts_file: { code: 8015, category: ts.DiagnosticCategory.Error, key: "'enum declarations' can only be used in a .ts file." }, + type_assertion_expressions_can_only_be_used_in_a_ts_file: { code: 8016, category: ts.DiagnosticCategory.Error, key: "'type assertion expressions' can only be used in a .ts file." }, + decorators_can_only_be_used_in_a_ts_file: { code: 8017, category: ts.DiagnosticCategory.Error, key: "'decorators' can only be used in a .ts file." }, + yield_expressions_are_not_currently_supported: { code: 9000, category: ts.DiagnosticCategory.Error, key: "'yield' expressions are not currently supported." }, + Generators_are_not_currently_supported: { code: 9001, category: ts.DiagnosticCategory.Error, key: "Generators are not currently supported." }, + Only_identifiers_Slashqualified_names_with_optional_type_arguments_are_currently_supported_in_a_class_extends_clauses: { code: 9002, category: ts.DiagnosticCategory.Error, key: "Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clauses." }, + class_expressions_are_not_currently_supported: { code: 9003, category: ts.DiagnosticCategory.Error, key: "'class' expressions are not currently supported." }, + class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration: { code: 9004, category: ts.DiagnosticCategory.Error, key: "'class' declarations are only supported directly inside a module or as a top level declaration." }, + }; +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/emitter.js b/dist/typescript/compiler/emitter.js new file mode 100644 index 000000000..8ccc93668 --- /dev/null +++ b/dist/typescript/compiler/emitter.js @@ -0,0 +1,4184 @@ +/// +/// +var ts; +(function (ts) { + function isExternalModuleOrDeclarationFile(sourceFile) { + return ts.isExternalModule(sourceFile) || ts.isDeclarationFile(sourceFile); + } + ts.isExternalModuleOrDeclarationFile = isExternalModuleOrDeclarationFile; + var TempFlags; + (function (TempFlags) { + TempFlags[TempFlags["Auto"] = 0] = "Auto"; + TempFlags[TempFlags["CountMask"] = 268435455] = "CountMask"; + TempFlags[TempFlags["_i"] = 268435456] = "_i"; + TempFlags[TempFlags["_n"] = 536870912] = "_n"; + })(TempFlags || (TempFlags = {})); + function emitFiles(resolver, host, targetSourceFile) { + var extendsHelper = "\nvar __extends = this.__extends || function (d, b) {\n for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];\n function __() { this.constructor = d; }\n __.prototype = b.prototype;\n d.prototype = new __();\n};"; + var decorateHelper = "\nif (typeof __decorate !== \"function\") __decorate = function (decorators, target, key, desc) {\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") return Reflect.decorate(decorators, target, key, desc);\n switch (arguments.length) {\n case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);\n case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);\n case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);\n }\n};"; + var metadataHelper = "\nif (typeof __metadata !== \"function\") __metadata = function (k, v) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};"; + var paramHelper = "\nif (typeof __param !== \"function\") __param = function (paramIndex, decorator) {\n return function (target, key) { decorator(target, key, paramIndex); }\n};"; + var compilerOptions = host.getCompilerOptions(); + var languageVersion = compilerOptions.target || 0; + var sourceMapDataList = compilerOptions.sourceMap ? [] : undefined; + var diagnostics = []; + var newLine = host.getNewLine(); + if (targetSourceFile === undefined) { + ts.forEach(host.getSourceFiles(), function (sourceFile) { + if (ts.shouldEmitToOwnFile(sourceFile, compilerOptions)) { + var jsFilePath = ts.getOwnEmitOutputFilePath(sourceFile, host, ".js"); + emitFile(jsFilePath, sourceFile); + } + }); + if (compilerOptions.out) { + emitFile(compilerOptions.out); + } + } + else { + if (ts.shouldEmitToOwnFile(targetSourceFile, compilerOptions)) { + var jsFilePath = ts.getOwnEmitOutputFilePath(targetSourceFile, host, ".js"); + emitFile(jsFilePath, targetSourceFile); + } + else if (!ts.isDeclarationFile(targetSourceFile) && compilerOptions.out) { + emitFile(compilerOptions.out); + } + } + diagnostics = ts.sortAndDeduplicateDiagnostics(diagnostics); + return { + emitSkipped: false, + diagnostics: diagnostics, + sourceMaps: sourceMapDataList + }; + function isNodeDescendentOf(node, ancestor) { + while (node) { + if (node === ancestor) + return true; + node = node.parent; + } + return false; + } + function isUniqueLocalName(name, container) { + for (var node = container; isNodeDescendentOf(node, container); node = node.nextContainer) { + if (node.locals && ts.hasProperty(node.locals, name)) { + if (node.locals[name].flags & (107455 | 1048576 | 8388608)) { + return false; + } + } + } + return true; + } + function emitJavaScript(jsFilePath, root) { + var writer = ts.createTextWriter(newLine); + var write = writer.write; + var writeTextOfNode = writer.writeTextOfNode; + var writeLine = writer.writeLine; + var increaseIndent = writer.increaseIndent; + var decreaseIndent = writer.decreaseIndent; + var currentSourceFile; + var generatedNameSet = {}; + var nodeToGeneratedName = []; + var blockScopedVariableToGeneratedName; + var computedPropertyNamesToGeneratedNames; + var extendsEmitted = false; + var decorateEmitted = false; + var paramEmitted = false; + var tempFlags = 0; + var tempVariables; + var tempParameters; + var externalImports; + var exportSpecifiers; + var exportEquals; + var hasExportStars; + var writeEmittedFiles = writeJavaScriptFile; + var detachedCommentsInfo; + var writeComment = ts.writeCommentRange; + var emit = emitNodeWithoutSourceMap; + var emitStart = function (node) { }; + var emitEnd = function (node) { }; + var emitToken = emitTokenText; + var scopeEmitStart = function (scopeDeclaration, scopeName) { }; + var scopeEmitEnd = function () { }; + var sourceMapData; + if (compilerOptions.sourceMap) { + initializeEmitterWithSourceMaps(); + } + if (root) { + emitSourceFile(root); + } + else { + ts.forEach(host.getSourceFiles(), function (sourceFile) { + if (!isExternalModuleOrDeclarationFile(sourceFile)) { + emitSourceFile(sourceFile); + } + }); + } + writeLine(); + writeEmittedFiles(writer.getText(), compilerOptions.emitBOM); + return; + function emitSourceFile(sourceFile) { + currentSourceFile = sourceFile; + emit(sourceFile); + } + function isUniqueName(name) { + return !resolver.hasGlobalName(name) && + !ts.hasProperty(currentSourceFile.identifiers, name) && + !ts.hasProperty(generatedNameSet, name); + } + function makeTempVariableName(flags) { + if (flags && !(tempFlags & flags)) { + var name = flags === 268435456 ? "_i" : "_n"; + if (isUniqueName(name)) { + tempFlags |= flags; + return name; + } + } + while (true) { + var count = tempFlags & 268435455; + tempFlags++; + if (count !== 8 && count !== 13) { + var name_1 = count < 26 ? "_" + String.fromCharCode(97 + count) : "_" + (count - 26); + if (isUniqueName(name_1)) { + return name_1; + } + } + } + } + function makeUniqueName(baseName) { + if (baseName.charCodeAt(baseName.length - 1) !== 95) { + baseName += "_"; + } + var i = 1; + while (true) { + var generatedName = baseName + i; + if (isUniqueName(generatedName)) { + return generatedNameSet[generatedName] = generatedName; + } + i++; + } + } + function assignGeneratedName(node, name) { + nodeToGeneratedName[ts.getNodeId(node)] = ts.unescapeIdentifier(name); + } + function generateNameForFunctionOrClassDeclaration(node) { + if (!node.name) { + assignGeneratedName(node, makeUniqueName("default")); + } + } + function generateNameForModuleOrEnum(node) { + if (node.name.kind === 65) { + var name_2 = node.name.text; + assignGeneratedName(node, isUniqueLocalName(name_2, node) ? name_2 : makeUniqueName(name_2)); + } + } + function generateNameForImportOrExportDeclaration(node) { + var expr = ts.getExternalModuleName(node); + var baseName = expr.kind === 8 ? + ts.escapeIdentifier(ts.makeIdentifierFromModuleName(expr.text)) : "module"; + assignGeneratedName(node, makeUniqueName(baseName)); + } + function generateNameForImportDeclaration(node) { + if (node.importClause) { + generateNameForImportOrExportDeclaration(node); + } + } + function generateNameForExportDeclaration(node) { + if (node.moduleSpecifier) { + generateNameForImportOrExportDeclaration(node); + } + } + function generateNameForExportAssignment(node) { + if (node.expression && node.expression.kind !== 65) { + assignGeneratedName(node, makeUniqueName("default")); + } + } + function generateNameForNode(node) { + switch (node.kind) { + case 200: + case 201: + case 174: + generateNameForFunctionOrClassDeclaration(node); + break; + case 205: + generateNameForModuleOrEnum(node); + generateNameForNode(node.body); + break; + case 204: + generateNameForModuleOrEnum(node); + break; + case 209: + generateNameForImportDeclaration(node); + break; + case 215: + generateNameForExportDeclaration(node); + break; + case 214: + generateNameForExportAssignment(node); + break; + } + } + function getGeneratedNameForNode(node) { + var nodeId = ts.getNodeId(node); + if (!nodeToGeneratedName[nodeId]) { + generateNameForNode(node); + } + return nodeToGeneratedName[nodeId]; + } + function initializeEmitterWithSourceMaps() { + var sourceMapDir; + var sourceMapSourceIndex = -1; + var sourceMapNameIndexMap = {}; + var sourceMapNameIndices = []; + function getSourceMapNameIndex() { + return sourceMapNameIndices.length ? sourceMapNameIndices[sourceMapNameIndices.length - 1] : -1; + } + var lastRecordedSourceMapSpan; + var lastEncodedSourceMapSpan = { + emittedLine: 1, + emittedColumn: 1, + sourceLine: 1, + sourceColumn: 1, + sourceIndex: 0 + }; + var lastEncodedNameIndex = 0; + function encodeLastRecordedSourceMapSpan() { + if (!lastRecordedSourceMapSpan || lastRecordedSourceMapSpan === lastEncodedSourceMapSpan) { + return; + } + var prevEncodedEmittedColumn = lastEncodedSourceMapSpan.emittedColumn; + if (lastEncodedSourceMapSpan.emittedLine == lastRecordedSourceMapSpan.emittedLine) { + if (sourceMapData.sourceMapMappings) { + sourceMapData.sourceMapMappings += ","; + } + } + else { + for (var encodedLine = lastEncodedSourceMapSpan.emittedLine; encodedLine < lastRecordedSourceMapSpan.emittedLine; encodedLine++) { + sourceMapData.sourceMapMappings += ";"; + } + prevEncodedEmittedColumn = 1; + } + sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.emittedColumn - prevEncodedEmittedColumn); + sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceIndex - lastEncodedSourceMapSpan.sourceIndex); + sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceLine - lastEncodedSourceMapSpan.sourceLine); + sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceColumn - lastEncodedSourceMapSpan.sourceColumn); + if (lastRecordedSourceMapSpan.nameIndex >= 0) { + sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.nameIndex - lastEncodedNameIndex); + lastEncodedNameIndex = lastRecordedSourceMapSpan.nameIndex; + } + lastEncodedSourceMapSpan = lastRecordedSourceMapSpan; + sourceMapData.sourceMapDecodedMappings.push(lastEncodedSourceMapSpan); + function base64VLQFormatEncode(inValue) { + function base64FormatEncode(inValue) { + if (inValue < 64) { + return 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charAt(inValue); + } + throw TypeError(inValue + ": not a 64 based value"); + } + if (inValue < 0) { + inValue = ((-inValue) << 1) + 1; + } + else { + inValue = inValue << 1; + } + var encodedStr = ""; + do { + var currentDigit = inValue & 31; + inValue = inValue >> 5; + if (inValue > 0) { + currentDigit = currentDigit | 32; + } + encodedStr = encodedStr + base64FormatEncode(currentDigit); + } while (inValue > 0); + return encodedStr; + } + } + function recordSourceMapSpan(pos) { + var sourceLinePos = ts.getLineAndCharacterOfPosition(currentSourceFile, pos); + sourceLinePos.line++; + sourceLinePos.character++; + var emittedLine = writer.getLine(); + var emittedColumn = writer.getColumn(); + if (!lastRecordedSourceMapSpan || + lastRecordedSourceMapSpan.emittedLine != emittedLine || + lastRecordedSourceMapSpan.emittedColumn != emittedColumn || + (lastRecordedSourceMapSpan.sourceIndex === sourceMapSourceIndex && + (lastRecordedSourceMapSpan.sourceLine > sourceLinePos.line || + (lastRecordedSourceMapSpan.sourceLine === sourceLinePos.line && lastRecordedSourceMapSpan.sourceColumn > sourceLinePos.character)))) { + encodeLastRecordedSourceMapSpan(); + lastRecordedSourceMapSpan = { + emittedLine: emittedLine, + emittedColumn: emittedColumn, + sourceLine: sourceLinePos.line, + sourceColumn: sourceLinePos.character, + nameIndex: getSourceMapNameIndex(), + sourceIndex: sourceMapSourceIndex + }; + } + else { + lastRecordedSourceMapSpan.sourceLine = sourceLinePos.line; + lastRecordedSourceMapSpan.sourceColumn = sourceLinePos.character; + lastRecordedSourceMapSpan.sourceIndex = sourceMapSourceIndex; + } + } + function recordEmitNodeStartSpan(node) { + recordSourceMapSpan(ts.skipTrivia(currentSourceFile.text, node.pos)); + } + function recordEmitNodeEndSpan(node) { + recordSourceMapSpan(node.end); + } + function writeTextWithSpanRecord(tokenKind, startPos, emitFn) { + var tokenStartPos = ts.skipTrivia(currentSourceFile.text, startPos); + recordSourceMapSpan(tokenStartPos); + var tokenEndPos = emitTokenText(tokenKind, tokenStartPos, emitFn); + recordSourceMapSpan(tokenEndPos); + return tokenEndPos; + } + function recordNewSourceFileStart(node) { + var sourcesDirectoryPath = compilerOptions.sourceRoot ? host.getCommonSourceDirectory() : sourceMapDir; + sourceMapData.sourceMapSources.push(ts.getRelativePathToDirectoryOrUrl(sourcesDirectoryPath, node.fileName, host.getCurrentDirectory(), host.getCanonicalFileName, true)); + sourceMapSourceIndex = sourceMapData.sourceMapSources.length - 1; + sourceMapData.inputSourceFileNames.push(node.fileName); + } + function recordScopeNameOfNode(node, scopeName) { + function recordScopeNameIndex(scopeNameIndex) { + sourceMapNameIndices.push(scopeNameIndex); + } + function recordScopeNameStart(scopeName) { + var scopeNameIndex = -1; + if (scopeName) { + var parentIndex = getSourceMapNameIndex(); + if (parentIndex !== -1) { + var name_3 = node.name; + if (!name_3 || name_3.kind !== 127) { + scopeName = "." + scopeName; + } + scopeName = sourceMapData.sourceMapNames[parentIndex] + scopeName; + } + scopeNameIndex = ts.getProperty(sourceMapNameIndexMap, scopeName); + if (scopeNameIndex === undefined) { + scopeNameIndex = sourceMapData.sourceMapNames.length; + sourceMapData.sourceMapNames.push(scopeName); + sourceMapNameIndexMap[scopeName] = scopeNameIndex; + } + } + recordScopeNameIndex(scopeNameIndex); + } + if (scopeName) { + recordScopeNameStart(scopeName); + } + else if (node.kind === 200 || + node.kind === 162 || + node.kind === 134 || + node.kind === 133 || + node.kind === 136 || + node.kind === 137 || + node.kind === 205 || + node.kind === 201 || + node.kind === 204) { + if (node.name) { + var name_4 = node.name; + scopeName = name_4.kind === 127 + ? ts.getTextOfNode(name_4) + : node.name.text; + } + recordScopeNameStart(scopeName); + } + else { + recordScopeNameIndex(getSourceMapNameIndex()); + } + } + function recordScopeNameEnd() { + sourceMapNameIndices.pop(); + } + ; + function writeCommentRangeWithMap(curentSourceFile, writer, comment, newLine) { + recordSourceMapSpan(comment.pos); + ts.writeCommentRange(currentSourceFile, writer, comment, newLine); + recordSourceMapSpan(comment.end); + } + function serializeSourceMapContents(version, file, sourceRoot, sources, names, mappings) { + if (typeof JSON !== "undefined") { + return JSON.stringify({ + version: version, + file: file, + sourceRoot: sourceRoot, + sources: sources, + names: names, + mappings: mappings + }); + } + return "{\"version\":" + version + ",\"file\":\"" + ts.escapeString(file) + "\",\"sourceRoot\":\"" + ts.escapeString(sourceRoot) + "\",\"sources\":[" + serializeStringArray(sources) + "],\"names\":[" + serializeStringArray(names) + "],\"mappings\":\"" + ts.escapeString(mappings) + "\"}"; + function serializeStringArray(list) { + var output = ""; + for (var i = 0, n = list.length; i < n; i++) { + if (i) { + output += ","; + } + output += "\"" + ts.escapeString(list[i]) + "\""; + } + return output; + } + } + function writeJavaScriptAndSourceMapFile(emitOutput, writeByteOrderMark) { + encodeLastRecordedSourceMapSpan(); + ts.writeFile(host, diagnostics, sourceMapData.sourceMapFilePath, serializeSourceMapContents(3, sourceMapData.sourceMapFile, sourceMapData.sourceMapSourceRoot, sourceMapData.sourceMapSources, sourceMapData.sourceMapNames, sourceMapData.sourceMapMappings), false); + sourceMapDataList.push(sourceMapData); + writeJavaScriptFile(emitOutput + "//# sourceMappingURL=" + sourceMapData.jsSourceMappingURL, writeByteOrderMark); + } + var sourceMapJsFile = ts.getBaseFileName(ts.normalizeSlashes(jsFilePath)); + sourceMapData = { + sourceMapFilePath: jsFilePath + ".map", + jsSourceMappingURL: sourceMapJsFile + ".map", + sourceMapFile: sourceMapJsFile, + sourceMapSourceRoot: compilerOptions.sourceRoot || "", + sourceMapSources: [], + inputSourceFileNames: [], + sourceMapNames: [], + sourceMapMappings: "", + sourceMapDecodedMappings: [] + }; + sourceMapData.sourceMapSourceRoot = ts.normalizeSlashes(sourceMapData.sourceMapSourceRoot); + if (sourceMapData.sourceMapSourceRoot.length && sourceMapData.sourceMapSourceRoot.charCodeAt(sourceMapData.sourceMapSourceRoot.length - 1) !== 47) { + sourceMapData.sourceMapSourceRoot += ts.directorySeparator; + } + if (compilerOptions.mapRoot) { + sourceMapDir = ts.normalizeSlashes(compilerOptions.mapRoot); + if (root) { + sourceMapDir = ts.getDirectoryPath(ts.getSourceFilePathInNewDir(root, host, sourceMapDir)); + } + if (!ts.isRootedDiskPath(sourceMapDir) && !ts.isUrl(sourceMapDir)) { + sourceMapDir = ts.combinePaths(host.getCommonSourceDirectory(), sourceMapDir); + sourceMapData.jsSourceMappingURL = ts.getRelativePathToDirectoryOrUrl(ts.getDirectoryPath(ts.normalizePath(jsFilePath)), ts.combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL), host.getCurrentDirectory(), host.getCanonicalFileName, true); + } + else { + sourceMapData.jsSourceMappingURL = ts.combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL); + } + } + else { + sourceMapDir = ts.getDirectoryPath(ts.normalizePath(jsFilePath)); + } + function emitNodeWithSourceMap(node, allowGeneratedIdentifiers) { + if (node) { + if (ts.nodeIsSynthesized(node)) { + return emitNodeWithoutSourceMap(node, false); + } + if (node.kind != 227) { + recordEmitNodeStartSpan(node); + emitNodeWithoutSourceMap(node, allowGeneratedIdentifiers); + recordEmitNodeEndSpan(node); + } + else { + recordNewSourceFileStart(node); + emitNodeWithoutSourceMap(node, false); + } + } + } + writeEmittedFiles = writeJavaScriptAndSourceMapFile; + emit = emitNodeWithSourceMap; + emitStart = recordEmitNodeStartSpan; + emitEnd = recordEmitNodeEndSpan; + emitToken = writeTextWithSpanRecord; + scopeEmitStart = recordScopeNameOfNode; + scopeEmitEnd = recordScopeNameEnd; + writeComment = writeCommentRangeWithMap; + } + function writeJavaScriptFile(emitOutput, writeByteOrderMark) { + ts.writeFile(host, diagnostics, jsFilePath, emitOutput, writeByteOrderMark); + } + function createTempVariable(flags) { + var result = ts.createSynthesizedNode(65); + result.text = makeTempVariableName(flags); + return result; + } + function recordTempDeclaration(name) { + if (!tempVariables) { + tempVariables = []; + } + tempVariables.push(name); + } + function createAndRecordTempVariable(flags) { + var temp = createTempVariable(flags); + recordTempDeclaration(temp); + return temp; + } + function emitTempDeclarations(newLine) { + if (tempVariables) { + if (newLine) { + writeLine(); + } + else { + write(" "); + } + write("var "); + emitCommaList(tempVariables); + write(";"); + } + } + function emitTokenText(tokenKind, startPos, emitFn) { + var tokenString = ts.tokenToString(tokenKind); + if (emitFn) { + emitFn(); + } + else { + write(tokenString); + } + return startPos + tokenString.length; + } + function emitOptional(prefix, node) { + if (node) { + write(prefix); + emit(node); + } + } + function emitParenthesizedIf(node, parenthesized) { + if (parenthesized) { + write("("); + } + emit(node); + if (parenthesized) { + write(")"); + } + } + function emitTrailingCommaIfPresent(nodeList) { + if (nodeList.hasTrailingComma) { + write(","); + } + } + function emitLinePreservingList(parent, nodes, allowTrailingComma, spacesBetweenBraces) { + ts.Debug.assert(nodes.length > 0); + increaseIndent(); + if (nodeStartPositionsAreOnSameLine(parent, nodes[0])) { + if (spacesBetweenBraces) { + write(" "); + } + } + else { + writeLine(); + } + for (var i = 0, n = nodes.length; i < n; i++) { + if (i) { + if (nodeEndIsOnSameLineAsNodeStart(nodes[i - 1], nodes[i])) { + write(", "); + } + else { + write(","); + writeLine(); + } + } + emit(nodes[i]); + } + if (nodes.hasTrailingComma && allowTrailingComma) { + write(","); + } + decreaseIndent(); + if (nodeEndPositionsAreOnSameLine(parent, ts.lastOrUndefined(nodes))) { + if (spacesBetweenBraces) { + write(" "); + } + } + else { + writeLine(); + } + } + function emitList(nodes, start, count, multiLine, trailingComma, leadingComma, noTrailingNewLine, emitNode) { + if (!emitNode) { + emitNode = emit; + } + for (var i = 0; i < count; i++) { + if (multiLine) { + if (i || leadingComma) { + write(","); + } + writeLine(); + } + else { + if (i || leadingComma) { + write(", "); + } + } + emitNode(nodes[start + i]); + leadingComma = true; + } + if (trailingComma) { + write(","); + } + if (multiLine && !noTrailingNewLine) { + writeLine(); + } + return count; + } + function emitCommaList(nodes) { + if (nodes) { + emitList(nodes, 0, nodes.length, false, false); + } + } + function emitLines(nodes) { + emitLinesStartingAt(nodes, 0); + } + function emitLinesStartingAt(nodes, startIndex) { + for (var i = startIndex; i < nodes.length; i++) { + writeLine(); + emit(nodes[i]); + } + } + function isBinaryOrOctalIntegerLiteral(node, text) { + if (node.kind === 7 && text.length > 1) { + switch (text.charCodeAt(1)) { + case 98: + case 66: + case 111: + case 79: + return true; + } + } + return false; + } + function emitLiteral(node) { + var text = getLiteralText(node); + if (compilerOptions.sourceMap && (node.kind === 8 || ts.isTemplateLiteralKind(node.kind))) { + writer.writeLiteral(text); + } + else if (languageVersion < 2 && isBinaryOrOctalIntegerLiteral(node, text)) { + write(node.text); + } + else { + write(text); + } + } + function getLiteralText(node) { + if (languageVersion < 2 && (ts.isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape)) { + return getQuotedEscapedLiteralText('"', node.text, '"'); + } + if (node.parent) { + return ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, node); + } + switch (node.kind) { + case 8: + return getQuotedEscapedLiteralText('"', node.text, '"'); + case 10: + return getQuotedEscapedLiteralText('`', node.text, '`'); + case 11: + return getQuotedEscapedLiteralText('`', node.text, '${'); + case 12: + return getQuotedEscapedLiteralText('}', node.text, '${'); + case 13: + return getQuotedEscapedLiteralText('}', node.text, '`'); + case 7: + return node.text; + } + ts.Debug.fail("Literal kind '" + node.kind + "' not accounted for."); + } + function getQuotedEscapedLiteralText(leftQuote, text, rightQuote) { + return leftQuote + ts.escapeNonAsciiCharacters(ts.escapeString(text)) + rightQuote; + } + function emitDownlevelRawTemplateLiteral(node) { + var text = ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, node); + var isLast = node.kind === 10 || node.kind === 13; + text = text.substring(1, text.length - (isLast ? 1 : 2)); + text = text.replace(/\r\n?/g, "\n"); + text = ts.escapeString(text); + write('"' + text + '"'); + } + function emitDownlevelTaggedTemplateArray(node, literalEmitter) { + write("["); + if (node.template.kind === 10) { + literalEmitter(node.template); + } + else { + literalEmitter(node.template.head); + ts.forEach(node.template.templateSpans, function (child) { + write(", "); + literalEmitter(child.literal); + }); + } + write("]"); + } + function emitDownlevelTaggedTemplate(node) { + var tempVariable = createAndRecordTempVariable(0); + write("("); + emit(tempVariable); + write(" = "); + emitDownlevelTaggedTemplateArray(node, emit); + write(", "); + emit(tempVariable); + write(".raw = "); + emitDownlevelTaggedTemplateArray(node, emitDownlevelRawTemplateLiteral); + write(", "); + emitParenthesizedIf(node.tag, needsParenthesisForPropertyAccessOrInvocation(node.tag)); + write("("); + emit(tempVariable); + if (node.template.kind === 171) { + ts.forEach(node.template.templateSpans, function (templateSpan) { + write(", "); + var needsParens = templateSpan.expression.kind === 169 + && templateSpan.expression.operatorToken.kind === 23; + emitParenthesizedIf(templateSpan.expression, needsParens); + }); + } + write("))"); + } + function emitTemplateExpression(node) { + if (languageVersion >= 2) { + ts.forEachChild(node, emit); + return; + } + var emitOuterParens = ts.isExpression(node.parent) + && templateNeedsParens(node, node.parent); + if (emitOuterParens) { + write("("); + } + var headEmitted = false; + if (shouldEmitTemplateHead()) { + emitLiteral(node.head); + headEmitted = true; + } + for (var i = 0, n = node.templateSpans.length; i < n; i++) { + var templateSpan = node.templateSpans[i]; + var needsParens = templateSpan.expression.kind !== 161 + && comparePrecedenceToBinaryPlus(templateSpan.expression) !== 1; + if (i > 0 || headEmitted) { + write(" + "); + } + emitParenthesizedIf(templateSpan.expression, needsParens); + if (templateSpan.literal.text.length !== 0) { + write(" + "); + emitLiteral(templateSpan.literal); + } + } + if (emitOuterParens) { + write(")"); + } + function shouldEmitTemplateHead() { + // If this expression has an empty head literal and the first template span has a non-empty + // literal, then emitting the empty head literal is not necessary. + // `${ foo } and ${ bar }` + // can be emitted as + // foo + " and " + bar + // This is because it is only required that one of the first two operands in the emit + // output must be a string literal, so that the other operand and all following operands + // are forced into strings. + // + // If the first template span has an empty literal, then the head must still be emitted. + // `${ foo }${ bar }` + // must still be emitted as + // "" + foo + bar + ts.Debug.assert(node.templateSpans.length !== 0); + return node.head.text.length !== 0 || node.templateSpans[0].literal.text.length === 0; + } + function templateNeedsParens(template, parent) { + switch (parent.kind) { + case 157: + case 158: + return parent.expression === template; + case 159: + case 161: + return false; + default: + return comparePrecedenceToBinaryPlus(parent) !== -1; + } + } + function comparePrecedenceToBinaryPlus(expression) { + switch (expression.kind) { + case 169: + switch (expression.operatorToken.kind) { + case 35: + case 36: + case 37: + return 1; + case 33: + case 34: + return 0; + default: + return -1; + } + case 172: + case 170: + return -1; + default: + return 1; + } + } + } + function emitTemplateSpan(span) { + emit(span.expression); + emit(span.literal); + } + function emitExpressionForPropertyName(node) { + ts.Debug.assert(node.kind !== 152); + if (node.kind === 8) { + emitLiteral(node); + } + else if (node.kind === 127) { + if (ts.nodeIsDecorated(node.parent)) { + if (!computedPropertyNamesToGeneratedNames) { + computedPropertyNamesToGeneratedNames = []; + } + var generatedName = computedPropertyNamesToGeneratedNames[ts.getNodeId(node)]; + if (generatedName) { + write(generatedName); + return; + } + generatedName = createAndRecordTempVariable(0).text; + computedPropertyNamesToGeneratedNames[ts.getNodeId(node)] = generatedName; + write(generatedName); + write(" = "); + } + emit(node.expression); + } + else { + write("\""); + if (node.kind === 7) { + write(node.text); + } + else { + writeTextOfNode(currentSourceFile, node); + } + write("\""); + } + } + function isNotExpressionIdentifier(node) { + var parent = node.parent; + switch (parent.kind) { + case 129: + case 198: + case 152: + case 132: + case 131: + case 224: + case 225: + case 226: + case 134: + case 133: + case 200: + case 136: + case 137: + case 162: + case 201: + case 202: + case 204: + case 205: + case 208: + case 210: + case 211: + return parent.name === node; + case 213: + case 217: + return parent.name === node || parent.propertyName === node; + case 190: + case 189: + case 214: + return false; + case 194: + return node.parent.label === node; + } + } + function emitExpressionIdentifier(node) { + var substitution = resolver.getExpressionNameSubstitution(node, getGeneratedNameForNode); + if (substitution) { + write(substitution); + } + else { + writeTextOfNode(currentSourceFile, node); + } + } + function getGeneratedNameForIdentifier(node) { + if (ts.nodeIsSynthesized(node) || !blockScopedVariableToGeneratedName) { + return undefined; + } + var variableId = resolver.getBlockScopedVariableId(node); + if (variableId === undefined) { + return undefined; + } + return blockScopedVariableToGeneratedName[variableId]; + } + function emitIdentifier(node, allowGeneratedIdentifiers) { + if (allowGeneratedIdentifiers) { + var generatedName = getGeneratedNameForIdentifier(node); + if (generatedName) { + write(generatedName); + return; + } + } + if (!node.parent) { + write(node.text); + } + else if (!isNotExpressionIdentifier(node)) { + emitExpressionIdentifier(node); + } + else { + writeTextOfNode(currentSourceFile, node); + } + } + function emitThis(node) { + if (resolver.getNodeCheckFlags(node) & 2) { + write("_this"); + } + else { + write("this"); + } + } + function emitSuper(node) { + if (languageVersion >= 2) { + write("super"); + } + else { + var flags = resolver.getNodeCheckFlags(node); + if (flags & 16) { + write("_super.prototype"); + } + else { + write("_super"); + } + } + } + function emitObjectBindingPattern(node) { + write("{ "); + var elements = node.elements; + emitList(elements, 0, elements.length, false, elements.hasTrailingComma); + write(" }"); + } + function emitArrayBindingPattern(node) { + write("["); + var elements = node.elements; + emitList(elements, 0, elements.length, false, elements.hasTrailingComma); + write("]"); + } + function emitBindingElement(node) { + if (node.propertyName) { + emit(node.propertyName, false); + write(": "); + } + if (node.dotDotDotToken) { + write("..."); + } + if (ts.isBindingPattern(node.name)) { + emit(node.name); + } + else { + emitModuleMemberName(node); + } + emitOptional(" = ", node.initializer); + } + function emitSpreadElementExpression(node) { + write("..."); + emit(node.expression); + } + function emitYieldExpression(node) { + write(ts.tokenToString(110)); + if (node.asteriskToken) { + write("*"); + } + if (node.expression) { + write(" "); + emit(node.expression); + } + } + function needsParenthesisForPropertyAccessOrInvocation(node) { + switch (node.kind) { + case 65: + case 153: + case 155: + case 156: + case 157: + case 161: + return false; + } + return true; + } + function emitListWithSpread(elements, multiLine, trailingComma) { + var pos = 0; + var group = 0; + var length = elements.length; + while (pos < length) { + if (group === 1) { + write(".concat("); + } + else if (group > 1) { + write(", "); + } + var e = elements[pos]; + if (e.kind === 173) { + e = e.expression; + emitParenthesizedIf(e, group === 0 && needsParenthesisForPropertyAccessOrInvocation(e)); + pos++; + } + else { + var i = pos; + while (i < length && elements[i].kind !== 173) { + i++; + } + write("["); + if (multiLine) { + increaseIndent(); + } + emitList(elements, pos, i - pos, multiLine, trailingComma && i === length); + if (multiLine) { + decreaseIndent(); + } + write("]"); + pos = i; + } + group++; + } + if (group > 1) { + write(")"); + } + } + function isSpreadElementExpression(node) { + return node.kind === 173; + } + function emitArrayLiteral(node) { + var elements = node.elements; + if (elements.length === 0) { + write("[]"); + } + else if (languageVersion >= 2 || !ts.forEach(elements, isSpreadElementExpression)) { + write("["); + emitLinePreservingList(node, node.elements, elements.hasTrailingComma, false); + write("]"); + } + else { + emitListWithSpread(elements, (node.flags & 512) !== 0, elements.hasTrailingComma); + } + } + function emitObjectLiteralBody(node, numElements) { + if (numElements === 0) { + write("{}"); + return; + } + write("{"); + if (numElements > 0) { + var properties = node.properties; + if (numElements === properties.length) { + emitLinePreservingList(node, properties, languageVersion >= 1, true); + } + else { + var multiLine = (node.flags & 512) !== 0; + if (!multiLine) { + write(" "); + } + else { + increaseIndent(); + } + emitList(properties, 0, numElements, multiLine, false); + if (!multiLine) { + write(" "); + } + else { + decreaseIndent(); + } + } + } + write("}"); + } + function emitDownlevelObjectLiteralWithComputedProperties(node, firstComputedPropertyIndex) { + var multiLine = (node.flags & 512) !== 0; + var properties = node.properties; + write("("); + if (multiLine) { + increaseIndent(); + } + var tempVar = createAndRecordTempVariable(0); + emit(tempVar); + write(" = "); + emitObjectLiteralBody(node, firstComputedPropertyIndex); + for (var i = firstComputedPropertyIndex, n = properties.length; i < n; i++) { + writeComma(); + var property = properties[i]; + emitStart(property); + if (property.kind === 136 || property.kind === 137) { + var accessors = ts.getAllAccessorDeclarations(node.properties, property); + if (property !== accessors.firstAccessor) { + continue; + } + write("Object.defineProperty("); + emit(tempVar); + write(", "); + emitStart(node.name); + emitExpressionForPropertyName(property.name); + emitEnd(property.name); + write(", {"); + increaseIndent(); + if (accessors.getAccessor) { + writeLine(); + emitLeadingComments(accessors.getAccessor); + write("get: "); + emitStart(accessors.getAccessor); + write("function "); + emitSignatureAndBody(accessors.getAccessor); + emitEnd(accessors.getAccessor); + emitTrailingComments(accessors.getAccessor); + write(","); + } + if (accessors.setAccessor) { + writeLine(); + emitLeadingComments(accessors.setAccessor); + write("set: "); + emitStart(accessors.setAccessor); + write("function "); + emitSignatureAndBody(accessors.setAccessor); + emitEnd(accessors.setAccessor); + emitTrailingComments(accessors.setAccessor); + write(","); + } + writeLine(); + write("enumerable: true,"); + writeLine(); + write("configurable: true"); + decreaseIndent(); + writeLine(); + write("})"); + emitEnd(property); + } + else { + emitLeadingComments(property); + emitStart(property.name); + emit(tempVar); + emitMemberAccessForPropertyName(property.name); + emitEnd(property.name); + write(" = "); + if (property.kind === 224) { + emit(property.initializer); + } + else if (property.kind === 225) { + emitExpressionIdentifier(property.name); + } + else if (property.kind === 134) { + emitFunctionDeclaration(property); + } + else { + ts.Debug.fail("ObjectLiteralElement type not accounted for: " + property.kind); + } + } + emitEnd(property); + } + writeComma(); + emit(tempVar); + if (multiLine) { + decreaseIndent(); + writeLine(); + } + write(")"); + function writeComma() { + if (multiLine) { + write(","); + writeLine(); + } + else { + write(", "); + } + } + } + function emitObjectLiteral(node) { + var properties = node.properties; + if (languageVersion < 2) { + var numProperties = properties.length; + var numInitialNonComputedProperties = numProperties; + for (var i = 0, n = properties.length; i < n; i++) { + if (properties[i].name.kind === 127) { + numInitialNonComputedProperties = i; + break; + } + } + var hasComputedProperty = numInitialNonComputedProperties !== properties.length; + if (hasComputedProperty) { + emitDownlevelObjectLiteralWithComputedProperties(node, numInitialNonComputedProperties); + return; + } + } + emitObjectLiteralBody(node, properties.length); + } + function createBinaryExpression(left, operator, right, startsOnNewLine) { + var result = ts.createSynthesizedNode(169, startsOnNewLine); + result.operatorToken = ts.createSynthesizedNode(operator); + result.left = left; + result.right = right; + return result; + } + function createPropertyAccessExpression(expression, name) { + var result = ts.createSynthesizedNode(155); + result.expression = parenthesizeForAccess(expression); + result.dotToken = ts.createSynthesizedNode(20); + result.name = name; + return result; + } + function createElementAccessExpression(expression, argumentExpression) { + var result = ts.createSynthesizedNode(156); + result.expression = parenthesizeForAccess(expression); + result.argumentExpression = argumentExpression; + return result; + } + function parenthesizeForAccess(expr) { + if (ts.isLeftHandSideExpression(expr) && expr.kind !== 158 && expr.kind !== 7) { + return expr; + } + var node = ts.createSynthesizedNode(161); + node.expression = expr; + return node; + } + function emitComputedPropertyName(node) { + write("["); + emitExpressionForPropertyName(node); + write("]"); + } + function emitMethod(node) { + if (languageVersion >= 2 && node.asteriskToken) { + write("*"); + } + emit(node.name, false); + if (languageVersion < 2) { + write(": function "); + } + emitSignatureAndBody(node); + } + function emitPropertyAssignment(node) { + emit(node.name, false); + write(": "); + emit(node.initializer); + } + function emitShorthandPropertyAssignment(node) { + emit(node.name, false); + if (languageVersion < 2) { + write(": "); + var generatedName = getGeneratedNameForIdentifier(node.name); + if (generatedName) { + write(generatedName); + } + else { + emitExpressionIdentifier(node.name); + } + } + else if (resolver.getExpressionNameSubstitution(node.name, getGeneratedNameForNode)) { + write(": "); + emitExpressionIdentifier(node.name); + } + } + function tryEmitConstantValue(node) { + if (compilerOptions.separateCompilation) { + return false; + } + var constantValue = resolver.getConstantValue(node); + if (constantValue !== undefined) { + write(constantValue.toString()); + if (!compilerOptions.removeComments) { + var propertyName = node.kind === 155 ? ts.declarationNameToString(node.name) : ts.getTextOfNode(node.argumentExpression); + write(" /* " + propertyName + " */"); + } + return true; + } + return false; + } + function indentIfOnDifferentLines(parent, node1, node2, valueToWriteWhenNotIndenting) { + var realNodesAreOnDifferentLines = !ts.nodeIsSynthesized(parent) && !nodeEndIsOnSameLineAsNodeStart(node1, node2); + var synthesizedNodeIsOnDifferentLine = synthesizedNodeStartsOnNewLine(node2); + if (realNodesAreOnDifferentLines || synthesizedNodeIsOnDifferentLine) { + increaseIndent(); + writeLine(); + return true; + } + else { + if (valueToWriteWhenNotIndenting) { + write(valueToWriteWhenNotIndenting); + } + return false; + } + } + function emitPropertyAccess(node) { + if (tryEmitConstantValue(node)) { + return; + } + emit(node.expression); + var indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, node.dotToken); + write("."); + var indentedAfterDot = indentIfOnDifferentLines(node, node.dotToken, node.name); + emit(node.name, false); + decreaseIndentIf(indentedBeforeDot, indentedAfterDot); + } + function emitQualifiedName(node) { + emit(node.left); + write("."); + emit(node.right); + } + function emitIndexedAccess(node) { + if (tryEmitConstantValue(node)) { + return; + } + emit(node.expression); + write("["); + emit(node.argumentExpression); + write("]"); + } + function hasSpreadElement(elements) { + return ts.forEach(elements, function (e) { return e.kind === 173; }); + } + function skipParentheses(node) { + while (node.kind === 161 || node.kind === 160) { + node = node.expression; + } + return node; + } + function emitCallTarget(node) { + if (node.kind === 65 || node.kind === 93 || node.kind === 91) { + emit(node); + return node; + } + var temp = createAndRecordTempVariable(0); + write("("); + emit(temp); + write(" = "); + emit(node); + write(")"); + return temp; + } + function emitCallWithSpread(node) { + var target; + var expr = skipParentheses(node.expression); + if (expr.kind === 155) { + target = emitCallTarget(expr.expression); + write("."); + emit(expr.name); + } + else if (expr.kind === 156) { + target = emitCallTarget(expr.expression); + write("["); + emit(expr.argumentExpression); + write("]"); + } + else if (expr.kind === 91) { + target = expr; + write("_super"); + } + else { + emit(node.expression); + } + write(".apply("); + if (target) { + if (target.kind === 91) { + emitThis(target); + } + else { + emit(target); + } + } + else { + write("void 0"); + } + write(", "); + emitListWithSpread(node.arguments, false, false); + write(")"); + } + function emitCallExpression(node) { + if (languageVersion < 2 && hasSpreadElement(node.arguments)) { + emitCallWithSpread(node); + return; + } + var superCall = false; + if (node.expression.kind === 91) { + emitSuper(node.expression); + superCall = true; + } + else { + emit(node.expression); + superCall = node.expression.kind === 155 && node.expression.expression.kind === 91; + } + if (superCall && languageVersion < 2) { + write(".call("); + emitThis(node.expression); + if (node.arguments.length) { + write(", "); + emitCommaList(node.arguments); + } + write(")"); + } + else { + write("("); + emitCommaList(node.arguments); + write(")"); + } + } + function emitNewExpression(node) { + write("new "); + emit(node.expression); + if (node.arguments) { + write("("); + emitCommaList(node.arguments); + write(")"); + } + } + function emitTaggedTemplateExpression(node) { + if (languageVersion >= 2) { + emit(node.tag); + write(" "); + emit(node.template); + } + else { + emitDownlevelTaggedTemplate(node); + } + } + function emitParenExpression(node) { + if (!node.parent || node.parent.kind !== 163) { + if (node.expression.kind === 160) { + var operand = node.expression.expression; + while (operand.kind == 160) { + operand = operand.expression; + } + if (operand.kind !== 167 && + operand.kind !== 166 && + operand.kind !== 165 && + operand.kind !== 164 && + operand.kind !== 168 && + operand.kind !== 158 && + !(operand.kind === 157 && node.parent.kind === 158) && + !(operand.kind === 162 && node.parent.kind === 157)) { + emit(operand); + return; + } + } + } + write("("); + emit(node.expression); + write(")"); + } + function emitDeleteExpression(node) { + write(ts.tokenToString(74)); + write(" "); + emit(node.expression); + } + function emitVoidExpression(node) { + write(ts.tokenToString(99)); + write(" "); + emit(node.expression); + } + function emitTypeOfExpression(node) { + write(ts.tokenToString(97)); + write(" "); + emit(node.expression); + } + function emitPrefixUnaryExpression(node) { + write(ts.tokenToString(node.operator)); + if (node.operand.kind === 167) { + var operand = node.operand; + if (node.operator === 33 && (operand.operator === 33 || operand.operator === 38)) { + write(" "); + } + else if (node.operator === 34 && (operand.operator === 34 || operand.operator === 39)) { + write(" "); + } + } + emit(node.operand); + } + function emitPostfixUnaryExpression(node) { + emit(node.operand); + write(ts.tokenToString(node.operator)); + } + function emitBinaryExpression(node) { + if (languageVersion < 2 && node.operatorToken.kind === 53 && + (node.left.kind === 154 || node.left.kind === 153)) { + emitDestructuring(node, node.parent.kind === 182); + } + else { + emit(node.left); + var indentedBeforeOperator = indentIfOnDifferentLines(node, node.left, node.operatorToken, node.operatorToken.kind !== 23 ? " " : undefined); + write(ts.tokenToString(node.operatorToken.kind)); + var indentedAfterOperator = indentIfOnDifferentLines(node, node.operatorToken, node.right, " "); + emit(node.right); + decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator); + } + } + function synthesizedNodeStartsOnNewLine(node) { + return ts.nodeIsSynthesized(node) && node.startsOnNewLine; + } + function emitConditionalExpression(node) { + emit(node.condition); + var indentedBeforeQuestion = indentIfOnDifferentLines(node, node.condition, node.questionToken, " "); + write("?"); + var indentedAfterQuestion = indentIfOnDifferentLines(node, node.questionToken, node.whenTrue, " "); + emit(node.whenTrue); + decreaseIndentIf(indentedBeforeQuestion, indentedAfterQuestion); + var indentedBeforeColon = indentIfOnDifferentLines(node, node.whenTrue, node.colonToken, " "); + write(":"); + var indentedAfterColon = indentIfOnDifferentLines(node, node.colonToken, node.whenFalse, " "); + emit(node.whenFalse); + decreaseIndentIf(indentedBeforeColon, indentedAfterColon); + } + function decreaseIndentIf(value1, value2) { + if (value1) { + decreaseIndent(); + } + if (value2) { + decreaseIndent(); + } + } + function isSingleLineEmptyBlock(node) { + if (node && node.kind === 179) { + var block = node; + return block.statements.length === 0 && nodeEndIsOnSameLineAsNodeStart(block, block); + } + } + function emitBlock(node) { + if (isSingleLineEmptyBlock(node)) { + emitToken(14, node.pos); + write(" "); + emitToken(15, node.statements.end); + return; + } + emitToken(14, node.pos); + increaseIndent(); + scopeEmitStart(node.parent); + if (node.kind === 206) { + ts.Debug.assert(node.parent.kind === 205); + emitCaptureThisForNodeIfNecessary(node.parent); + } + emitLines(node.statements); + if (node.kind === 206) { + emitTempDeclarations(true); + } + decreaseIndent(); + writeLine(); + emitToken(15, node.statements.end); + scopeEmitEnd(); + } + function emitEmbeddedStatement(node) { + if (node.kind === 179) { + write(" "); + emit(node); + } + else { + increaseIndent(); + writeLine(); + emit(node); + decreaseIndent(); + } + } + function emitExpressionStatement(node) { + emitParenthesizedIf(node.expression, node.expression.kind === 163); + write(";"); + } + function emitIfStatement(node) { + var endPos = emitToken(84, node.pos); + write(" "); + endPos = emitToken(16, endPos); + emit(node.expression); + emitToken(17, node.expression.end); + emitEmbeddedStatement(node.thenStatement); + if (node.elseStatement) { + writeLine(); + emitToken(76, node.thenStatement.end); + if (node.elseStatement.kind === 183) { + write(" "); + emit(node.elseStatement); + } + else { + emitEmbeddedStatement(node.elseStatement); + } + } + } + function emitDoStatement(node) { + write("do"); + emitEmbeddedStatement(node.statement); + if (node.statement.kind === 179) { + write(" "); + } + else { + writeLine(); + } + write("while ("); + emit(node.expression); + write(");"); + } + function emitWhileStatement(node) { + write("while ("); + emit(node.expression); + write(")"); + emitEmbeddedStatement(node.statement); + } + function emitStartOfVariableDeclarationList(decl, startPos) { + var tokenKind = 98; + if (decl && languageVersion >= 2) { + if (ts.isLet(decl)) { + tokenKind = 104; + } + else if (ts.isConst(decl)) { + tokenKind = 70; + } + } + if (startPos !== undefined) { + emitToken(tokenKind, startPos); + } + else { + switch (tokenKind) { + case 98: + return write("var "); + case 104: + return write("let "); + case 70: + return write("const "); + } + } + } + function emitForStatement(node) { + var endPos = emitToken(82, node.pos); + write(" "); + endPos = emitToken(16, endPos); + if (node.initializer && node.initializer.kind === 199) { + var variableDeclarationList = node.initializer; + var declarations = variableDeclarationList.declarations; + emitStartOfVariableDeclarationList(declarations[0], endPos); + write(" "); + emitCommaList(declarations); + } + else if (node.initializer) { + emit(node.initializer); + } + write(";"); + emitOptional(" ", node.condition); + write(";"); + emitOptional(" ", node.incrementor); + write(")"); + emitEmbeddedStatement(node.statement); + } + function emitForInOrForOfStatement(node) { + if (languageVersion < 2 && node.kind === 188) { + return emitDownLevelForOfStatement(node); + } + var endPos = emitToken(82, node.pos); + write(" "); + endPos = emitToken(16, endPos); + if (node.initializer.kind === 199) { + var variableDeclarationList = node.initializer; + if (variableDeclarationList.declarations.length >= 1) { + var decl = variableDeclarationList.declarations[0]; + emitStartOfVariableDeclarationList(decl, endPos); + write(" "); + emit(decl); + } + } + else { + emit(node.initializer); + } + if (node.kind === 187) { + write(" in "); + } + else { + write(" of "); + } + emit(node.expression); + emitToken(17, node.expression.end); + emitEmbeddedStatement(node.statement); + } + function emitDownLevelForOfStatement(node) { + // The following ES6 code: + // + // for (let v of expr) { } + // + // should be emitted as + // + // for (let _i = 0, _a = expr; _i < _a.length; _i++) { + // let v = _a[_i]; + // } + // + // where _a and _i are temps emitted to capture the RHS and the counter, + // respectively. + // When the left hand side is an expression instead of a let declaration, + // the "let v" is not emitted. + // When the left hand side is a let/const, the v is renamed if there is + // another v in scope. + // Note that all assignments to the LHS are emitted in the body, including + // all destructuring. + // Note also that because an extra statement is needed to assign to the LHS, + // for-of bodies are always emitted as blocks. + var endPos = emitToken(82, node.pos); + write(" "); + endPos = emitToken(16, endPos); + var rhsIsIdentifier = node.expression.kind === 65; + var counter = createTempVariable(268435456); + var rhsReference = rhsIsIdentifier ? node.expression : createTempVariable(0); + emitStart(node.expression); + write("var "); + emitNodeWithoutSourceMap(counter); + write(" = 0"); + emitEnd(node.expression); + if (!rhsIsIdentifier) { + write(", "); + emitStart(node.expression); + emitNodeWithoutSourceMap(rhsReference); + write(" = "); + emitNodeWithoutSourceMap(node.expression); + emitEnd(node.expression); + } + write("; "); + emitStart(node.initializer); + emitNodeWithoutSourceMap(counter); + write(" < "); + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + emitEnd(node.initializer); + write("; "); + emitStart(node.initializer); + emitNodeWithoutSourceMap(counter); + write("++"); + emitEnd(node.initializer); + emitToken(17, node.expression.end); + write(" {"); + writeLine(); + increaseIndent(); + var rhsIterationValue = createElementAccessExpression(rhsReference, counter); + emitStart(node.initializer); + if (node.initializer.kind === 199) { + write("var "); + var variableDeclarationList = node.initializer; + if (variableDeclarationList.declarations.length > 0) { + var declaration = variableDeclarationList.declarations[0]; + if (ts.isBindingPattern(declaration.name)) { + emitDestructuring(declaration, false, rhsIterationValue); + } + else { + emitNodeWithoutSourceMap(declaration); + write(" = "); + emitNodeWithoutSourceMap(rhsIterationValue); + } + } + else { + emitNodeWithoutSourceMap(createTempVariable(0)); + write(" = "); + emitNodeWithoutSourceMap(rhsIterationValue); + } + } + else { + var assignmentExpression = createBinaryExpression(node.initializer, 53, rhsIterationValue, false); + if (node.initializer.kind === 153 || node.initializer.kind === 154) { + emitDestructuring(assignmentExpression, true, undefined); + } + else { + emitNodeWithoutSourceMap(assignmentExpression); + } + } + emitEnd(node.initializer); + write(";"); + if (node.statement.kind === 179) { + emitLines(node.statement.statements); + } + else { + writeLine(); + emit(node.statement); + } + writeLine(); + decreaseIndent(); + write("}"); + } + function emitBreakOrContinueStatement(node) { + emitToken(node.kind === 190 ? 66 : 71, node.pos); + emitOptional(" ", node.label); + write(";"); + } + function emitReturnStatement(node) { + emitToken(90, node.pos); + emitOptional(" ", node.expression); + write(";"); + } + function emitWithStatement(node) { + write("with ("); + emit(node.expression); + write(")"); + emitEmbeddedStatement(node.statement); + } + function emitSwitchStatement(node) { + var endPos = emitToken(92, node.pos); + write(" "); + emitToken(16, endPos); + emit(node.expression); + endPos = emitToken(17, node.expression.end); + write(" "); + emitCaseBlock(node.caseBlock, endPos); + } + function emitCaseBlock(node, startPos) { + emitToken(14, startPos); + increaseIndent(); + emitLines(node.clauses); + decreaseIndent(); + writeLine(); + emitToken(15, node.clauses.end); + } + function nodeStartPositionsAreOnSameLine(node1, node2) { + return ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node1.pos)) === + ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node2.pos)); + } + function nodeEndPositionsAreOnSameLine(node1, node2) { + return ts.getLineOfLocalPosition(currentSourceFile, node1.end) === + ts.getLineOfLocalPosition(currentSourceFile, node2.end); + } + function nodeEndIsOnSameLineAsNodeStart(node1, node2) { + return ts.getLineOfLocalPosition(currentSourceFile, node1.end) === + ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node2.pos)); + } + function emitCaseOrDefaultClause(node) { + if (node.kind === 220) { + write("case "); + emit(node.expression); + write(":"); + } + else { + write("default:"); + } + if (node.statements.length === 1 && nodeStartPositionsAreOnSameLine(node, node.statements[0])) { + write(" "); + emit(node.statements[0]); + } + else { + increaseIndent(); + emitLines(node.statements); + decreaseIndent(); + } + } + function emitThrowStatement(node) { + write("throw "); + emit(node.expression); + write(";"); + } + function emitTryStatement(node) { + write("try "); + emit(node.tryBlock); + emit(node.catchClause); + if (node.finallyBlock) { + writeLine(); + write("finally "); + emit(node.finallyBlock); + } + } + function emitCatchClause(node) { + writeLine(); + var endPos = emitToken(68, node.pos); + write(" "); + emitToken(16, endPos); + emit(node.variableDeclaration); + emitToken(17, node.variableDeclaration ? node.variableDeclaration.end : endPos); + write(" "); + emitBlock(node.block); + } + function emitDebuggerStatement(node) { + emitToken(72, node.pos); + write(";"); + } + function emitLabelledStatement(node) { + emit(node.label); + write(": "); + emit(node.statement); + } + function getContainingModule(node) { + do { + node = node.parent; + } while (node && node.kind !== 205); + return node; + } + function emitContainingModuleName(node) { + var container = getContainingModule(node); + write(container ? getGeneratedNameForNode(container) : "exports"); + } + function emitModuleMemberName(node) { + emitStart(node.name); + if (ts.getCombinedNodeFlags(node) & 1) { + var container = getContainingModule(node); + if (container) { + write(getGeneratedNameForNode(container)); + write("."); + } + else if (languageVersion < 2) { + write("exports."); + } + } + emitNodeWithoutSourceMap(node.name); + emitEnd(node.name); + } + function createVoidZero() { + var zero = ts.createSynthesizedNode(7); + zero.text = "0"; + var result = ts.createSynthesizedNode(166); + result.expression = zero; + return result; + } + function emitExportMemberAssignment(node) { + if (node.flags & 1) { + writeLine(); + emitStart(node); + if (node.flags & 256) { + if (languageVersion === 0) { + write("exports[\"default\"]"); + } + else { + write("exports.default"); + } + } + else { + emitModuleMemberName(node); + } + write(" = "); + emitDeclarationName(node); + emitEnd(node); + write(";"); + } + } + function emitExportMemberAssignments(name) { + if (!exportEquals && exportSpecifiers && ts.hasProperty(exportSpecifiers, name.text)) { + for (var _a = 0, _b = exportSpecifiers[name.text]; _a < _b.length; _a++) { + var specifier = _b[_a]; + writeLine(); + emitStart(specifier.name); + emitContainingModuleName(specifier); + write("."); + emitNodeWithoutSourceMap(specifier.name); + emitEnd(specifier.name); + write(" = "); + emitExpressionIdentifier(name); + write(";"); + } + } + } + function emitDestructuring(root, isAssignmentExpressionStatement, value) { + var emitCount = 0; + var isDeclaration = (root.kind === 198 && !(ts.getCombinedNodeFlags(root) & 1)) || root.kind === 129; + if (root.kind === 169) { + emitAssignmentExpression(root); + } + else { + ts.Debug.assert(!isAssignmentExpressionStatement); + emitBindingElement(root, value); + } + function emitAssignment(name, value) { + if (emitCount++) { + write(", "); + } + renameNonTopLevelLetAndConst(name); + if (name.parent && (name.parent.kind === 198 || name.parent.kind === 152)) { + emitModuleMemberName(name.parent); + } + else { + emit(name); + } + write(" = "); + emit(value); + } + function ensureIdentifier(expr) { + if (expr.kind !== 65) { + var identifier = createTempVariable(0); + if (!isDeclaration) { + recordTempDeclaration(identifier); + } + emitAssignment(identifier, expr); + expr = identifier; + } + return expr; + } + function createDefaultValueCheck(value, defaultValue) { + value = ensureIdentifier(value); + var equals = ts.createSynthesizedNode(169); + equals.left = value; + equals.operatorToken = ts.createSynthesizedNode(30); + equals.right = createVoidZero(); + return createConditionalExpression(equals, defaultValue, value); + } + function createConditionalExpression(condition, whenTrue, whenFalse) { + var cond = ts.createSynthesizedNode(170); + cond.condition = condition; + cond.questionToken = ts.createSynthesizedNode(50); + cond.whenTrue = whenTrue; + cond.colonToken = ts.createSynthesizedNode(51); + cond.whenFalse = whenFalse; + return cond; + } + function createNumericLiteral(value) { + var node = ts.createSynthesizedNode(7); + node.text = "" + value; + return node; + } + function createPropertyAccessForDestructuringProperty(object, propName) { + if (propName.kind !== 65) { + return createElementAccessExpression(object, propName); + } + return createPropertyAccessExpression(object, propName); + } + function createSliceCall(value, sliceIndex) { + var call = ts.createSynthesizedNode(157); + var sliceIdentifier = ts.createSynthesizedNode(65); + sliceIdentifier.text = "slice"; + call.expression = createPropertyAccessExpression(value, sliceIdentifier); + call.arguments = ts.createSynthesizedNodeArray(); + call.arguments[0] = createNumericLiteral(sliceIndex); + return call; + } + function emitObjectLiteralAssignment(target, value) { + var properties = target.properties; + if (properties.length !== 1) { + value = ensureIdentifier(value); + } + for (var _a = 0; _a < properties.length; _a++) { + var p = properties[_a]; + if (p.kind === 224 || p.kind === 225) { + var propName = (p.name); + emitDestructuringAssignment(p.initializer || propName, createPropertyAccessForDestructuringProperty(value, propName)); + } + } + } + function emitArrayLiteralAssignment(target, value) { + var elements = target.elements; + if (elements.length !== 1) { + value = ensureIdentifier(value); + } + for (var i = 0; i < elements.length; i++) { + var e = elements[i]; + if (e.kind !== 175) { + if (e.kind !== 173) { + emitDestructuringAssignment(e, createElementAccessExpression(value, createNumericLiteral(i))); + } + else if (i === elements.length - 1) { + emitDestructuringAssignment(e.expression, createSliceCall(value, i)); + } + } + } + } + function emitDestructuringAssignment(target, value) { + if (target.kind === 169 && target.operatorToken.kind === 53) { + value = createDefaultValueCheck(value, target.right); + target = target.left; + } + if (target.kind === 154) { + emitObjectLiteralAssignment(target, value); + } + else if (target.kind === 153) { + emitArrayLiteralAssignment(target, value); + } + else { + emitAssignment(target, value); + } + } + function emitAssignmentExpression(root) { + var target = root.left; + var value = root.right; + if (isAssignmentExpressionStatement) { + emitDestructuringAssignment(target, value); + } + else { + if (root.parent.kind !== 161) { + write("("); + } + value = ensureIdentifier(value); + emitDestructuringAssignment(target, value); + write(", "); + emit(value); + if (root.parent.kind !== 161) { + write(")"); + } + } + } + function emitBindingElement(target, value) { + if (target.initializer) { + value = value ? createDefaultValueCheck(value, target.initializer) : target.initializer; + } + else if (!value) { + value = createVoidZero(); + } + if (ts.isBindingPattern(target.name)) { + var pattern = target.name; + var elements = pattern.elements; + if (elements.length !== 1) { + value = ensureIdentifier(value); + } + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + if (pattern.kind === 150) { + var propName = element.propertyName || element.name; + emitBindingElement(element, createPropertyAccessForDestructuringProperty(value, propName)); + } + else if (element.kind !== 175) { + if (!element.dotDotDotToken) { + emitBindingElement(element, createElementAccessExpression(value, createNumericLiteral(i))); + } + else if (i === elements.length - 1) { + emitBindingElement(element, createSliceCall(value, i)); + } + } + } + } + else { + emitAssignment(target.name, value); + } + } + } + function emitVariableDeclaration(node) { + if (ts.isBindingPattern(node.name)) { + if (languageVersion < 2) { + emitDestructuring(node, false); + } + else { + emit(node.name); + emitOptional(" = ", node.initializer); + } + } + else { + renameNonTopLevelLetAndConst(node.name); + emitModuleMemberName(node); + var initializer = node.initializer; + if (!initializer && languageVersion < 2) { + var isUninitializedLet = (resolver.getNodeCheckFlags(node) & 256) && + (getCombinedFlagsForIdentifier(node.name) & 4096); + if (isUninitializedLet && + node.parent.parent.kind !== 187 && + node.parent.parent.kind !== 188) { + initializer = createVoidZero(); + } + } + emitOptional(" = ", initializer); + } + } + function emitExportVariableAssignments(node) { + if (node.kind === 175) { + return; + } + var name = node.name; + if (name.kind === 65) { + emitExportMemberAssignments(name); + } + else if (ts.isBindingPattern(name)) { + ts.forEach(name.elements, emitExportVariableAssignments); + } + } + function getCombinedFlagsForIdentifier(node) { + if (!node.parent || (node.parent.kind !== 198 && node.parent.kind !== 152)) { + return 0; + } + return ts.getCombinedNodeFlags(node.parent); + } + function renameNonTopLevelLetAndConst(node) { + if (languageVersion >= 2 || + ts.nodeIsSynthesized(node) || + node.kind !== 65 || + (node.parent.kind !== 198 && node.parent.kind !== 152)) { + return; + } + var combinedFlags = getCombinedFlagsForIdentifier(node); + if (((combinedFlags & 12288) === 0) || combinedFlags & 1) { + return; + } + var list = ts.getAncestor(node, 199); + if (list.parent.kind === 180) { + var isSourceFileLevelBinding = list.parent.parent.kind === 227; + var isModuleLevelBinding = list.parent.parent.kind === 206; + var isFunctionLevelBinding = list.parent.parent.kind === 179 && ts.isFunctionLike(list.parent.parent.parent); + if (isSourceFileLevelBinding || isModuleLevelBinding || isFunctionLevelBinding) { + return; + } + } + var blockScopeContainer = ts.getEnclosingBlockScopeContainer(node); + var parent = blockScopeContainer.kind === 227 + ? blockScopeContainer + : blockScopeContainer.parent; + if (resolver.resolvesToSomeValue(parent, node.text)) { + var variableId = resolver.getBlockScopedVariableId(node); + if (!blockScopedVariableToGeneratedName) { + blockScopedVariableToGeneratedName = []; + } + var generatedName = makeUniqueName(node.text); + blockScopedVariableToGeneratedName[variableId] = generatedName; + } + } + function isES6ExportedDeclaration(node) { + return !!(node.flags & 1) && + languageVersion >= 2 && + node.parent.kind === 227; + } + function emitVariableStatement(node) { + if (!(node.flags & 1)) { + emitStartOfVariableDeclarationList(node.declarationList); + } + else if (isES6ExportedDeclaration(node)) { + write("export "); + emitStartOfVariableDeclarationList(node.declarationList); + } + emitCommaList(node.declarationList.declarations); + write(";"); + if (languageVersion < 2 && node.parent === currentSourceFile) { + ts.forEach(node.declarationList.declarations, emitExportVariableAssignments); + } + } + function emitParameter(node) { + if (languageVersion < 2) { + if (ts.isBindingPattern(node.name)) { + var name_5 = createTempVariable(0); + if (!tempParameters) { + tempParameters = []; + } + tempParameters.push(name_5); + emit(name_5); + } + else { + emit(node.name); + } + } + else { + if (node.dotDotDotToken) { + write("..."); + } + emit(node.name); + emitOptional(" = ", node.initializer); + } + } + function emitDefaultValueAssignments(node) { + if (languageVersion < 2) { + var tempIndex = 0; + ts.forEach(node.parameters, function (p) { + if (p.dotDotDotToken) { + return; + } + if (ts.isBindingPattern(p.name)) { + writeLine(); + write("var "); + emitDestructuring(p, false, tempParameters[tempIndex]); + write(";"); + tempIndex++; + } + else if (p.initializer) { + writeLine(); + emitStart(p); + write("if ("); + emitNodeWithoutSourceMap(p.name); + write(" === void 0)"); + emitEnd(p); + write(" { "); + emitStart(p); + emitNodeWithoutSourceMap(p.name); + write(" = "); + emitNodeWithoutSourceMap(p.initializer); + emitEnd(p); + write("; }"); + } + }); + } + } + function emitRestParameter(node) { + if (languageVersion < 2 && ts.hasRestParameters(node)) { + var restIndex = node.parameters.length - 1; + var restParam = node.parameters[restIndex]; + if (ts.isBindingPattern(restParam.name)) { + return; + } + var tempName = createTempVariable(268435456).text; + writeLine(); + emitLeadingComments(restParam); + emitStart(restParam); + write("var "); + emitNodeWithoutSourceMap(restParam.name); + write(" = [];"); + emitEnd(restParam); + emitTrailingComments(restParam); + writeLine(); + write("for ("); + emitStart(restParam); + write("var " + tempName + " = " + restIndex + ";"); + emitEnd(restParam); + write(" "); + emitStart(restParam); + write(tempName + " < arguments.length;"); + emitEnd(restParam); + write(" "); + emitStart(restParam); + write(tempName + "++"); + emitEnd(restParam); + write(") {"); + increaseIndent(); + writeLine(); + emitStart(restParam); + emitNodeWithoutSourceMap(restParam.name); + write("[" + tempName + " - " + restIndex + "] = arguments[" + tempName + "];"); + emitEnd(restParam); + decreaseIndent(); + writeLine(); + write("}"); + } + } + function emitAccessor(node) { + write(node.kind === 136 ? "get " : "set "); + emit(node.name, false); + emitSignatureAndBody(node); + } + function shouldEmitAsArrowFunction(node) { + return node.kind === 163 && languageVersion >= 2; + } + function emitDeclarationName(node) { + if (node.name) { + emitNodeWithoutSourceMap(node.name); + } + else { + write(getGeneratedNameForNode(node)); + } + } + function shouldEmitFunctionName(node) { + if (node.kind === 162) { + return !!node.name; + } + if (node.kind === 200) { + return !!node.name || languageVersion < 2; + } + } + function emitFunctionDeclaration(node) { + if (ts.nodeIsMissing(node.body)) { + return emitOnlyPinnedOrTripleSlashComments(node); + } + if (node.kind !== 134 && node.kind !== 133) { + emitLeadingComments(node); + } + if (!shouldEmitAsArrowFunction(node)) { + if (isES6ExportedDeclaration(node)) { + write("export "); + if (node.flags & 256) { + write("default "); + } + } + write("function"); + if (languageVersion >= 2 && node.asteriskToken) { + write("*"); + } + write(" "); + } + if (shouldEmitFunctionName(node)) { + emitDeclarationName(node); + } + emitSignatureAndBody(node); + if (languageVersion < 2 && node.kind === 200 && node.parent === currentSourceFile && node.name) { + emitExportMemberAssignments(node.name); + } + if (node.kind !== 134 && node.kind !== 133) { + emitTrailingComments(node); + } + } + function emitCaptureThisForNodeIfNecessary(node) { + if (resolver.getNodeCheckFlags(node) & 4) { + writeLine(); + emitStart(node); + write("var _this = this;"); + emitEnd(node); + } + } + function emitSignatureParameters(node) { + increaseIndent(); + write("("); + if (node) { + var parameters = node.parameters; + var omitCount = languageVersion < 2 && ts.hasRestParameters(node) ? 1 : 0; + emitList(parameters, 0, parameters.length - omitCount, false, false); + } + write(")"); + decreaseIndent(); + } + function emitSignatureParametersForArrow(node) { + if (node.parameters.length === 1 && node.pos === node.parameters[0].pos) { + emit(node.parameters[0]); + return; + } + emitSignatureParameters(node); + } + function emitSignatureAndBody(node) { + var saveTempFlags = tempFlags; + var saveTempVariables = tempVariables; + var saveTempParameters = tempParameters; + tempFlags = 0; + tempVariables = undefined; + tempParameters = undefined; + if (shouldEmitAsArrowFunction(node)) { + emitSignatureParametersForArrow(node); + write(" =>"); + } + else { + emitSignatureParameters(node); + } + if (!node.body) { + write(" { }"); + } + else if (node.body.kind === 179) { + emitBlockFunctionBody(node, node.body); + } + else { + emitExpressionFunctionBody(node, node.body); + } + if (!isES6ExportedDeclaration(node)) { + emitExportMemberAssignment(node); + } + tempFlags = saveTempFlags; + tempVariables = saveTempVariables; + tempParameters = saveTempParameters; + } + function emitFunctionBodyPreamble(node) { + emitCaptureThisForNodeIfNecessary(node); + emitDefaultValueAssignments(node); + emitRestParameter(node); + } + function emitExpressionFunctionBody(node, body) { + if (languageVersion < 2) { + emitDownLevelExpressionFunctionBody(node, body); + return; + } + write(" "); + var current = body; + while (current.kind === 160) { + current = current.expression; + } + emitParenthesizedIf(body, current.kind === 154); + } + function emitDownLevelExpressionFunctionBody(node, body) { + write(" {"); + scopeEmitStart(node); + increaseIndent(); + var outPos = writer.getTextPos(); + emitDetachedComments(node.body); + emitFunctionBodyPreamble(node); + var preambleEmitted = writer.getTextPos() !== outPos; + decreaseIndent(); + if (!preambleEmitted && nodeStartPositionsAreOnSameLine(node, body)) { + write(" "); + emitStart(body); + write("return "); + emit(body); + emitEnd(body); + write(";"); + emitTempDeclarations(false); + write(" "); + } + else { + increaseIndent(); + writeLine(); + emitLeadingComments(node.body); + write("return "); + emit(body); + write(";"); + emitTrailingComments(node.body); + emitTempDeclarations(true); + decreaseIndent(); + writeLine(); + } + emitStart(node.body); + write("}"); + emitEnd(node.body); + scopeEmitEnd(); + } + function emitBlockFunctionBody(node, body) { + write(" {"); + scopeEmitStart(node); + var initialTextPos = writer.getTextPos(); + increaseIndent(); + emitDetachedComments(body.statements); + var startIndex = emitDirectivePrologues(body.statements, true); + emitFunctionBodyPreamble(node); + decreaseIndent(); + var preambleEmitted = writer.getTextPos() !== initialTextPos; + if (!preambleEmitted && nodeEndIsOnSameLineAsNodeStart(body, body)) { + for (var _a = 0, _b = body.statements; _a < _b.length; _a++) { + var statement = _b[_a]; + write(" "); + emit(statement); + } + emitTempDeclarations(false); + write(" "); + emitLeadingCommentsOfPosition(body.statements.end); + } + else { + increaseIndent(); + emitLinesStartingAt(body.statements, startIndex); + emitTempDeclarations(true); + writeLine(); + emitLeadingCommentsOfPosition(body.statements.end); + decreaseIndent(); + } + emitToken(15, body.statements.end); + scopeEmitEnd(); + } + function findInitialSuperCall(ctor) { + if (ctor.body) { + var statement = ctor.body.statements[0]; + if (statement && statement.kind === 182) { + var expr = statement.expression; + if (expr && expr.kind === 157) { + var func = expr.expression; + if (func && func.kind === 91) { + return statement; + } + } + } + } + } + function emitParameterPropertyAssignments(node) { + ts.forEach(node.parameters, function (param) { + if (param.flags & 112) { + writeLine(); + emitStart(param); + emitStart(param.name); + write("this."); + emitNodeWithoutSourceMap(param.name); + emitEnd(param.name); + write(" = "); + emit(param.name); + write(";"); + emitEnd(param); + } + }); + } + function emitMemberAccessForPropertyName(memberName) { + if (memberName.kind === 8 || memberName.kind === 7) { + write("["); + emitNodeWithoutSourceMap(memberName); + write("]"); + } + else if (memberName.kind === 127) { + emitComputedPropertyName(memberName); + } + else { + write("."); + emitNodeWithoutSourceMap(memberName); + } + } + function getInitializedProperties(node, static) { + var properties = []; + for (var _a = 0, _b = node.members; _a < _b.length; _a++) { + var member = _b[_a]; + if (member.kind === 132 && static === ((member.flags & 128) !== 0) && member.initializer) { + properties.push(member); + } + } + return properties; + } + function emitPropertyDeclarations(node, properties) { + for (var _a = 0; _a < properties.length; _a++) { + var property = properties[_a]; + emitPropertyDeclaration(node, property); + } + } + function emitPropertyDeclaration(node, property, receiver, isExpression) { + writeLine(); + emitLeadingComments(property); + emitStart(property); + emitStart(property.name); + if (receiver) { + emit(receiver); + } + else { + if (property.flags & 128) { + emitDeclarationName(node); + } + else { + write("this"); + } + } + emitMemberAccessForPropertyName(property.name); + emitEnd(property.name); + write(" = "); + emit(property.initializer); + if (!isExpression) { + write(";"); + } + emitEnd(property); + emitTrailingComments(property); + } + function emitMemberFunctionsForES5AndLower(node) { + ts.forEach(node.members, function (member) { + if (member.kind === 178) { + writeLine(); + write(";"); + } + else if (member.kind === 134 || node.kind === 133) { + if (!member.body) { + return emitOnlyPinnedOrTripleSlashComments(member); + } + writeLine(); + emitLeadingComments(member); + emitStart(member); + emitStart(member.name); + emitClassMemberPrefix(node, member); + emitMemberAccessForPropertyName(member.name); + emitEnd(member.name); + write(" = "); + emitStart(member); + emitFunctionDeclaration(member); + emitEnd(member); + emitEnd(member); + write(";"); + emitTrailingComments(member); + } + else if (member.kind === 136 || member.kind === 137) { + var accessors = ts.getAllAccessorDeclarations(node.members, member); + if (member === accessors.firstAccessor) { + writeLine(); + emitStart(member); + write("Object.defineProperty("); + emitStart(member.name); + emitClassMemberPrefix(node, member); + write(", "); + emitExpressionForPropertyName(member.name); + emitEnd(member.name); + write(", {"); + increaseIndent(); + if (accessors.getAccessor) { + writeLine(); + emitLeadingComments(accessors.getAccessor); + write("get: "); + emitStart(accessors.getAccessor); + write("function "); + emitSignatureAndBody(accessors.getAccessor); + emitEnd(accessors.getAccessor); + emitTrailingComments(accessors.getAccessor); + write(","); + } + if (accessors.setAccessor) { + writeLine(); + emitLeadingComments(accessors.setAccessor); + write("set: "); + emitStart(accessors.setAccessor); + write("function "); + emitSignatureAndBody(accessors.setAccessor); + emitEnd(accessors.setAccessor); + emitTrailingComments(accessors.setAccessor); + write(","); + } + writeLine(); + write("enumerable: true,"); + writeLine(); + write("configurable: true"); + decreaseIndent(); + writeLine(); + write("});"); + emitEnd(member); + } + } + }); + } + function emitMemberFunctionsForES6AndHigher(node) { + for (var _a = 0, _b = node.members; _a < _b.length; _a++) { + var member = _b[_a]; + if ((member.kind === 134 || node.kind === 133) && !member.body) { + emitOnlyPinnedOrTripleSlashComments(member); + } + else if (member.kind === 134 || + member.kind === 136 || + member.kind === 137) { + writeLine(); + emitLeadingComments(member); + emitStart(member); + if (member.flags & 128) { + write("static "); + } + if (member.kind === 136) { + write("get "); + } + else if (member.kind === 137) { + write("set "); + } + if (member.asteriskToken) { + write("*"); + } + emit(member.name); + emitSignatureAndBody(member); + emitEnd(member); + emitTrailingComments(member); + } + else if (member.kind === 178) { + writeLine(); + write(";"); + } + } + } + function emitConstructor(node, baseTypeElement) { + var saveTempFlags = tempFlags; + var saveTempVariables = tempVariables; + var saveTempParameters = tempParameters; + tempFlags = 0; + tempVariables = undefined; + tempParameters = undefined; + emitConstructorWorker(node, baseTypeElement); + tempFlags = saveTempFlags; + tempVariables = saveTempVariables; + tempParameters = saveTempParameters; + } + function emitConstructorWorker(node, baseTypeElement) { + var hasInstancePropertyWithInitializer = false; + ts.forEach(node.members, function (member) { + if (member.kind === 135 && !member.body) { + emitOnlyPinnedOrTripleSlashComments(member); + } + if (member.kind === 132 && member.initializer && (member.flags & 128) === 0) { + hasInstancePropertyWithInitializer = true; + } + }); + var ctor = ts.getFirstConstructorWithBody(node); + if (languageVersion >= 2 && !ctor && !hasInstancePropertyWithInitializer) { + return; + } + if (ctor) { + emitLeadingComments(ctor); + } + emitStart(ctor || node); + if (languageVersion < 2) { + write("function "); + emitDeclarationName(node); + emitSignatureParameters(ctor); + } + else { + write("constructor"); + if (ctor) { + emitSignatureParameters(ctor); + } + else { + if (baseTypeElement) { + write("(...args)"); + } + else { + write("()"); + } + } + } + write(" {"); + scopeEmitStart(node, "constructor"); + increaseIndent(); + if (ctor) { + emitDetachedComments(ctor.body.statements); + } + emitCaptureThisForNodeIfNecessary(node); + if (ctor) { + emitDefaultValueAssignments(ctor); + emitRestParameter(ctor); + if (baseTypeElement) { + var superCall = findInitialSuperCall(ctor); + if (superCall) { + writeLine(); + emit(superCall); + } + } + emitParameterPropertyAssignments(ctor); + } + else { + if (baseTypeElement) { + writeLine(); + emitStart(baseTypeElement); + if (languageVersion < 2) { + write("_super.apply(this, arguments);"); + } + else { + write("super(...args);"); + } + emitEnd(baseTypeElement); + } + } + emitPropertyDeclarations(node, getInitializedProperties(node, false)); + if (ctor) { + var statements = ctor.body.statements; + if (superCall) { + statements = statements.slice(1); + } + emitLines(statements); + } + emitTempDeclarations(true); + writeLine(); + if (ctor) { + emitLeadingCommentsOfPosition(ctor.body.statements.end); + } + decreaseIndent(); + emitToken(15, ctor ? ctor.body.statements.end : node.members.end); + scopeEmitEnd(); + emitEnd(ctor || node); + if (ctor) { + emitTrailingComments(ctor); + } + } + function emitClassExpression(node) { + return emitClassLikeDeclaration(node); + } + function emitClassDeclaration(node) { + return emitClassLikeDeclaration(node); + } + function emitClassLikeDeclaration(node) { + if (languageVersion < 2) { + emitClassLikeDeclarationBelowES6(node); + } + else { + emitClassLikeDeclarationForES6AndHigher(node); + } + } + function emitClassLikeDeclarationForES6AndHigher(node) { + var thisNodeIsDecorated = ts.nodeIsDecorated(node); + if (node.kind === 201) { + if (thisNodeIsDecorated) { + if (isES6ExportedDeclaration(node) && !(node.flags & 256)) { + write("export "); + } + write("let "); + emitDeclarationName(node); + write(" = "); + } + else if (isES6ExportedDeclaration(node)) { + write("export "); + if (node.flags & 256) { + write("default "); + } + } + } + var staticProperties = getInitializedProperties(node, true); + var isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === 174; + var tempVariable; + if (isClassExpressionWithStaticProperties) { + tempVariable = createAndRecordTempVariable(0); + write("("); + increaseIndent(); + emit(tempVariable); + write(" = "); + } + write("class"); + if ((node.name || !(node.flags & 256)) && !thisNodeIsDecorated) { + write(" "); + emitDeclarationName(node); + } + var baseTypeNode = ts.getClassExtendsHeritageClauseElement(node); + if (baseTypeNode) { + write(" extends "); + emit(baseTypeNode.expression); + } + write(" {"); + increaseIndent(); + scopeEmitStart(node); + writeLine(); + emitConstructor(node, baseTypeNode); + emitMemberFunctionsForES6AndHigher(node); + decreaseIndent(); + writeLine(); + emitToken(15, node.members.end); + scopeEmitEnd(); + if (thisNodeIsDecorated) { + write(";"); + if (node.name) { + writeLine(); + write("Object.defineProperty("); + emitDeclarationName(node); + write(", \"name\", { value: \""); + emitDeclarationName(node); + write("\", configurable: true });"); + writeLine(); + } + } + if (isClassExpressionWithStaticProperties) { + for (var _a = 0; _a < staticProperties.length; _a++) { + var property = staticProperties[_a]; + write(","); + writeLine(); + emitPropertyDeclaration(node, property, tempVariable, true); + } + write(","); + writeLine(); + emit(tempVariable); + decreaseIndent(); + write(")"); + } + else { + writeLine(); + emitPropertyDeclarations(node, staticProperties); + emitDecoratorsOfClass(node); + } + if (!isES6ExportedDeclaration(node) && (node.flags & 1)) { + writeLine(); + emitStart(node); + emitModuleMemberName(node); + write(" = "); + emitDeclarationName(node); + emitEnd(node); + write(";"); + } + else if (isES6ExportedDeclaration(node) && (node.flags & 256) && thisNodeIsDecorated) { + writeLine(); + write("export default "); + emitDeclarationName(node); + write(";"); + } + } + function emitClassLikeDeclarationBelowES6(node) { + if (node.kind === 201) { + write("var "); + emitDeclarationName(node); + write(" = "); + } + write("(function ("); + var baseTypeNode = ts.getClassExtendsHeritageClauseElement(node); + if (baseTypeNode) { + write("_super"); + } + write(") {"); + var saveTempFlags = tempFlags; + var saveTempVariables = tempVariables; + var saveTempParameters = tempParameters; + var saveComputedPropertyNamesToGeneratedNames = computedPropertyNamesToGeneratedNames; + tempFlags = 0; + tempVariables = undefined; + tempParameters = undefined; + computedPropertyNamesToGeneratedNames = undefined; + increaseIndent(); + scopeEmitStart(node); + if (baseTypeNode) { + writeLine(); + emitStart(baseTypeNode); + write("__extends("); + emitDeclarationName(node); + write(", _super);"); + emitEnd(baseTypeNode); + } + writeLine(); + emitConstructor(node, baseTypeNode); + emitMemberFunctionsForES5AndLower(node); + emitPropertyDeclarations(node, getInitializedProperties(node, true)); + writeLine(); + emitDecoratorsOfClass(node); + writeLine(); + emitToken(15, node.members.end, function () { + write("return "); + emitDeclarationName(node); + }); + write(";"); + emitTempDeclarations(true); + tempFlags = saveTempFlags; + tempVariables = saveTempVariables; + tempParameters = saveTempParameters; + computedPropertyNamesToGeneratedNames = saveComputedPropertyNamesToGeneratedNames; + decreaseIndent(); + writeLine(); + emitToken(15, node.members.end); + scopeEmitEnd(); + emitStart(node); + write(")("); + if (baseTypeNode) { + emit(baseTypeNode.expression); + } + write(")"); + if (node.kind === 201) { + write(";"); + } + emitEnd(node); + if (node.kind === 201) { + emitExportMemberAssignment(node); + } + if (languageVersion < 2 && node.parent === currentSourceFile && node.name) { + emitExportMemberAssignments(node.name); + } + } + function emitClassMemberPrefix(node, member) { + emitDeclarationName(node); + if (!(member.flags & 128)) { + write(".prototype"); + } + } + function emitDecoratorsOfClass(node) { + emitDecoratorsOfMembers(node, 0); + emitDecoratorsOfMembers(node, 128); + emitDecoratorsOfConstructor(node); + } + function emitDecoratorsOfConstructor(node) { + var decorators = node.decorators; + var constructor = ts.getFirstConstructorWithBody(node); + var hasDecoratedParameters = constructor && ts.forEach(constructor.parameters, ts.nodeIsDecorated); + if (!decorators && !hasDecoratedParameters) { + return; + } + writeLine(); + emitStart(node); + emitDeclarationName(node); + write(" = __decorate(["); + increaseIndent(); + writeLine(); + var decoratorCount = decorators ? decorators.length : 0; + var argumentsWritten = emitList(decorators, 0, decoratorCount, true, false, false, true, function (decorator) { + emitStart(decorator); + emit(decorator.expression); + emitEnd(decorator); + }); + argumentsWritten += emitDecoratorsOfParameters(constructor, argumentsWritten > 0); + emitSerializedTypeMetadata(node, argumentsWritten >= 0); + decreaseIndent(); + writeLine(); + write("], "); + emitDeclarationName(node); + write(");"); + emitEnd(node); + writeLine(); + } + function emitDecoratorsOfMembers(node, staticFlag) { + for (var _a = 0, _b = node.members; _a < _b.length; _a++) { + var member = _b[_a]; + if ((member.flags & 128) !== staticFlag) { + continue; + } + if (!ts.nodeCanBeDecorated(member)) { + continue; + } + if (!ts.nodeOrChildIsDecorated(member)) { + continue; + } + var decorators = void 0; + var functionLikeMember = void 0; + if (ts.isAccessor(member)) { + var accessors = ts.getAllAccessorDeclarations(node.members, member); + if (member !== accessors.firstAccessor) { + continue; + } + decorators = accessors.firstAccessor.decorators; + if (!decorators && accessors.secondAccessor) { + decorators = accessors.secondAccessor.decorators; + } + functionLikeMember = accessors.setAccessor; + } + else { + decorators = member.decorators; + if (member.kind === 134) { + functionLikeMember = member; + } + } + writeLine(); + emitStart(member); + if (member.kind !== 132) { + write("Object.defineProperty("); + emitStart(member.name); + emitClassMemberPrefix(node, member); + write(", "); + emitExpressionForPropertyName(member.name); + emitEnd(member.name); + write(","); + increaseIndent(); + writeLine(); + } + write("__decorate(["); + increaseIndent(); + writeLine(); + var decoratorCount = decorators ? decorators.length : 0; + var argumentsWritten = emitList(decorators, 0, decoratorCount, true, false, false, true, function (decorator) { + emitStart(decorator); + emit(decorator.expression); + emitEnd(decorator); + }); + argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0); + emitSerializedTypeMetadata(member, argumentsWritten > 0); + decreaseIndent(); + writeLine(); + write("], "); + emitStart(member.name); + emitClassMemberPrefix(node, member); + write(", "); + emitExpressionForPropertyName(member.name); + emitEnd(member.name); + if (member.kind !== 132) { + write(", Object.getOwnPropertyDescriptor("); + emitStart(member.name); + emitClassMemberPrefix(node, member); + write(", "); + emitExpressionForPropertyName(member.name); + emitEnd(member.name); + write("))"); + decreaseIndent(); + } + write(");"); + emitEnd(member); + writeLine(); + } + } + function emitDecoratorsOfParameters(node, leadingComma) { + var argumentsWritten = 0; + if (node) { + var parameterIndex = 0; + for (var _a = 0, _b = node.parameters; _a < _b.length; _a++) { + var parameter = _b[_a]; + if (ts.nodeIsDecorated(parameter)) { + var decorators = parameter.decorators; + argumentsWritten += emitList(decorators, 0, decorators.length, true, false, leadingComma, true, function (decorator) { + emitStart(decorator); + write("__param(" + parameterIndex + ", "); + emit(decorator.expression); + write(")"); + emitEnd(decorator); + }); + leadingComma = true; + } + ++parameterIndex; + } + } + return argumentsWritten; + } + function shouldEmitTypeMetadata(node) { + switch (node.kind) { + case 134: + case 136: + case 137: + case 132: + return true; + } + return false; + } + function shouldEmitReturnTypeMetadata(node) { + switch (node.kind) { + case 134: + return true; + } + return false; + } + function shouldEmitParamTypesMetadata(node) { + switch (node.kind) { + case 201: + case 134: + case 137: + return true; + } + return false; + } + function emitSerializedTypeMetadata(node, writeComma) { + var argumentsWritten = 0; + if (compilerOptions.emitDecoratorMetadata) { + if (shouldEmitTypeMetadata(node)) { + var serializedType = resolver.serializeTypeOfNode(node, getGeneratedNameForNode); + if (serializedType) { + if (writeComma) { + write(", "); + } + writeLine(); + write("__metadata('design:type', "); + emitSerializedType(node, serializedType); + write(")"); + argumentsWritten++; + } + } + if (shouldEmitParamTypesMetadata(node)) { + var serializedTypes = resolver.serializeParameterTypesOfNode(node, getGeneratedNameForNode); + if (serializedTypes) { + if (writeComma || argumentsWritten) { + write(", "); + } + writeLine(); + write("__metadata('design:paramtypes', ["); + for (var i = 0; i < serializedTypes.length; ++i) { + if (i > 0) { + write(", "); + } + emitSerializedType(node, serializedTypes[i]); + } + write("])"); + argumentsWritten++; + } + } + if (shouldEmitReturnTypeMetadata(node)) { + var serializedType = resolver.serializeReturnTypeOfNode(node, getGeneratedNameForNode); + if (serializedType) { + if (writeComma || argumentsWritten) { + write(", "); + } + writeLine(); + write("__metadata('design:returntype', "); + emitSerializedType(node, serializedType); + write(")"); + argumentsWritten++; + } + } + } + return argumentsWritten; + } + function serializeTypeNameSegment(location, path, index) { + switch (index) { + case 0: + return "typeof " + path[index] + " !== 'undefined' && " + path[index]; + case 1: + return serializeTypeNameSegment(location, path, index - 1) + "." + path[index]; + default: + var temp = createAndRecordTempVariable(0).text; + return "(" + temp + " = " + serializeTypeNameSegment(location, path, index - 1) + ") && " + temp + "." + path[index]; + } + } + function emitSerializedType(location, name) { + if (typeof name === "string") { + write(name); + return; + } + else { + ts.Debug.assert(name.length > 0, "Invalid serialized type name"); + write("(" + serializeTypeNameSegment(location, name, name.length - 1) + ") || Object"); + } + } + function emitInterfaceDeclaration(node) { + emitOnlyPinnedOrTripleSlashComments(node); + } + function shouldEmitEnumDeclaration(node) { + var isConstEnum = ts.isConst(node); + return !isConstEnum || compilerOptions.preserveConstEnums || compilerOptions.separateCompilation; + } + function emitEnumDeclaration(node) { + if (!shouldEmitEnumDeclaration(node)) { + return; + } + if (!(node.flags & 1) || isES6ExportedDeclaration(node)) { + emitStart(node); + if (isES6ExportedDeclaration(node)) { + write("export "); + } + write("var "); + emit(node.name); + emitEnd(node); + write(";"); + } + writeLine(); + emitStart(node); + write("(function ("); + emitStart(node.name); + write(getGeneratedNameForNode(node)); + emitEnd(node.name); + write(") {"); + increaseIndent(); + scopeEmitStart(node); + emitLines(node.members); + decreaseIndent(); + writeLine(); + emitToken(15, node.members.end); + scopeEmitEnd(); + write(")("); + emitModuleMemberName(node); + write(" || ("); + emitModuleMemberName(node); + write(" = {}));"); + emitEnd(node); + if (!isES6ExportedDeclaration(node) && node.flags & 1) { + writeLine(); + emitStart(node); + write("var "); + emit(node.name); + write(" = "); + emitModuleMemberName(node); + emitEnd(node); + write(";"); + } + if (languageVersion < 2 && node.parent === currentSourceFile) { + emitExportMemberAssignments(node.name); + } + } + function emitEnumMember(node) { + var enumParent = node.parent; + emitStart(node); + write(getGeneratedNameForNode(enumParent)); + write("["); + write(getGeneratedNameForNode(enumParent)); + write("["); + emitExpressionForPropertyName(node.name); + write("] = "); + writeEnumMemberDeclarationValue(node); + write("] = "); + emitExpressionForPropertyName(node.name); + emitEnd(node); + write(";"); + } + function writeEnumMemberDeclarationValue(member) { + var value = resolver.getConstantValue(member); + if (value !== undefined) { + write(value.toString()); + return; + } + else if (member.initializer) { + emit(member.initializer); + } + else { + write("undefined"); + } + } + function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration) { + if (moduleDeclaration.body.kind === 205) { + var recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration.body); + return recursiveInnerModule || moduleDeclaration.body; + } + } + function shouldEmitModuleDeclaration(node) { + return ts.isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.separateCompilation); + } + function isModuleMergedWithES6Class(node) { + return languageVersion === 2 && !!(resolver.getNodeCheckFlags(node) & 2048); + } + function emitModuleDeclaration(node) { + var shouldEmit = shouldEmitModuleDeclaration(node); + if (!shouldEmit) { + return emitOnlyPinnedOrTripleSlashComments(node); + } + if (!isModuleMergedWithES6Class(node)) { + emitStart(node); + if (isES6ExportedDeclaration(node)) { + write("export "); + } + write("var "); + emit(node.name); + write(";"); + emitEnd(node); + writeLine(); + } + emitStart(node); + write("(function ("); + emitStart(node.name); + write(getGeneratedNameForNode(node)); + emitEnd(node.name); + write(") "); + if (node.body.kind === 206) { + var saveTempFlags = tempFlags; + var saveTempVariables = tempVariables; + tempFlags = 0; + tempVariables = undefined; + emit(node.body); + tempFlags = saveTempFlags; + tempVariables = saveTempVariables; + } + else { + write("{"); + increaseIndent(); + scopeEmitStart(node); + emitCaptureThisForNodeIfNecessary(node); + writeLine(); + emit(node.body); + decreaseIndent(); + writeLine(); + var moduleBlock = getInnerMostModuleDeclarationFromDottedModule(node).body; + emitToken(15, moduleBlock.statements.end); + scopeEmitEnd(); + } + write(")("); + if ((node.flags & 1) && !isES6ExportedDeclaration(node)) { + emit(node.name); + write(" = "); + } + emitModuleMemberName(node); + write(" || ("); + emitModuleMemberName(node); + write(" = {}));"); + emitEnd(node); + if (!isES6ExportedDeclaration(node) && node.name.kind === 65 && node.parent === currentSourceFile) { + emitExportMemberAssignments(node.name); + } + } + function emitRequire(moduleName) { + if (moduleName.kind === 8) { + write("require("); + emitStart(moduleName); + emitLiteral(moduleName); + emitEnd(moduleName); + emitToken(17, moduleName.end); + } + else { + write("require()"); + } + } + function getNamespaceDeclarationNode(node) { + if (node.kind === 208) { + return node; + } + var importClause = node.importClause; + if (importClause && importClause.namedBindings && importClause.namedBindings.kind === 211) { + return importClause.namedBindings; + } + } + function isDefaultImport(node) { + return node.kind === 209 && node.importClause && !!node.importClause.name; + } + function emitExportImportAssignments(node) { + if (ts.isAliasSymbolDeclaration(node) && resolver.isValueAliasDeclaration(node)) { + emitExportMemberAssignments(node.name); + } + ts.forEachChild(node, emitExportImportAssignments); + } + function emitImportDeclaration(node) { + if (languageVersion < 2) { + return emitExternalImportDeclaration(node); + } + if (node.importClause) { + var shouldEmitDefaultBindings = resolver.isReferencedAliasDeclaration(node.importClause); + var shouldEmitNamedBindings = node.importClause.namedBindings && resolver.isReferencedAliasDeclaration(node.importClause.namedBindings, true); + if (shouldEmitDefaultBindings || shouldEmitNamedBindings) { + write("import "); + emitStart(node.importClause); + if (shouldEmitDefaultBindings) { + emit(node.importClause.name); + if (shouldEmitNamedBindings) { + write(", "); + } + } + if (shouldEmitNamedBindings) { + emitLeadingComments(node.importClause.namedBindings); + emitStart(node.importClause.namedBindings); + if (node.importClause.namedBindings.kind === 211) { + write("* as "); + emit(node.importClause.namedBindings.name); + } + else { + write("{ "); + emitExportOrImportSpecifierList(node.importClause.namedBindings.elements, resolver.isReferencedAliasDeclaration); + write(" }"); + } + emitEnd(node.importClause.namedBindings); + emitTrailingComments(node.importClause.namedBindings); + } + emitEnd(node.importClause); + write(" from "); + emit(node.moduleSpecifier); + write(";"); + } + } + else { + write("import "); + emit(node.moduleSpecifier); + write(";"); + } + } + function emitExternalImportDeclaration(node) { + if (ts.contains(externalImports, node)) { + var isExportedImport = node.kind === 208 && (node.flags & 1) !== 0; + var namespaceDeclaration = getNamespaceDeclarationNode(node); + if (compilerOptions.module !== 2) { + emitLeadingComments(node); + emitStart(node); + if (namespaceDeclaration && !isDefaultImport(node)) { + if (!isExportedImport) + write("var "); + emitModuleMemberName(namespaceDeclaration); + write(" = "); + } + else { + var isNakedImport = 209 && !node.importClause; + if (!isNakedImport) { + write("var "); + write(getGeneratedNameForNode(node)); + write(" = "); + } + } + emitRequire(ts.getExternalModuleName(node)); + if (namespaceDeclaration && isDefaultImport(node)) { + write(", "); + emitModuleMemberName(namespaceDeclaration); + write(" = "); + write(getGeneratedNameForNode(node)); + } + write(";"); + emitEnd(node); + emitExportImportAssignments(node); + emitTrailingComments(node); + } + else { + if (isExportedImport) { + emitModuleMemberName(namespaceDeclaration); + write(" = "); + emit(namespaceDeclaration.name); + write(";"); + } + else if (namespaceDeclaration && isDefaultImport(node)) { + write("var "); + emitModuleMemberName(namespaceDeclaration); + write(" = "); + write(getGeneratedNameForNode(node)); + write(";"); + } + emitExportImportAssignments(node); + } + } + } + function emitImportEqualsDeclaration(node) { + if (ts.isExternalModuleImportEqualsDeclaration(node)) { + emitExternalImportDeclaration(node); + return; + } + if (resolver.isReferencedAliasDeclaration(node) || + (!ts.isExternalModule(currentSourceFile) && resolver.isTopLevelValueImportEqualsWithEntityName(node))) { + emitLeadingComments(node); + emitStart(node); + if (isES6ExportedDeclaration(node)) { + write("export "); + write("var "); + } + else if (!(node.flags & 1)) { + write("var "); + } + emitModuleMemberName(node); + write(" = "); + emit(node.moduleReference); + write(";"); + emitEnd(node); + emitExportImportAssignments(node); + emitTrailingComments(node); + } + } + function emitExportDeclaration(node) { + if (languageVersion < 2) { + if (node.moduleSpecifier && (!node.exportClause || resolver.isValueAliasDeclaration(node))) { + emitStart(node); + var generatedName = getGeneratedNameForNode(node); + if (node.exportClause) { + if (compilerOptions.module !== 2) { + write("var "); + write(generatedName); + write(" = "); + emitRequire(ts.getExternalModuleName(node)); + write(";"); + } + for (var _a = 0, _b = node.exportClause.elements; _a < _b.length; _a++) { + var specifier = _b[_a]; + if (resolver.isValueAliasDeclaration(specifier)) { + writeLine(); + emitStart(specifier); + emitContainingModuleName(specifier); + write("."); + emitNodeWithoutSourceMap(specifier.name); + write(" = "); + write(generatedName); + write("."); + emitNodeWithoutSourceMap(specifier.propertyName || specifier.name); + write(";"); + emitEnd(specifier); + } + } + } + else { + writeLine(); + write("__export("); + if (compilerOptions.module !== 2) { + emitRequire(ts.getExternalModuleName(node)); + } + else { + write(generatedName); + } + write(");"); + } + emitEnd(node); + } + } + else { + if (!node.exportClause || resolver.isValueAliasDeclaration(node)) { + emitStart(node); + write("export "); + if (node.exportClause) { + write("{ "); + emitExportOrImportSpecifierList(node.exportClause.elements, resolver.isValueAliasDeclaration); + write(" }"); + } + else { + write("*"); + } + if (node.moduleSpecifier) { + write(" from "); + emitNodeWithoutSourceMap(node.moduleSpecifier); + } + write(";"); + emitEnd(node); + } + } + } + function emitExportOrImportSpecifierList(specifiers, shouldEmit) { + ts.Debug.assert(languageVersion >= 2); + var needsComma = false; + for (var _a = 0; _a < specifiers.length; _a++) { + var specifier = specifiers[_a]; + if (shouldEmit(specifier)) { + if (needsComma) { + write(", "); + } + emitStart(specifier); + if (specifier.propertyName) { + emitNodeWithoutSourceMap(specifier.propertyName); + write(" as "); + } + emitNodeWithoutSourceMap(specifier.name); + emitEnd(specifier); + needsComma = true; + } + } + } + function emitExportAssignment(node) { + if (!node.isExportEquals && resolver.isValueAliasDeclaration(node)) { + if (languageVersion >= 2) { + writeLine(); + emitStart(node); + write("export default "); + var expression = node.expression; + emit(expression); + if (expression.kind !== 200 && + expression.kind !== 201) { + write(";"); + } + emitEnd(node); + } + else { + writeLine(); + emitStart(node); + emitContainingModuleName(node); + if (languageVersion === 0) { + write("[\"default\"] = "); + } + else { + write(".default = "); + } + emit(node.expression); + write(";"); + emitEnd(node); + } + } + } + function collectExternalModuleInfo(sourceFile) { + externalImports = []; + exportSpecifiers = {}; + exportEquals = undefined; + hasExportStars = false; + for (var _a = 0, _b = sourceFile.statements; _a < _b.length; _a++) { + var node = _b[_a]; + switch (node.kind) { + case 209: + if (!node.importClause || + resolver.isReferencedAliasDeclaration(node.importClause, true)) { + externalImports.push(node); + } + break; + case 208: + if (node.moduleReference.kind === 219 && resolver.isReferencedAliasDeclaration(node)) { + externalImports.push(node); + } + break; + case 215: + if (node.moduleSpecifier) { + if (!node.exportClause) { + externalImports.push(node); + hasExportStars = true; + } + else if (resolver.isValueAliasDeclaration(node)) { + externalImports.push(node); + } + } + else { + for (var _c = 0, _d = node.exportClause.elements; _c < _d.length; _c++) { + var specifier = _d[_c]; + var name_6 = (specifier.propertyName || specifier.name).text; + (exportSpecifiers[name_6] || (exportSpecifiers[name_6] = [])).push(specifier); + } + } + break; + case 214: + if (node.isExportEquals && !exportEquals) { + exportEquals = node; + } + break; + } + } + } + function emitExportStarHelper() { + if (hasExportStars) { + writeLine(); + write("function __export(m) {"); + increaseIndent(); + writeLine(); + write("for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];"); + decreaseIndent(); + writeLine(); + write("}"); + } + } + function emitAMDDependencies(node, includeNonAmdDependencies) { + // An AMD define function has the following shape: + // define(id?, dependencies?, factory); + // + // This has the shape of + // define(name, ["module1", "module2"], function (module1Alias) { + // The location of the alias in the parameter list in the factory function needs to + // match the position of the module name in the dependency list. + // + // To ensure this is true in cases of modules with no aliases, e.g.: + // `import "module"` or `` + // we need to add modules without alias names to the end of the dependencies list + var aliasedModuleNames = []; + var unaliasedModuleNames = []; + var importAliasNames = []; + for (var _a = 0, _b = node.amdDependencies; _a < _b.length; _a++) { + var amdDependency = _b[_a]; + if (amdDependency.name) { + aliasedModuleNames.push("\"" + amdDependency.path + "\""); + importAliasNames.push(amdDependency.name); + } + else { + unaliasedModuleNames.push("\"" + amdDependency.path + "\""); + } + } + for (var _c = 0; _c < externalImports.length; _c++) { + var importNode = externalImports[_c]; + var externalModuleName = ""; + var moduleName = ts.getExternalModuleName(importNode); + if (moduleName.kind === 8) { + externalModuleName = getLiteralText(moduleName); + } + var importAliasName = void 0; + var namespaceDeclaration = getNamespaceDeclarationNode(importNode); + if (namespaceDeclaration && !isDefaultImport(importNode)) { + importAliasName = ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, namespaceDeclaration.name); + } + else { + importAliasName = getGeneratedNameForNode(importNode); + } + if (includeNonAmdDependencies && importAliasName) { + aliasedModuleNames.push(externalModuleName); + importAliasNames.push(importAliasName); + } + else { + unaliasedModuleNames.push(externalModuleName); + } + } + write("[\"require\", \"exports\""); + if (aliasedModuleNames.length) { + write(", "); + write(aliasedModuleNames.join(", ")); + } + if (unaliasedModuleNames.length) { + write(", "); + write(unaliasedModuleNames.join(", ")); + } + write("], function (require, exports"); + if (importAliasNames.length) { + write(", "); + write(importAliasNames.join(", ")); + } + } + function emitAMDModule(node, startIndex) { + collectExternalModuleInfo(node); + writeLine(); + write("define("); + if (node.amdModuleName) { + write("\"" + node.amdModuleName + "\", "); + } + emitAMDDependencies(node, true); + write(") {"); + increaseIndent(); + emitExportStarHelper(); + emitCaptureThisForNodeIfNecessary(node); + emitLinesStartingAt(node.statements, startIndex); + emitTempDeclarations(true); + emitExportEquals(true); + decreaseIndent(); + writeLine(); + write("});"); + } + function emitCommonJSModule(node, startIndex) { + collectExternalModuleInfo(node); + emitExportStarHelper(); + emitCaptureThisForNodeIfNecessary(node); + emitLinesStartingAt(node.statements, startIndex); + emitTempDeclarations(true); + emitExportEquals(false); + } + function emitUMDModule(node, startIndex) { + collectExternalModuleInfo(node); + writeLines("(function (deps, factory) {\n if (typeof module === 'object' && typeof module.exports === 'object') {\n var v = factory(require, exports); if (v !== undefined) module.exports = v;\n }\n else if (typeof define === 'function' && define.amd) {\n define(deps, factory);\n }\n})("); + emitAMDDependencies(node, false); + write(") {"); + increaseIndent(); + emitExportStarHelper(); + emitCaptureThisForNodeIfNecessary(node); + emitLinesStartingAt(node.statements, startIndex); + emitTempDeclarations(true); + emitExportEquals(true); + decreaseIndent(); + writeLine(); + write("});"); + } + function emitES6Module(node, startIndex) { + externalImports = undefined; + exportSpecifiers = undefined; + exportEquals = undefined; + hasExportStars = false; + emitCaptureThisForNodeIfNecessary(node); + emitLinesStartingAt(node.statements, startIndex); + emitTempDeclarations(true); + } + function emitExportEquals(emitAsReturn) { + if (exportEquals && resolver.isValueAliasDeclaration(exportEquals)) { + writeLine(); + emitStart(exportEquals); + write(emitAsReturn ? "return " : "module.exports = "); + emit(exportEquals.expression); + write(";"); + emitEnd(exportEquals); + } + } + function emitDirectivePrologues(statements, startWithNewLine) { + for (var i = 0; i < statements.length; ++i) { + if (ts.isPrologueDirective(statements[i])) { + if (startWithNewLine || i > 0) { + writeLine(); + } + emit(statements[i]); + } + else { + return i; + } + } + return statements.length; + } + function writeLines(text) { + var lines = text.split(/\r\n|\r|\n/g); + for (var i = 0; i < lines.length; ++i) { + var line = lines[i]; + if (line.length) { + writeLine(); + write(line); + } + } + } + function emitSourceFileNode(node) { + writeLine(); + emitDetachedComments(node); + var startIndex = emitDirectivePrologues(node.statements, false); + if ((languageVersion < 2) && (!extendsEmitted && resolver.getNodeCheckFlags(node) & 8)) { + writeLines(extendsHelper); + extendsEmitted = true; + } + if (!decorateEmitted && resolver.getNodeCheckFlags(node) & 512) { + writeLines(decorateHelper); + if (compilerOptions.emitDecoratorMetadata) { + writeLines(metadataHelper); + } + decorateEmitted = true; + } + if (!paramEmitted && resolver.getNodeCheckFlags(node) & 1024) { + writeLines(paramHelper); + paramEmitted = true; + } + if (ts.isExternalModule(node)) { + if (languageVersion >= 2) { + emitES6Module(node, startIndex); + } + else if (compilerOptions.module === 2) { + emitAMDModule(node, startIndex); + } + else if (compilerOptions.module === 3) { + emitUMDModule(node, startIndex); + } + else { + emitCommonJSModule(node, startIndex); + } + } + else { + externalImports = undefined; + exportSpecifiers = undefined; + exportEquals = undefined; + hasExportStars = false; + emitCaptureThisForNodeIfNecessary(node); + emitLinesStartingAt(node.statements, startIndex); + emitTempDeclarations(true); + } + emitLeadingComments(node.endOfFileToken); + } + function emitNodeWithoutSourceMap(node, allowGeneratedIdentifiers) { + if (!node) { + return; + } + if (node.flags & 2) { + return emitOnlyPinnedOrTripleSlashComments(node); + } + var emitComments = shouldEmitLeadingAndTrailingComments(node); + if (emitComments) { + emitLeadingComments(node); + } + emitJavaScriptWorker(node, allowGeneratedIdentifiers); + if (emitComments) { + emitTrailingComments(node); + } + } + function shouldEmitLeadingAndTrailingComments(node) { + switch (node.kind) { + case 202: + case 200: + case 209: + case 208: + case 203: + case 214: + return false; + case 205: + return shouldEmitModuleDeclaration(node); + case 204: + return shouldEmitEnumDeclaration(node); + } + if (node.kind !== 179 && + node.parent && + node.parent.kind === 163 && + node.parent.body === node && + compilerOptions.target <= 1) { + return false; + } + return true; + } + function emitJavaScriptWorker(node, allowGeneratedIdentifiers) { + if (allowGeneratedIdentifiers === void 0) { allowGeneratedIdentifiers = true; } + switch (node.kind) { + case 65: + return emitIdentifier(node, allowGeneratedIdentifiers); + case 129: + return emitParameter(node); + case 134: + case 133: + return emitMethod(node); + case 136: + case 137: + return emitAccessor(node); + case 93: + return emitThis(node); + case 91: + return emitSuper(node); + case 89: + return write("null"); + case 95: + return write("true"); + case 80: + return write("false"); + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + return emitLiteral(node); + case 171: + return emitTemplateExpression(node); + case 176: + return emitTemplateSpan(node); + case 126: + return emitQualifiedName(node); + case 150: + return emitObjectBindingPattern(node); + case 151: + return emitArrayBindingPattern(node); + case 152: + return emitBindingElement(node); + case 153: + return emitArrayLiteral(node); + case 154: + return emitObjectLiteral(node); + case 224: + return emitPropertyAssignment(node); + case 225: + return emitShorthandPropertyAssignment(node); + case 127: + return emitComputedPropertyName(node); + case 155: + return emitPropertyAccess(node); + case 156: + return emitIndexedAccess(node); + case 157: + return emitCallExpression(node); + case 158: + return emitNewExpression(node); + case 159: + return emitTaggedTemplateExpression(node); + case 160: + return emit(node.expression); + case 161: + return emitParenExpression(node); + case 200: + case 162: + case 163: + return emitFunctionDeclaration(node); + case 164: + return emitDeleteExpression(node); + case 165: + return emitTypeOfExpression(node); + case 166: + return emitVoidExpression(node); + case 167: + return emitPrefixUnaryExpression(node); + case 168: + return emitPostfixUnaryExpression(node); + case 169: + return emitBinaryExpression(node); + case 170: + return emitConditionalExpression(node); + case 173: + return emitSpreadElementExpression(node); + case 172: + return emitYieldExpression(node); + case 175: + return; + case 179: + case 206: + return emitBlock(node); + case 180: + return emitVariableStatement(node); + case 181: + return write(";"); + case 182: + return emitExpressionStatement(node); + case 183: + return emitIfStatement(node); + case 184: + return emitDoStatement(node); + case 185: + return emitWhileStatement(node); + case 186: + return emitForStatement(node); + case 188: + case 187: + return emitForInOrForOfStatement(node); + case 189: + case 190: + return emitBreakOrContinueStatement(node); + case 191: + return emitReturnStatement(node); + case 192: + return emitWithStatement(node); + case 193: + return emitSwitchStatement(node); + case 220: + case 221: + return emitCaseOrDefaultClause(node); + case 194: + return emitLabelledStatement(node); + case 195: + return emitThrowStatement(node); + case 196: + return emitTryStatement(node); + case 223: + return emitCatchClause(node); + case 197: + return emitDebuggerStatement(node); + case 198: + return emitVariableDeclaration(node); + case 174: + return emitClassExpression(node); + case 201: + return emitClassDeclaration(node); + case 202: + return emitInterfaceDeclaration(node); + case 204: + return emitEnumDeclaration(node); + case 226: + return emitEnumMember(node); + case 205: + return emitModuleDeclaration(node); + case 209: + return emitImportDeclaration(node); + case 208: + return emitImportEqualsDeclaration(node); + case 215: + return emitExportDeclaration(node); + case 214: + return emitExportAssignment(node); + case 227: + return emitSourceFileNode(node); + } + } + function hasDetachedComments(pos) { + return detachedCommentsInfo !== undefined && detachedCommentsInfo[detachedCommentsInfo.length - 1].nodePos === pos; + } + function getLeadingCommentsWithoutDetachedComments() { + var leadingComments = ts.getLeadingCommentRanges(currentSourceFile.text, detachedCommentsInfo[detachedCommentsInfo.length - 1].detachedCommentEndPos); + if (detachedCommentsInfo.length - 1) { + detachedCommentsInfo.pop(); + } + else { + detachedCommentsInfo = undefined; + } + return leadingComments; + } + function filterComments(ranges, onlyPinnedOrTripleSlashComments) { + if (ranges && onlyPinnedOrTripleSlashComments) { + ranges = ts.filter(ranges, isPinnedOrTripleSlashComment); + if (ranges.length === 0) { + return undefined; + } + } + return ranges; + } + function getLeadingCommentsToEmit(node) { + if (node.parent) { + if (node.parent.kind === 227 || node.pos !== node.parent.pos) { + if (hasDetachedComments(node.pos)) { + return getLeadingCommentsWithoutDetachedComments(); + } + else { + return ts.getLeadingCommentRangesOfNode(node, currentSourceFile); + } + } + } + } + function getTrailingCommentsToEmit(node) { + if (node.parent) { + if (node.parent.kind === 227 || node.end !== node.parent.end) { + return ts.getTrailingCommentRanges(currentSourceFile.text, node.end); + } + } + } + function emitOnlyPinnedOrTripleSlashComments(node) { + emitLeadingCommentsWorker(node, true); + } + function emitLeadingComments(node) { + return emitLeadingCommentsWorker(node, compilerOptions.removeComments); + } + function emitLeadingCommentsWorker(node, onlyPinnedOrTripleSlashComments) { + var leadingComments = filterComments(getLeadingCommentsToEmit(node), onlyPinnedOrTripleSlashComments); + ts.emitNewLineBeforeLeadingComments(currentSourceFile, writer, node, leadingComments); + ts.emitComments(currentSourceFile, writer, leadingComments, true, newLine, writeComment); + } + function emitTrailingComments(node) { + var trailingComments = filterComments(getTrailingCommentsToEmit(node), compilerOptions.removeComments); + ts.emitComments(currentSourceFile, writer, trailingComments, false, newLine, writeComment); + } + function emitLeadingCommentsOfPosition(pos) { + var leadingComments; + if (hasDetachedComments(pos)) { + leadingComments = getLeadingCommentsWithoutDetachedComments(); + } + else { + leadingComments = ts.getLeadingCommentRanges(currentSourceFile.text, pos); + } + leadingComments = filterComments(leadingComments, compilerOptions.removeComments); + ts.emitNewLineBeforeLeadingComments(currentSourceFile, writer, { pos: pos, end: pos }, leadingComments); + ts.emitComments(currentSourceFile, writer, leadingComments, true, newLine, writeComment); + } + function emitDetachedComments(node) { + var leadingComments = ts.getLeadingCommentRanges(currentSourceFile.text, node.pos); + if (leadingComments) { + var detachedComments = []; + var lastComment; + ts.forEach(leadingComments, function (comment) { + if (lastComment) { + var lastCommentLine = ts.getLineOfLocalPosition(currentSourceFile, lastComment.end); + var commentLine = ts.getLineOfLocalPosition(currentSourceFile, comment.pos); + if (commentLine >= lastCommentLine + 2) { + return detachedComments; + } + } + detachedComments.push(comment); + lastComment = comment; + }); + if (detachedComments.length) { + var lastCommentLine = ts.getLineOfLocalPosition(currentSourceFile, detachedComments[detachedComments.length - 1].end); + var nodeLine = ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node.pos)); + if (nodeLine >= lastCommentLine + 2) { + ts.emitNewLineBeforeLeadingComments(currentSourceFile, writer, node, leadingComments); + ts.emitComments(currentSourceFile, writer, detachedComments, true, newLine, writeComment); + var currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: detachedComments[detachedComments.length - 1].end }; + if (detachedCommentsInfo) { + detachedCommentsInfo.push(currentDetachedCommentInfo); + } + else { + detachedCommentsInfo = [currentDetachedCommentInfo]; + } + } + } + } + } + function isPinnedOrTripleSlashComment(comment) { + if (currentSourceFile.text.charCodeAt(comment.pos + 1) === 42) { + return currentSourceFile.text.charCodeAt(comment.pos + 2) === 33; + } + else if (currentSourceFile.text.charCodeAt(comment.pos + 1) === 47 && + comment.pos + 2 < comment.end && + currentSourceFile.text.charCodeAt(comment.pos + 2) === 47 && + currentSourceFile.text.substring(comment.pos, comment.end).match(ts.fullTripleSlashReferencePathRegEx)) { + return true; + } + } + } + function emitFile(jsFilePath, sourceFile) { + emitJavaScript(jsFilePath, sourceFile); + if (compilerOptions.declaration) { + ts.writeDeclarationFile(jsFilePath, sourceFile, host, resolver, diagnostics); + } + } + } + ts.emitFiles = emitFiles; +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/parser.js b/dist/typescript/compiler/parser.js new file mode 100644 index 000000000..2731f6e2b --- /dev/null +++ b/dist/typescript/compiler/parser.js @@ -0,0 +1,3733 @@ +/// +/// +var ts; +(function (ts) { + var nodeConstructors = new Array(229); + ts.parseTime = 0; + function getNodeConstructor(kind) { + return nodeConstructors[kind] || (nodeConstructors[kind] = ts.objectAllocator.getNodeConstructor(kind)); + } + ts.getNodeConstructor = getNodeConstructor; + function createNode(kind) { + return new (getNodeConstructor(kind))(); + } + ts.createNode = createNode; + function visitNode(cbNode, node) { + if (node) { + return cbNode(node); + } + } + function visitNodeArray(cbNodes, nodes) { + if (nodes) { + return cbNodes(nodes); + } + } + function visitEachNode(cbNode, nodes) { + if (nodes) { + for (var _i = 0; _i < nodes.length; _i++) { + var node = nodes[_i]; + var result = cbNode(node); + if (result) { + return result; + } + } + } + } + function forEachChild(node, cbNode, cbNodeArray) { + if (!node) { + return; + } + var visitNodes = cbNodeArray ? visitNodeArray : visitEachNode; + var cbNodes = cbNodeArray || cbNode; + switch (node.kind) { + case 126: + return visitNode(cbNode, node.left) || + visitNode(cbNode, node.right); + case 128: + return visitNode(cbNode, node.name) || + visitNode(cbNode, node.constraint) || + visitNode(cbNode, node.expression); + case 129: + case 132: + case 131: + case 224: + case 225: + case 198: + case 152: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.propertyName) || + visitNode(cbNode, node.dotDotDotToken) || + visitNode(cbNode, node.name) || + visitNode(cbNode, node.questionToken) || + visitNode(cbNode, node.type) || + visitNode(cbNode, node.initializer); + case 142: + case 143: + case 138: + case 139: + case 140: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNodes(cbNodes, node.typeParameters) || + visitNodes(cbNodes, node.parameters) || + visitNode(cbNode, node.type); + case 134: + case 133: + case 135: + case 136: + case 137: + case 162: + case 200: + case 163: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.asteriskToken) || + visitNode(cbNode, node.name) || + visitNode(cbNode, node.questionToken) || + visitNodes(cbNodes, node.typeParameters) || + visitNodes(cbNodes, node.parameters) || + visitNode(cbNode, node.type) || + visitNode(cbNode, node.equalsGreaterThanToken) || + visitNode(cbNode, node.body); + case 141: + return visitNode(cbNode, node.typeName) || + visitNodes(cbNodes, node.typeArguments); + case 144: + return visitNode(cbNode, node.exprName); + case 145: + return visitNodes(cbNodes, node.members); + case 146: + return visitNode(cbNode, node.elementType); + case 147: + return visitNodes(cbNodes, node.elementTypes); + case 148: + return visitNodes(cbNodes, node.types); + case 149: + return visitNode(cbNode, node.type); + case 150: + case 151: + return visitNodes(cbNodes, node.elements); + case 153: + return visitNodes(cbNodes, node.elements); + case 154: + return visitNodes(cbNodes, node.properties); + case 155: + return visitNode(cbNode, node.expression) || + visitNode(cbNode, node.dotToken) || + visitNode(cbNode, node.name); + case 156: + return visitNode(cbNode, node.expression) || + visitNode(cbNode, node.argumentExpression); + case 157: + case 158: + return visitNode(cbNode, node.expression) || + visitNodes(cbNodes, node.typeArguments) || + visitNodes(cbNodes, node.arguments); + case 159: + return visitNode(cbNode, node.tag) || + visitNode(cbNode, node.template); + case 160: + return visitNode(cbNode, node.type) || + visitNode(cbNode, node.expression); + case 161: + return visitNode(cbNode, node.expression); + case 164: + return visitNode(cbNode, node.expression); + case 165: + return visitNode(cbNode, node.expression); + case 166: + return visitNode(cbNode, node.expression); + case 167: + return visitNode(cbNode, node.operand); + case 172: + return visitNode(cbNode, node.asteriskToken) || + visitNode(cbNode, node.expression); + case 168: + return visitNode(cbNode, node.operand); + case 169: + return visitNode(cbNode, node.left) || + visitNode(cbNode, node.operatorToken) || + visitNode(cbNode, node.right); + case 170: + return visitNode(cbNode, node.condition) || + visitNode(cbNode, node.questionToken) || + visitNode(cbNode, node.whenTrue) || + visitNode(cbNode, node.colonToken) || + visitNode(cbNode, node.whenFalse); + case 173: + return visitNode(cbNode, node.expression); + case 179: + case 206: + return visitNodes(cbNodes, node.statements); + case 227: + return visitNodes(cbNodes, node.statements) || + visitNode(cbNode, node.endOfFileToken); + case 180: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.declarationList); + case 199: + return visitNodes(cbNodes, node.declarations); + case 182: + return visitNode(cbNode, node.expression); + case 183: + return visitNode(cbNode, node.expression) || + visitNode(cbNode, node.thenStatement) || + visitNode(cbNode, node.elseStatement); + case 184: + return visitNode(cbNode, node.statement) || + visitNode(cbNode, node.expression); + case 185: + return visitNode(cbNode, node.expression) || + visitNode(cbNode, node.statement); + case 186: + return visitNode(cbNode, node.initializer) || + visitNode(cbNode, node.condition) || + visitNode(cbNode, node.incrementor) || + visitNode(cbNode, node.statement); + case 187: + return visitNode(cbNode, node.initializer) || + visitNode(cbNode, node.expression) || + visitNode(cbNode, node.statement); + case 188: + return visitNode(cbNode, node.initializer) || + visitNode(cbNode, node.expression) || + visitNode(cbNode, node.statement); + case 189: + case 190: + return visitNode(cbNode, node.label); + case 191: + return visitNode(cbNode, node.expression); + case 192: + return visitNode(cbNode, node.expression) || + visitNode(cbNode, node.statement); + case 193: + return visitNode(cbNode, node.expression) || + visitNode(cbNode, node.caseBlock); + case 207: + return visitNodes(cbNodes, node.clauses); + case 220: + return visitNode(cbNode, node.expression) || + visitNodes(cbNodes, node.statements); + case 221: + return visitNodes(cbNodes, node.statements); + case 194: + return visitNode(cbNode, node.label) || + visitNode(cbNode, node.statement); + case 195: + return visitNode(cbNode, node.expression); + case 196: + return visitNode(cbNode, node.tryBlock) || + visitNode(cbNode, node.catchClause) || + visitNode(cbNode, node.finallyBlock); + case 223: + return visitNode(cbNode, node.variableDeclaration) || + visitNode(cbNode, node.block); + case 130: + return visitNode(cbNode, node.expression); + case 201: + case 174: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.name) || + visitNodes(cbNodes, node.typeParameters) || + visitNodes(cbNodes, node.heritageClauses) || + visitNodes(cbNodes, node.members); + case 202: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.name) || + visitNodes(cbNodes, node.typeParameters) || + visitNodes(cbNodes, node.heritageClauses) || + visitNodes(cbNodes, node.members); + case 203: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.name) || + visitNode(cbNode, node.type); + case 204: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.name) || + visitNodes(cbNodes, node.members); + case 226: + return visitNode(cbNode, node.name) || + visitNode(cbNode, node.initializer); + case 205: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.name) || + visitNode(cbNode, node.body); + case 208: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.name) || + visitNode(cbNode, node.moduleReference); + case 209: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.importClause) || + visitNode(cbNode, node.moduleSpecifier); + case 210: + return visitNode(cbNode, node.name) || + visitNode(cbNode, node.namedBindings); + case 211: + return visitNode(cbNode, node.name); + case 212: + case 216: + return visitNodes(cbNodes, node.elements); + case 215: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.exportClause) || + visitNode(cbNode, node.moduleSpecifier); + case 213: + case 217: + return visitNode(cbNode, node.propertyName) || + visitNode(cbNode, node.name); + case 214: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, node.expression); + case 171: + return visitNode(cbNode, node.head) || visitNodes(cbNodes, node.templateSpans); + case 176: + return visitNode(cbNode, node.expression) || visitNode(cbNode, node.literal); + case 127: + return visitNode(cbNode, node.expression); + case 222: + return visitNodes(cbNodes, node.types); + case 177: + return visitNode(cbNode, node.expression) || + visitNodes(cbNodes, node.typeArguments); + case 219: + return visitNode(cbNode, node.expression); + case 218: + return visitNodes(cbNodes, node.decorators); + } + } + ts.forEachChild = forEachChild; + function createSourceFile(fileName, sourceText, languageVersion, setParentNodes) { + if (setParentNodes === void 0) { setParentNodes = false; } + var start = new Date().getTime(); + var result = Parser.parseSourceFile(fileName, sourceText, languageVersion, undefined, setParentNodes); + ts.parseTime += new Date().getTime() - start; + return result; + } + ts.createSourceFile = createSourceFile; + function updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks) { + return IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); + } + ts.updateSourceFile = updateSourceFile; + var Parser; + (function (Parser) { + var scanner = ts.createScanner(2, true); + var disallowInAndDecoratorContext = 2 | 16; + var sourceFile; + var syntaxCursor; + var token; + var sourceText; + var nodeCount; + var identifiers; + var identifierCount; + var parsingContext; + var contextFlags = 0; + var parseErrorBeforeNextFinishedNode = false; + function parseSourceFile(fileName, _sourceText, languageVersion, _syntaxCursor, setParentNodes) { + sourceText = _sourceText; + syntaxCursor = _syntaxCursor; + parsingContext = 0; + identifiers = {}; + identifierCount = 0; + nodeCount = 0; + contextFlags = 0; + parseErrorBeforeNextFinishedNode = false; + createSourceFile(fileName, languageVersion); + scanner.setText(sourceText); + scanner.setOnError(scanError); + scanner.setScriptTarget(languageVersion); + token = nextToken(); + processReferenceComments(sourceFile); + sourceFile.statements = parseList(0, true, parseSourceElement); + ts.Debug.assert(token === 1); + sourceFile.endOfFileToken = parseTokenNode(); + setExternalModuleIndicator(sourceFile); + sourceFile.nodeCount = nodeCount; + sourceFile.identifierCount = identifierCount; + sourceFile.identifiers = identifiers; + if (setParentNodes) { + fixupParentReferences(sourceFile); + } + syntaxCursor = undefined; + scanner.setText(""); + scanner.setOnError(undefined); + var result = sourceFile; + sourceFile = undefined; + identifiers = undefined; + syntaxCursor = undefined; + sourceText = undefined; + return result; + } + Parser.parseSourceFile = parseSourceFile; + function fixupParentReferences(sourceFile) { + // normally parent references are set during binding. However, for clients that only need + // a syntax tree, and no semantic features, then the binding process is an unnecessary + // overhead. This functions allows us to set all the parents, without all the expense of + // binding. + var parent = sourceFile; + forEachChild(sourceFile, visitNode); + return; + function visitNode(n) { + if (n.parent !== parent) { + n.parent = parent; + var saveParent = parent; + parent = n; + forEachChild(n, visitNode); + parent = saveParent; + } + } + } + function createSourceFile(fileName, languageVersion) { + sourceFile = createNode(227, 0); + sourceFile.pos = 0; + sourceFile.end = sourceText.length; + sourceFile.text = sourceText; + sourceFile.parseDiagnostics = []; + sourceFile.bindDiagnostics = []; + sourceFile.languageVersion = languageVersion; + sourceFile.fileName = ts.normalizePath(fileName); + sourceFile.flags = ts.fileExtensionIs(sourceFile.fileName, ".d.ts") ? 2048 : 0; + } + function setContextFlag(val, flag) { + if (val) { + contextFlags |= flag; + } + else { + contextFlags &= ~flag; + } + } + function setStrictModeContext(val) { + setContextFlag(val, 1); + } + function setDisallowInContext(val) { + setContextFlag(val, 2); + } + function setYieldContext(val) { + setContextFlag(val, 4); + } + function setGeneratorParameterContext(val) { + setContextFlag(val, 8); + } + function setDecoratorContext(val) { + setContextFlag(val, 16); + } + function doOutsideOfContext(flags, func) { + var currentContextFlags = contextFlags & flags; + if (currentContextFlags) { + setContextFlag(false, currentContextFlags); + var result = func(); + setContextFlag(true, currentContextFlags); + return result; + } + return func(); + } + function allowInAnd(func) { + if (contextFlags & 2) { + setDisallowInContext(false); + var result = func(); + setDisallowInContext(true); + return result; + } + return func(); + } + function disallowInAnd(func) { + if (contextFlags & 2) { + return func(); + } + setDisallowInContext(true); + var result = func(); + setDisallowInContext(false); + return result; + } + function doInYieldContext(func) { + if (contextFlags & 4) { + return func(); + } + setYieldContext(true); + var result = func(); + setYieldContext(false); + return result; + } + function doOutsideOfYieldContext(func) { + if (contextFlags & 4) { + setYieldContext(false); + var result = func(); + setYieldContext(true); + return result; + } + return func(); + } + function doInDecoratorContext(func) { + if (contextFlags & 16) { + return func(); + } + setDecoratorContext(true); + var result = func(); + setDecoratorContext(false); + return result; + } + function inYieldContext() { + return (contextFlags & 4) !== 0; + } + function inStrictModeContext() { + return (contextFlags & 1) !== 0; + } + function inGeneratorParameterContext() { + return (contextFlags & 8) !== 0; + } + function inDisallowInContext() { + return (contextFlags & 2) !== 0; + } + function inDecoratorContext() { + return (contextFlags & 16) !== 0; + } + function parseErrorAtCurrentToken(message, arg0) { + var start = scanner.getTokenPos(); + var length = scanner.getTextPos() - start; + parseErrorAtPosition(start, length, message, arg0); + } + function parseErrorAtPosition(start, length, message, arg0) { + var lastError = ts.lastOrUndefined(sourceFile.parseDiagnostics); + if (!lastError || start !== lastError.start) { + sourceFile.parseDiagnostics.push(ts.createFileDiagnostic(sourceFile, start, length, message, arg0)); + } + parseErrorBeforeNextFinishedNode = true; + } + function scanError(message, length) { + var pos = scanner.getTextPos(); + parseErrorAtPosition(pos, length || 0, message); + } + function getNodePos() { + return scanner.getStartPos(); + } + function getNodeEnd() { + return scanner.getStartPos(); + } + function nextToken() { + return token = scanner.scan(); + } + function getTokenPos(pos) { + return ts.skipTrivia(sourceText, pos); + } + function reScanGreaterToken() { + return token = scanner.reScanGreaterToken(); + } + function reScanSlashToken() { + return token = scanner.reScanSlashToken(); + } + function reScanTemplateToken() { + return token = scanner.reScanTemplateToken(); + } + function speculationHelper(callback, isLookAhead) { + var saveToken = token; + var saveParseDiagnosticsLength = sourceFile.parseDiagnostics.length; + var saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; + var saveContextFlags = contextFlags; + var result = isLookAhead + ? scanner.lookAhead(callback) + : scanner.tryScan(callback); + ts.Debug.assert(saveContextFlags === contextFlags); + if (!result || isLookAhead) { + token = saveToken; + sourceFile.parseDiagnostics.length = saveParseDiagnosticsLength; + parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; + } + return result; + } + function lookAhead(callback) { + return speculationHelper(callback, true); + } + function tryParse(callback) { + return speculationHelper(callback, false); + } + function isIdentifier() { + if (token === 65) { + return true; + } + if (token === 110 && inYieldContext()) { + return false; + } + return token > 101; + } + function parseExpected(kind, diagnosticMessage) { + if (token === kind) { + nextToken(); + return true; + } + if (diagnosticMessage) { + parseErrorAtCurrentToken(diagnosticMessage); + } + else { + parseErrorAtCurrentToken(ts.Diagnostics._0_expected, ts.tokenToString(kind)); + } + return false; + } + function parseOptional(t) { + if (token === t) { + nextToken(); + return true; + } + return false; + } + function parseOptionalToken(t) { + if (token === t) { + return parseTokenNode(); + } + return undefined; + } + function parseExpectedToken(t, reportAtCurrentPosition, diagnosticMessage, arg0) { + return parseOptionalToken(t) || + createMissingNode(t, reportAtCurrentPosition, diagnosticMessage, arg0); + } + function parseTokenNode() { + var node = createNode(token); + nextToken(); + return finishNode(node); + } + function canParseSemicolon() { + if (token === 22) { + return true; + } + return token === 15 || token === 1 || scanner.hasPrecedingLineBreak(); + } + function parseSemicolon() { + if (canParseSemicolon()) { + if (token === 22) { + nextToken(); + } + return true; + } + else { + return parseExpected(22); + } + } + function createNode(kind, pos) { + nodeCount++; + var node = new (nodeConstructors[kind] || (nodeConstructors[kind] = ts.objectAllocator.getNodeConstructor(kind)))(); + if (!(pos >= 0)) { + pos = scanner.getStartPos(); + } + node.pos = pos; + node.end = pos; + return node; + } + function finishNode(node) { + node.end = scanner.getStartPos(); + if (contextFlags) { + node.parserContextFlags = contextFlags; + } + if (parseErrorBeforeNextFinishedNode) { + parseErrorBeforeNextFinishedNode = false; + node.parserContextFlags |= 32; + } + return node; + } + function createMissingNode(kind, reportAtCurrentPosition, diagnosticMessage, arg0) { + if (reportAtCurrentPosition) { + parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0); + } + else { + parseErrorAtCurrentToken(diagnosticMessage, arg0); + } + var result = createNode(kind, scanner.getStartPos()); + result.text = ""; + return finishNode(result); + } + function internIdentifier(text) { + text = ts.escapeIdentifier(text); + return ts.hasProperty(identifiers, text) ? identifiers[text] : (identifiers[text] = text); + } + function createIdentifier(isIdentifier, diagnosticMessage) { + identifierCount++; + if (isIdentifier) { + var node = createNode(65); + if (token !== 65) { + node.originalKeywordKind = token; + } + node.text = internIdentifier(scanner.getTokenValue()); + nextToken(); + return finishNode(node); + } + return createMissingNode(65, false, diagnosticMessage || ts.Diagnostics.Identifier_expected); + } + function parseIdentifier(diagnosticMessage) { + return createIdentifier(isIdentifier(), diagnosticMessage); + } + function parseIdentifierName() { + return createIdentifier(isIdentifierOrKeyword()); + } + function isLiteralPropertyName() { + return isIdentifierOrKeyword() || + token === 8 || + token === 7; + } + function parsePropertyName() { + if (token === 8 || token === 7) { + return parseLiteralNode(true); + } + if (token === 18) { + return parseComputedPropertyName(); + } + return parseIdentifierName(); + } + function parseComputedPropertyName() { + var node = createNode(127); + parseExpected(18); + var yieldContext = inYieldContext(); + if (inGeneratorParameterContext()) { + setYieldContext(false); + } + node.expression = allowInAnd(parseExpression); + if (inGeneratorParameterContext()) { + setYieldContext(yieldContext); + } + parseExpected(19); + return finishNode(node); + } + function parseContextualModifier(t) { + return token === t && tryParse(nextTokenCanFollowModifier); + } + function nextTokenCanFollowModifier() { + nextToken(); + return canFollowModifier(); + } + function parseAnyContextualModifier() { + return ts.isModifier(token) && tryParse(nextTokenCanFollowContextualModifier); + } + function nextTokenCanFollowContextualModifier() { + if (token === 70) { + return nextToken() === 77; + } + if (token === 78) { + nextToken(); + if (token === 73) { + return lookAhead(nextTokenIsClassOrFunction); + } + return token !== 35 && token !== 14 && canFollowModifier(); + } + if (token === 73) { + return nextTokenIsClassOrFunction(); + } + nextToken(); + return canFollowModifier(); + } + function canFollowModifier() { + return token === 18 + || token === 14 + || token === 35 + || isLiteralPropertyName(); + } + function nextTokenIsClassOrFunction() { + nextToken(); + return token === 69 || token === 83; + } + function isListElement(parsingContext, inErrorRecovery) { + var node = currentNode(parsingContext); + if (node) { + return true; + } + switch (parsingContext) { + case 0: + case 1: + return isSourceElement(inErrorRecovery); + case 2: + case 4: + return isStartOfStatement(inErrorRecovery); + case 3: + return token === 67 || token === 73; + case 5: + return isStartOfTypeMember(); + case 6: + return lookAhead(isClassMemberStart) || (token === 22 && !inErrorRecovery); + case 7: + return token === 18 || isLiteralPropertyName(); + case 13: + return token === 18 || token === 35 || isLiteralPropertyName(); + case 10: + return isLiteralPropertyName(); + case 8: + if (token === 14) { + return lookAhead(isValidHeritageClauseObjectLiteral); + } + if (!inErrorRecovery) { + return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword(); + } + else { + return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword(); + } + case 9: + return isIdentifierOrPattern(); + case 11: + return token === 23 || token === 21 || isIdentifierOrPattern(); + case 16: + return isIdentifier(); + case 12: + case 14: + return token === 23 || token === 21 || isStartOfExpression(); + case 15: + return isStartOfParameter(); + case 17: + case 18: + return token === 23 || isStartOfType(); + case 19: + return isHeritageClause(); + case 20: + return isIdentifierOrKeyword(); + } + ts.Debug.fail("Non-exhaustive case in 'isListElement'."); + } + function isValidHeritageClauseObjectLiteral() { + ts.Debug.assert(token === 14); + if (nextToken() === 15) { + var next = nextToken(); + return next === 23 || next === 14 || next === 79 || next === 102; + } + return true; + } + function nextTokenIsIdentifier() { + nextToken(); + return isIdentifier(); + } + function isHeritageClauseExtendsOrImplementsKeyword() { + if (token === 102 || + token === 79) { + return lookAhead(nextTokenIsStartOfExpression); + } + return false; + } + function nextTokenIsStartOfExpression() { + nextToken(); + return isStartOfExpression(); + } + function isListTerminator(kind) { + if (token === 1) { + return true; + } + switch (kind) { + case 1: + case 2: + case 3: + case 5: + case 6: + case 7: + case 13: + case 10: + case 20: + return token === 15; + case 4: + return token === 15 || token === 67 || token === 73; + case 8: + return token === 14 || token === 79 || token === 102; + case 9: + return isVariableDeclaratorListTerminator(); + case 16: + return token === 25 || token === 16 || token === 14 || token === 79 || token === 102; + case 12: + return token === 17 || token === 22; + case 14: + case 18: + case 11: + return token === 19; + case 15: + return token === 17 || token === 19; + case 17: + return token === 25 || token === 16; + case 19: + return token === 14 || token === 15; + } + } + function isVariableDeclaratorListTerminator() { + if (canParseSemicolon()) { + return true; + } + if (isInOrOfKeyword(token)) { + return true; + } + if (token === 32) { + return true; + } + return false; + } + function isInSomeParsingContext() { + for (var kind = 0; kind < 21; kind++) { + if (parsingContext & (1 << kind)) { + if (isListElement(kind, true) || isListTerminator(kind)) { + return true; + } + } + } + return false; + } + function parseList(kind, checkForStrictMode, parseElement) { + var saveParsingContext = parsingContext; + parsingContext |= 1 << kind; + var result = []; + result.pos = getNodePos(); + var savedStrictModeContext = inStrictModeContext(); + while (!isListTerminator(kind)) { + if (isListElement(kind, false)) { + var element = parseListElement(kind, parseElement); + result.push(element); + if (checkForStrictMode && !inStrictModeContext()) { + if (ts.isPrologueDirective(element)) { + if (isUseStrictPrologueDirective(sourceFile, element)) { + setStrictModeContext(true); + checkForStrictMode = false; + } + } + else { + checkForStrictMode = false; + } + } + continue; + } + if (abortParsingListOrMoveToNextToken(kind)) { + break; + } + } + setStrictModeContext(savedStrictModeContext); + result.end = getNodeEnd(); + parsingContext = saveParsingContext; + return result; + } + function isUseStrictPrologueDirective(sourceFile, node) { + ts.Debug.assert(ts.isPrologueDirective(node)); + var nodeText = ts.getSourceTextOfNodeFromSourceFile(sourceFile, node.expression); + return nodeText === '"use strict"' || nodeText === "'use strict'"; + } + function parseListElement(parsingContext, parseElement) { + var node = currentNode(parsingContext); + if (node) { + return consumeNode(node); + } + return parseElement(); + } + function currentNode(parsingContext) { + if (parseErrorBeforeNextFinishedNode) { + return undefined; + } + if (!syntaxCursor) { + return undefined; + } + var node = syntaxCursor.currentNode(scanner.getStartPos()); + if (ts.nodeIsMissing(node)) { + return undefined; + } + if (node.intersectsChange) { + return undefined; + } + if (ts.containsParseError(node)) { + return undefined; + } + var nodeContextFlags = node.parserContextFlags & 63; + if (nodeContextFlags !== contextFlags) { + return undefined; + } + if (!canReuseNode(node, parsingContext)) { + return undefined; + } + return node; + } + function consumeNode(node) { + scanner.setTextPos(node.end); + nextToken(); + return node; + } + function canReuseNode(node, parsingContext) { + switch (parsingContext) { + case 1: + return isReusableModuleElement(node); + case 6: + return isReusableClassMember(node); + case 3: + return isReusableSwitchClause(node); + case 2: + case 4: + return isReusableStatement(node); + case 7: + return isReusableEnumMember(node); + case 5: + return isReusableTypeMember(node); + case 9: + return isReusableVariableDeclaration(node); + case 15: + return isReusableParameter(node); + case 19: + case 16: + case 18: + case 17: + case 12: + case 13: + case 8: + } + return false; + } + function isReusableModuleElement(node) { + if (node) { + switch (node.kind) { + case 209: + case 208: + case 215: + case 214: + case 201: + case 202: + case 205: + case 204: + return true; + } + return isReusableStatement(node); + } + return false; + } + function isReusableClassMember(node) { + if (node) { + switch (node.kind) { + case 135: + case 140: + case 134: + case 136: + case 137: + case 132: + case 178: + return true; + } + } + return false; + } + function isReusableSwitchClause(node) { + if (node) { + switch (node.kind) { + case 220: + case 221: + return true; + } + } + return false; + } + function isReusableStatement(node) { + if (node) { + switch (node.kind) { + case 200: + case 180: + case 179: + case 183: + case 182: + case 195: + case 191: + case 193: + case 190: + case 189: + case 187: + case 188: + case 186: + case 185: + case 192: + case 181: + case 196: + case 194: + case 184: + case 197: + return true; + } + } + return false; + } + function isReusableEnumMember(node) { + return node.kind === 226; + } + function isReusableTypeMember(node) { + if (node) { + switch (node.kind) { + case 139: + case 133: + case 140: + case 131: + case 138: + return true; + } + } + return false; + } + function isReusableVariableDeclaration(node) { + if (node.kind !== 198) { + return false; + } + var variableDeclarator = node; + return variableDeclarator.initializer === undefined; + } + function isReusableParameter(node) { + if (node.kind !== 129) { + return false; + } + var parameter = node; + return parameter.initializer === undefined; + } + function abortParsingListOrMoveToNextToken(kind) { + parseErrorAtCurrentToken(parsingContextErrors(kind)); + if (isInSomeParsingContext()) { + return true; + } + nextToken(); + return false; + } + function parsingContextErrors(context) { + switch (context) { + case 0: return ts.Diagnostics.Declaration_or_statement_expected; + case 1: return ts.Diagnostics.Declaration_or_statement_expected; + case 2: return ts.Diagnostics.Statement_expected; + case 3: return ts.Diagnostics.case_or_default_expected; + case 4: return ts.Diagnostics.Statement_expected; + case 5: return ts.Diagnostics.Property_or_signature_expected; + case 6: return ts.Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected; + case 7: return ts.Diagnostics.Enum_member_expected; + case 8: return ts.Diagnostics.Expression_expected; + case 9: return ts.Diagnostics.Variable_declaration_expected; + case 10: return ts.Diagnostics.Property_destructuring_pattern_expected; + case 11: return ts.Diagnostics.Array_element_destructuring_pattern_expected; + case 12: return ts.Diagnostics.Argument_expression_expected; + case 13: return ts.Diagnostics.Property_assignment_expected; + case 14: return ts.Diagnostics.Expression_or_comma_expected; + case 15: return ts.Diagnostics.Parameter_declaration_expected; + case 16: return ts.Diagnostics.Type_parameter_declaration_expected; + case 17: return ts.Diagnostics.Type_argument_expected; + case 18: return ts.Diagnostics.Type_expected; + case 19: return ts.Diagnostics.Unexpected_token_expected; + case 20: return ts.Diagnostics.Identifier_expected; + } + } + ; + function parseDelimitedList(kind, parseElement, considerSemicolonAsDelimeter) { + var saveParsingContext = parsingContext; + parsingContext |= 1 << kind; + var result = []; + result.pos = getNodePos(); + var commaStart = -1; + while (true) { + if (isListElement(kind, false)) { + result.push(parseListElement(kind, parseElement)); + commaStart = scanner.getTokenPos(); + if (parseOptional(23)) { + continue; + } + commaStart = -1; + if (isListTerminator(kind)) { + break; + } + parseExpected(23); + if (considerSemicolonAsDelimeter && token === 22 && !scanner.hasPrecedingLineBreak()) { + nextToken(); + } + continue; + } + if (isListTerminator(kind)) { + break; + } + if (abortParsingListOrMoveToNextToken(kind)) { + break; + } + } + if (commaStart >= 0) { + result.hasTrailingComma = true; + } + result.end = getNodeEnd(); + parsingContext = saveParsingContext; + return result; + } + function createMissingList() { + var pos = getNodePos(); + var result = []; + result.pos = pos; + result.end = pos; + return result; + } + function parseBracketedList(kind, parseElement, open, close) { + if (parseExpected(open)) { + var result = parseDelimitedList(kind, parseElement); + parseExpected(close); + return result; + } + return createMissingList(); + } + function parseEntityName(allowReservedWords, diagnosticMessage) { + var entity = parseIdentifier(diagnosticMessage); + while (parseOptional(20)) { + var node = createNode(126, entity.pos); + node.left = entity; + node.right = parseRightSideOfDot(allowReservedWords); + entity = finishNode(node); + } + return entity; + } + function parseRightSideOfDot(allowIdentifierNames) { + if (scanner.hasPrecedingLineBreak() && scanner.isReservedWord()) { + var matchesPattern = lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); + if (matchesPattern) { + return createMissingNode(65, true, ts.Diagnostics.Identifier_expected); + } + } + return allowIdentifierNames ? parseIdentifierName() : parseIdentifier(); + } + function parseTemplateExpression() { + var template = createNode(171); + template.head = parseLiteralNode(); + ts.Debug.assert(template.head.kind === 11, "Template head has wrong token kind"); + var templateSpans = []; + templateSpans.pos = getNodePos(); + do { + templateSpans.push(parseTemplateSpan()); + } while (templateSpans[templateSpans.length - 1].literal.kind === 12); + templateSpans.end = getNodeEnd(); + template.templateSpans = templateSpans; + return finishNode(template); + } + function parseTemplateSpan() { + var span = createNode(176); + span.expression = allowInAnd(parseExpression); + var literal; + if (token === 15) { + reScanTemplateToken(); + literal = parseLiteralNode(); + } + else { + literal = parseExpectedToken(13, false, ts.Diagnostics._0_expected, ts.tokenToString(15)); + } + span.literal = literal; + return finishNode(span); + } + function parseLiteralNode(internName) { + var node = createNode(token); + var text = scanner.getTokenValue(); + node.text = internName ? internIdentifier(text) : text; + if (scanner.hasExtendedUnicodeEscape()) { + node.hasExtendedUnicodeEscape = true; + } + if (scanner.isUnterminated()) { + node.isUnterminated = true; + } + var tokenPos = scanner.getTokenPos(); + nextToken(); + finishNode(node); + if (node.kind === 7 + && sourceText.charCodeAt(tokenPos) === 48 + && ts.isOctalDigit(sourceText.charCodeAt(tokenPos + 1))) { + node.flags |= 16384; + } + return node; + } + function parseTypeReference() { + var node = createNode(141); + node.typeName = parseEntityName(false, ts.Diagnostics.Type_expected); + if (!scanner.hasPrecedingLineBreak() && token === 24) { + node.typeArguments = parseBracketedList(17, parseType, 24, 25); + } + return finishNode(node); + } + function parseTypeQuery() { + var node = createNode(144); + parseExpected(97); + node.exprName = parseEntityName(true); + return finishNode(node); + } + function parseTypeParameter() { + var node = createNode(128); + node.name = parseIdentifier(); + if (parseOptional(79)) { + if (isStartOfType() || !isStartOfExpression()) { + node.constraint = parseType(); + } + else { + node.expression = parseUnaryExpressionOrHigher(); + } + } + return finishNode(node); + } + function parseTypeParameters() { + if (token === 24) { + return parseBracketedList(16, parseTypeParameter, 24, 25); + } + } + function parseParameterType() { + if (parseOptional(51)) { + return token === 8 + ? parseLiteralNode(true) + : parseType(); + } + return undefined; + } + function isStartOfParameter() { + return token === 21 || isIdentifierOrPattern() || ts.isModifier(token) || token === 52; + } + function setModifiers(node, modifiers) { + if (modifiers) { + node.flags |= modifiers.flags; + node.modifiers = modifiers; + } + } + function parseParameter() { + var node = createNode(129); + node.decorators = parseDecorators(); + setModifiers(node, parseModifiers()); + node.dotDotDotToken = parseOptionalToken(21); + node.name = inGeneratorParameterContext() ? doInYieldContext(parseIdentifierOrPattern) : parseIdentifierOrPattern(); + if (ts.getFullWidth(node.name) === 0 && node.flags === 0 && ts.isModifier(token)) { + nextToken(); + } + node.questionToken = parseOptionalToken(50); + node.type = parseParameterType(); + node.initializer = inGeneratorParameterContext() ? doOutsideOfYieldContext(parseParameterInitializer) : parseParameterInitializer(); + return finishNode(node); + } + function parseParameterInitializer() { + return parseInitializer(true); + } + function fillSignature(returnToken, yieldAndGeneratorParameterContext, requireCompleteParameterList, signature) { + var returnTokenRequired = returnToken === 32; + signature.typeParameters = parseTypeParameters(); + signature.parameters = parseParameterList(yieldAndGeneratorParameterContext, requireCompleteParameterList); + if (returnTokenRequired) { + parseExpected(returnToken); + signature.type = parseType(); + } + else if (parseOptional(returnToken)) { + signature.type = parseType(); + } + } + function parseParameterList(yieldAndGeneratorParameterContext, requireCompleteParameterList) { + if (parseExpected(16)) { + var savedYieldContext = inYieldContext(); + var savedGeneratorParameterContext = inGeneratorParameterContext(); + setYieldContext(yieldAndGeneratorParameterContext); + setGeneratorParameterContext(yieldAndGeneratorParameterContext); + var result = parseDelimitedList(15, parseParameter); + setYieldContext(savedYieldContext); + setGeneratorParameterContext(savedGeneratorParameterContext); + if (!parseExpected(17) && requireCompleteParameterList) { + return undefined; + } + return result; + } + return requireCompleteParameterList ? undefined : createMissingList(); + } + function parseTypeMemberSemicolon() { + if (parseOptional(23)) { + return; + } + parseSemicolon(); + } + function parseSignatureMember(kind) { + var node = createNode(kind); + if (kind === 139) { + parseExpected(88); + } + fillSignature(51, false, false, node); + parseTypeMemberSemicolon(); + return finishNode(node); + } + function isIndexSignature() { + if (token !== 18) { + return false; + } + return lookAhead(isUnambiguouslyIndexSignature); + } + function isUnambiguouslyIndexSignature() { + nextToken(); + if (token === 21 || token === 19) { + return true; + } + if (ts.isModifier(token)) { + nextToken(); + if (isIdentifier()) { + return true; + } + } + else if (!isIdentifier()) { + return false; + } + else { + nextToken(); + } + if (token === 51 || token === 23) { + return true; + } + if (token !== 50) { + return false; + } + nextToken(); + return token === 51 || token === 23 || token === 19; + } + function parseIndexSignatureDeclaration(fullStart, decorators, modifiers) { + var node = createNode(140, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + node.parameters = parseBracketedList(15, parseParameter, 18, 19); + node.type = parseTypeAnnotation(); + parseTypeMemberSemicolon(); + return finishNode(node); + } + function parsePropertyOrMethodSignature() { + var fullStart = scanner.getStartPos(); + var name = parsePropertyName(); + var questionToken = parseOptionalToken(50); + if (token === 16 || token === 24) { + var method = createNode(133, fullStart); + method.name = name; + method.questionToken = questionToken; + fillSignature(51, false, false, method); + parseTypeMemberSemicolon(); + return finishNode(method); + } + else { + var property = createNode(131, fullStart); + property.name = name; + property.questionToken = questionToken; + property.type = parseTypeAnnotation(); + parseTypeMemberSemicolon(); + return finishNode(property); + } + } + function isStartOfTypeMember() { + switch (token) { + case 16: + case 24: + case 18: + return true; + default: + if (ts.isModifier(token)) { + var result = lookAhead(isStartOfIndexSignatureDeclaration); + if (result) { + return result; + } + } + return isLiteralPropertyName() && lookAhead(isTypeMemberWithLiteralPropertyName); + } + } + function isStartOfIndexSignatureDeclaration() { + while (ts.isModifier(token)) { + nextToken(); + } + return isIndexSignature(); + } + function isTypeMemberWithLiteralPropertyName() { + nextToken(); + return token === 16 || + token === 24 || + token === 50 || + token === 51 || + canParseSemicolon(); + } + function parseTypeMember() { + switch (token) { + case 16: + case 24: + return parseSignatureMember(138); + case 18: + return isIndexSignature() + ? parseIndexSignatureDeclaration(scanner.getStartPos(), undefined, undefined) + : parsePropertyOrMethodSignature(); + case 88: + if (lookAhead(isStartOfConstructSignature)) { + return parseSignatureMember(139); + } + case 8: + case 7: + return parsePropertyOrMethodSignature(); + default: + if (ts.isModifier(token)) { + var result = tryParse(parseIndexSignatureWithModifiers); + if (result) { + return result; + } + } + if (isIdentifierOrKeyword()) { + return parsePropertyOrMethodSignature(); + } + } + } + function parseIndexSignatureWithModifiers() { + var fullStart = scanner.getStartPos(); + var decorators = parseDecorators(); + var modifiers = parseModifiers(); + return isIndexSignature() + ? parseIndexSignatureDeclaration(fullStart, decorators, modifiers) + : undefined; + } + function isStartOfConstructSignature() { + nextToken(); + return token === 16 || token === 24; + } + function parseTypeLiteral() { + var node = createNode(145); + node.members = parseObjectTypeMembers(); + return finishNode(node); + } + function parseObjectTypeMembers() { + var members; + if (parseExpected(14)) { + members = parseList(5, false, parseTypeMember); + parseExpected(15); + } + else { + members = createMissingList(); + } + return members; + } + function parseTupleType() { + var node = createNode(147); + node.elementTypes = parseBracketedList(18, parseType, 18, 19); + return finishNode(node); + } + function parseParenthesizedType() { + var node = createNode(149); + parseExpected(16); + node.type = parseType(); + parseExpected(17); + return finishNode(node); + } + function parseFunctionOrConstructorType(kind) { + var node = createNode(kind); + if (kind === 143) { + parseExpected(88); + } + fillSignature(32, false, false, node); + return finishNode(node); + } + function parseKeywordAndNoDot() { + var node = parseTokenNode(); + return token === 20 ? undefined : node; + } + function parseNonArrayType() { + switch (token) { + case 112: + case 121: + case 119: + case 113: + case 122: + var node = tryParse(parseKeywordAndNoDot); + return node || parseTypeReference(); + case 99: + return parseTokenNode(); + case 97: + return parseTypeQuery(); + case 14: + return parseTypeLiteral(); + case 18: + return parseTupleType(); + case 16: + return parseParenthesizedType(); + default: + return parseTypeReference(); + } + } + function isStartOfType() { + switch (token) { + case 112: + case 121: + case 119: + case 113: + case 122: + case 99: + case 97: + case 14: + case 18: + case 24: + case 88: + return true; + case 16: + return lookAhead(isStartOfParenthesizedOrFunctionType); + default: + return isIdentifier(); + } + } + function isStartOfParenthesizedOrFunctionType() { + nextToken(); + return token === 17 || isStartOfParameter() || isStartOfType(); + } + function parseArrayTypeOrHigher() { + var type = parseNonArrayType(); + while (!scanner.hasPrecedingLineBreak() && parseOptional(18)) { + parseExpected(19); + var node = createNode(146, type.pos); + node.elementType = type; + type = finishNode(node); + } + return type; + } + function parseUnionTypeOrHigher() { + var type = parseArrayTypeOrHigher(); + if (token === 44) { + var types = [type]; + types.pos = type.pos; + while (parseOptional(44)) { + types.push(parseArrayTypeOrHigher()); + } + types.end = getNodeEnd(); + var node = createNode(148, type.pos); + node.types = types; + type = finishNode(node); + } + return type; + } + function isStartOfFunctionType() { + if (token === 24) { + return true; + } + return token === 16 && lookAhead(isUnambiguouslyStartOfFunctionType); + } + function isUnambiguouslyStartOfFunctionType() { + nextToken(); + if (token === 17 || token === 21) { + return true; + } + if (isIdentifier() || ts.isModifier(token)) { + nextToken(); + if (token === 51 || token === 23 || + token === 50 || token === 53 || + isIdentifier() || ts.isModifier(token)) { + return true; + } + if (token === 17) { + nextToken(); + if (token === 32) { + return true; + } + } + } + return false; + } + function parseType() { + var savedYieldContext = inYieldContext(); + var savedGeneratorParameterContext = inGeneratorParameterContext(); + setYieldContext(false); + setGeneratorParameterContext(false); + var result = parseTypeWorker(); + setYieldContext(savedYieldContext); + setGeneratorParameterContext(savedGeneratorParameterContext); + return result; + } + function parseTypeWorker() { + if (isStartOfFunctionType()) { + return parseFunctionOrConstructorType(142); + } + if (token === 88) { + return parseFunctionOrConstructorType(143); + } + return parseUnionTypeOrHigher(); + } + function parseTypeAnnotation() { + return parseOptional(51) ? parseType() : undefined; + } + function isStartOfLeftHandSideExpression() { + switch (token) { + case 93: + case 91: + case 89: + case 95: + case 80: + case 7: + case 8: + case 10: + case 11: + case 16: + case 18: + case 14: + case 83: + case 69: + case 88: + case 36: + case 57: + case 65: + return true; + default: + return isIdentifier(); + } + } + function isStartOfExpression() { + if (isStartOfLeftHandSideExpression()) { + return true; + } + switch (token) { + case 33: + case 34: + case 47: + case 46: + case 74: + case 97: + case 99: + case 38: + case 39: + case 24: + case 110: + return true; + default: + if (isBinaryOperator()) { + return true; + } + return isIdentifier(); + } + } + function isStartOfExpressionStatement() { + return token !== 14 && + token !== 83 && + token !== 69 && + token !== 52 && + isStartOfExpression(); + } + function parseExpression() { + // Expression[in]: + // AssignmentExpression[in] + // Expression[in] , AssignmentExpression[in] + var saveDecoratorContext = inDecoratorContext(); + if (saveDecoratorContext) { + setDecoratorContext(false); + } + var expr = parseAssignmentExpressionOrHigher(); + var operatorToken; + while ((operatorToken = parseOptionalToken(23))) { + expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher()); + } + if (saveDecoratorContext) { + setDecoratorContext(true); + } + return expr; + } + function parseInitializer(inParameter) { + if (token !== 53) { + if (scanner.hasPrecedingLineBreak() || (inParameter && token === 14) || !isStartOfExpression()) { + return undefined; + } + } + parseExpected(53); + return parseAssignmentExpressionOrHigher(); + } + function parseAssignmentExpressionOrHigher() { + // AssignmentExpression[in,yield]: + // 1) ConditionalExpression[?in,?yield] + // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield] + // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield] + // 4) ArrowFunctionExpression[?in,?yield] + // 5) [+Yield] YieldExpression[?In] + // + // Note: for ease of implementation we treat productions '2' and '3' as the same thing. + // (i.e. they're both BinaryExpressions with an assignment operator in it). + if (isYieldExpression()) { + return parseYieldExpression(); + } + var arrowExpression = tryParseParenthesizedArrowFunctionExpression(); + if (arrowExpression) { + return arrowExpression; + } + var expr = parseBinaryExpressionOrHigher(0); + if (expr.kind === 65 && token === 32) { + return parseSimpleArrowFunctionExpression(expr); + } + if (ts.isLeftHandSideExpression(expr) && ts.isAssignmentOperator(reScanGreaterToken())) { + return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher()); + } + return parseConditionalExpressionRest(expr); + } + function isYieldExpression() { + if (token === 110) { + if (inYieldContext()) { + return true; + } + if (inStrictModeContext()) { + return true; + } + return lookAhead(nextTokenIsIdentifierOnSameLine); + } + return false; + } + function nextTokenIsIdentifierOnSameLine() { + nextToken(); + return !scanner.hasPrecedingLineBreak() && isIdentifier(); + } + function nextTokenIsIdentifierOrStartOfDestructuringOnTheSameLine() { + nextToken(); + return !scanner.hasPrecedingLineBreak() && + (isIdentifier() || token === 14 || token === 18); + } + function parseYieldExpression() { + var node = createNode(172); + nextToken(); + if (!scanner.hasPrecedingLineBreak() && + (token === 35 || isStartOfExpression())) { + node.asteriskToken = parseOptionalToken(35); + node.expression = parseAssignmentExpressionOrHigher(); + return finishNode(node); + } + else { + return finishNode(node); + } + } + function parseSimpleArrowFunctionExpression(identifier) { + ts.Debug.assert(token === 32, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); + var node = createNode(163, identifier.pos); + var parameter = createNode(129, identifier.pos); + parameter.name = identifier; + finishNode(parameter); + node.parameters = [parameter]; + node.parameters.pos = parameter.pos; + node.parameters.end = parameter.end; + node.equalsGreaterThanToken = parseExpectedToken(32, false, ts.Diagnostics._0_expected, "=>"); + node.body = parseArrowFunctionExpressionBody(); + return finishNode(node); + } + function tryParseParenthesizedArrowFunctionExpression() { + var triState = isParenthesizedArrowFunctionExpression(); + if (triState === 0) { + return undefined; + } + var arrowFunction = triState === 1 + ? parseParenthesizedArrowFunctionExpressionHead(true) + : tryParse(parsePossibleParenthesizedArrowFunctionExpressionHead); + if (!arrowFunction) { + return undefined; + } + var lastToken = token; + arrowFunction.equalsGreaterThanToken = parseExpectedToken(32, false, ts.Diagnostics._0_expected, "=>"); + arrowFunction.body = (lastToken === 32 || lastToken === 14) + ? parseArrowFunctionExpressionBody() + : parseIdentifier(); + return finishNode(arrowFunction); + } + function isParenthesizedArrowFunctionExpression() { + if (token === 16 || token === 24) { + return lookAhead(isParenthesizedArrowFunctionExpressionWorker); + } + if (token === 32) { + return 1; + } + return 0; + } + function isParenthesizedArrowFunctionExpressionWorker() { + var first = token; + var second = nextToken(); + if (first === 16) { + if (second === 17) { + var third = nextToken(); + switch (third) { + case 32: + case 51: + case 14: + return 1; + default: + return 0; + } + } + if (second === 18 || second === 14) { + return 2; + } + if (second === 21) { + return 1; + } + if (!isIdentifier()) { + return 0; + } + if (nextToken() === 51) { + return 1; + } + return 2; + } + else { + ts.Debug.assert(first === 24); + if (!isIdentifier()) { + return 0; + } + return 2; + } + } + function parsePossibleParenthesizedArrowFunctionExpressionHead() { + return parseParenthesizedArrowFunctionExpressionHead(false); + } + function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity) { + var node = createNode(163); + fillSignature(51, false, !allowAmbiguity, node); + if (!node.parameters) { + return undefined; + } + if (!allowAmbiguity && token !== 32 && token !== 14) { + return undefined; + } + return node; + } + function parseArrowFunctionExpressionBody() { + if (token === 14) { + return parseFunctionBlock(false, false); + } + if (isStartOfStatement(true) && + !isStartOfExpressionStatement() && + token !== 83 && + token !== 69) { + return parseFunctionBlock(false, true); + } + return parseAssignmentExpressionOrHigher(); + } + function parseConditionalExpressionRest(leftOperand) { + var questionToken = parseOptionalToken(50); + if (!questionToken) { + return leftOperand; + } + var node = createNode(170, leftOperand.pos); + node.condition = leftOperand; + node.questionToken = questionToken; + node.whenTrue = doOutsideOfContext(disallowInAndDecoratorContext, parseAssignmentExpressionOrHigher); + node.colonToken = parseExpectedToken(51, false, ts.Diagnostics._0_expected, ts.tokenToString(51)); + node.whenFalse = parseAssignmentExpressionOrHigher(); + return finishNode(node); + } + function parseBinaryExpressionOrHigher(precedence) { + var leftOperand = parseUnaryExpressionOrHigher(); + return parseBinaryExpressionRest(precedence, leftOperand); + } + function isInOrOfKeyword(t) { + return t === 86 || t === 125; + } + function parseBinaryExpressionRest(precedence, leftOperand) { + while (true) { + reScanGreaterToken(); + var newPrecedence = getBinaryOperatorPrecedence(); + if (newPrecedence <= precedence) { + break; + } + if (token === 86 && inDisallowInContext()) { + break; + } + leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence)); + } + return leftOperand; + } + function isBinaryOperator() { + if (inDisallowInContext() && token === 86) { + return false; + } + return getBinaryOperatorPrecedence() > 0; + } + function getBinaryOperatorPrecedence() { + switch (token) { + case 49: + return 1; + case 48: + return 2; + case 44: + return 3; + case 45: + return 4; + case 43: + return 5; + case 28: + case 29: + case 30: + case 31: + return 6; + case 24: + case 25: + case 26: + case 27: + case 87: + case 86: + return 7; + case 40: + case 41: + case 42: + return 8; + case 33: + case 34: + return 9; + case 35: + case 36: + case 37: + return 10; + } + return -1; + } + function makeBinaryExpression(left, operatorToken, right) { + var node = createNode(169, left.pos); + node.left = left; + node.operatorToken = operatorToken; + node.right = right; + return finishNode(node); + } + function parsePrefixUnaryExpression() { + var node = createNode(167); + node.operator = token; + nextToken(); + node.operand = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + function parseDeleteExpression() { + var node = createNode(164); + nextToken(); + node.expression = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + function parseTypeOfExpression() { + var node = createNode(165); + nextToken(); + node.expression = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + function parseVoidExpression() { + var node = createNode(166); + nextToken(); + node.expression = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + function parseUnaryExpressionOrHigher() { + switch (token) { + case 33: + case 34: + case 47: + case 46: + case 38: + case 39: + return parsePrefixUnaryExpression(); + case 74: + return parseDeleteExpression(); + case 97: + return parseTypeOfExpression(); + case 99: + return parseVoidExpression(); + case 24: + return parseTypeAssertion(); + default: + return parsePostfixExpressionOrHigher(); + } + } + function parsePostfixExpressionOrHigher() { + var expression = parseLeftHandSideExpressionOrHigher(); + ts.Debug.assert(ts.isLeftHandSideExpression(expression)); + if ((token === 38 || token === 39) && !scanner.hasPrecedingLineBreak()) { + var node = createNode(168, expression.pos); + node.operand = expression; + node.operator = token; + nextToken(); + return finishNode(node); + } + return expression; + } + function parseLeftHandSideExpressionOrHigher() { + var expression = token === 91 + ? parseSuperExpression() + : parseMemberExpressionOrHigher(); + return parseCallExpressionRest(expression); + } + function parseMemberExpressionOrHigher() { + var expression = parsePrimaryExpression(); + return parseMemberExpressionRest(expression); + } + function parseSuperExpression() { + var expression = parseTokenNode(); + if (token === 16 || token === 20) { + return expression; + } + var node = createNode(155, expression.pos); + node.expression = expression; + node.dotToken = parseExpectedToken(20, false, ts.Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); + node.name = parseRightSideOfDot(true); + return finishNode(node); + } + function parseTypeAssertion() { + var node = createNode(160); + parseExpected(24); + node.type = parseType(); + parseExpected(25); + node.expression = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + function parseMemberExpressionRest(expression) { + while (true) { + var dotToken = parseOptionalToken(20); + if (dotToken) { + var propertyAccess = createNode(155, expression.pos); + propertyAccess.expression = expression; + propertyAccess.dotToken = dotToken; + propertyAccess.name = parseRightSideOfDot(true); + expression = finishNode(propertyAccess); + continue; + } + if (!inDecoratorContext() && parseOptional(18)) { + var indexedAccess = createNode(156, expression.pos); + indexedAccess.expression = expression; + if (token !== 19) { + indexedAccess.argumentExpression = allowInAnd(parseExpression); + if (indexedAccess.argumentExpression.kind === 8 || indexedAccess.argumentExpression.kind === 7) { + var literal = indexedAccess.argumentExpression; + literal.text = internIdentifier(literal.text); + } + } + parseExpected(19); + expression = finishNode(indexedAccess); + continue; + } + if (token === 10 || token === 11) { + var tagExpression = createNode(159, expression.pos); + tagExpression.tag = expression; + tagExpression.template = token === 10 + ? parseLiteralNode() + : parseTemplateExpression(); + expression = finishNode(tagExpression); + continue; + } + return expression; + } + } + function parseCallExpressionRest(expression) { + while (true) { + expression = parseMemberExpressionRest(expression); + if (token === 24) { + var typeArguments = tryParse(parseTypeArgumentsInExpression); + if (!typeArguments) { + return expression; + } + var callExpr = createNode(157, expression.pos); + callExpr.expression = expression; + callExpr.typeArguments = typeArguments; + callExpr.arguments = parseArgumentList(); + expression = finishNode(callExpr); + continue; + } + else if (token === 16) { + var callExpr = createNode(157, expression.pos); + callExpr.expression = expression; + callExpr.arguments = parseArgumentList(); + expression = finishNode(callExpr); + continue; + } + return expression; + } + } + function parseArgumentList() { + parseExpected(16); + var result = parseDelimitedList(12, parseArgumentExpression); + parseExpected(17); + return result; + } + function parseTypeArgumentsInExpression() { + if (!parseOptional(24)) { + return undefined; + } + var typeArguments = parseDelimitedList(17, parseType); + if (!parseExpected(25)) { + return undefined; + } + return typeArguments && canFollowTypeArgumentsInExpression() + ? typeArguments + : undefined; + } + function canFollowTypeArgumentsInExpression() { + switch (token) { + case 16: + case 20: + case 17: + case 19: + case 51: + case 22: + case 50: + case 28: + case 30: + case 29: + case 31: + case 48: + case 49: + case 45: + case 43: + case 44: + case 15: + case 1: + return true; + case 23: + case 14: + default: + return false; + } + } + function parsePrimaryExpression() { + switch (token) { + case 7: + case 8: + case 10: + return parseLiteralNode(); + case 93: + case 91: + case 89: + case 95: + case 80: + return parseTokenNode(); + case 16: + return parseParenthesizedExpression(); + case 18: + return parseArrayLiteralExpression(); + case 14: + return parseObjectLiteralExpression(); + case 69: + return parseClassExpression(); + case 83: + return parseFunctionExpression(); + case 88: + return parseNewExpression(); + case 36: + case 57: + if (reScanSlashToken() === 9) { + return parseLiteralNode(); + } + break; + case 11: + return parseTemplateExpression(); + } + return parseIdentifier(ts.Diagnostics.Expression_expected); + } + function parseParenthesizedExpression() { + var node = createNode(161); + parseExpected(16); + node.expression = allowInAnd(parseExpression); + parseExpected(17); + return finishNode(node); + } + function parseSpreadElement() { + var node = createNode(173); + parseExpected(21); + node.expression = parseAssignmentExpressionOrHigher(); + return finishNode(node); + } + function parseArgumentOrArrayLiteralElement() { + return token === 21 ? parseSpreadElement() : + token === 23 ? createNode(175) : + parseAssignmentExpressionOrHigher(); + } + function parseArgumentExpression() { + return doOutsideOfContext(disallowInAndDecoratorContext, parseArgumentOrArrayLiteralElement); + } + function parseArrayLiteralExpression() { + var node = createNode(153); + parseExpected(18); + if (scanner.hasPrecedingLineBreak()) + node.flags |= 512; + node.elements = parseDelimitedList(14, parseArgumentOrArrayLiteralElement); + parseExpected(19); + return finishNode(node); + } + function tryParseAccessorDeclaration(fullStart, decorators, modifiers) { + if (parseContextualModifier(116)) { + return parseAccessorDeclaration(136, fullStart, decorators, modifiers); + } + else if (parseContextualModifier(120)) { + return parseAccessorDeclaration(137, fullStart, decorators, modifiers); + } + return undefined; + } + function parseObjectLiteralElement() { + var fullStart = scanner.getStartPos(); + var decorators = parseDecorators(); + var modifiers = parseModifiers(); + var accessor = tryParseAccessorDeclaration(fullStart, decorators, modifiers); + if (accessor) { + return accessor; + } + var asteriskToken = parseOptionalToken(35); + var tokenIsIdentifier = isIdentifier(); + var nameToken = token; + var propertyName = parsePropertyName(); + var questionToken = parseOptionalToken(50); + if (asteriskToken || token === 16 || token === 24) { + return parseMethodDeclaration(fullStart, decorators, modifiers, asteriskToken, propertyName, questionToken); + } + if ((token === 23 || token === 15) && tokenIsIdentifier) { + var shorthandDeclaration = createNode(225, fullStart); + shorthandDeclaration.name = propertyName; + shorthandDeclaration.questionToken = questionToken; + return finishNode(shorthandDeclaration); + } + else { + var propertyAssignment = createNode(224, fullStart); + propertyAssignment.name = propertyName; + propertyAssignment.questionToken = questionToken; + parseExpected(51); + propertyAssignment.initializer = allowInAnd(parseAssignmentExpressionOrHigher); + return finishNode(propertyAssignment); + } + } + function parseObjectLiteralExpression() { + var node = createNode(154); + parseExpected(14); + if (scanner.hasPrecedingLineBreak()) { + node.flags |= 512; + } + node.properties = parseDelimitedList(13, parseObjectLiteralElement, true); + parseExpected(15); + return finishNode(node); + } + function parseFunctionExpression() { + var saveDecoratorContext = inDecoratorContext(); + if (saveDecoratorContext) { + setDecoratorContext(false); + } + var node = createNode(162); + parseExpected(83); + node.asteriskToken = parseOptionalToken(35); + node.name = node.asteriskToken ? doInYieldContext(parseOptionalIdentifier) : parseOptionalIdentifier(); + fillSignature(51, !!node.asteriskToken, false, node); + node.body = parseFunctionBlock(!!node.asteriskToken, false); + if (saveDecoratorContext) { + setDecoratorContext(true); + } + return finishNode(node); + } + function parseOptionalIdentifier() { + return isIdentifier() ? parseIdentifier() : undefined; + } + function parseNewExpression() { + var node = createNode(158); + parseExpected(88); + node.expression = parseMemberExpressionOrHigher(); + node.typeArguments = tryParse(parseTypeArgumentsInExpression); + if (node.typeArguments || token === 16) { + node.arguments = parseArgumentList(); + } + return finishNode(node); + } + function parseBlock(ignoreMissingOpenBrace, checkForStrictMode, diagnosticMessage) { + var node = createNode(179); + if (parseExpected(14, diagnosticMessage) || ignoreMissingOpenBrace) { + node.statements = parseList(2, checkForStrictMode, parseStatement); + parseExpected(15); + } + else { + node.statements = createMissingList(); + } + return finishNode(node); + } + function parseFunctionBlock(allowYield, ignoreMissingOpenBrace, diagnosticMessage) { + var savedYieldContext = inYieldContext(); + setYieldContext(allowYield); + var saveDecoratorContext = inDecoratorContext(); + if (saveDecoratorContext) { + setDecoratorContext(false); + } + var block = parseBlock(ignoreMissingOpenBrace, true, diagnosticMessage); + if (saveDecoratorContext) { + setDecoratorContext(true); + } + setYieldContext(savedYieldContext); + return block; + } + function parseEmptyStatement() { + var node = createNode(181); + parseExpected(22); + return finishNode(node); + } + function parseIfStatement() { + var node = createNode(183); + parseExpected(84); + parseExpected(16); + node.expression = allowInAnd(parseExpression); + parseExpected(17); + node.thenStatement = parseStatement(); + node.elseStatement = parseOptional(76) ? parseStatement() : undefined; + return finishNode(node); + } + function parseDoStatement() { + var node = createNode(184); + parseExpected(75); + node.statement = parseStatement(); + parseExpected(100); + parseExpected(16); + node.expression = allowInAnd(parseExpression); + parseExpected(17); + parseOptional(22); + return finishNode(node); + } + function parseWhileStatement() { + var node = createNode(185); + parseExpected(100); + parseExpected(16); + node.expression = allowInAnd(parseExpression); + parseExpected(17); + node.statement = parseStatement(); + return finishNode(node); + } + function parseForOrForInOrForOfStatement() { + var pos = getNodePos(); + parseExpected(82); + parseExpected(16); + var initializer = undefined; + if (token !== 22) { + if (token === 98 || token === 104 || token === 70) { + initializer = parseVariableDeclarationList(true); + } + else { + initializer = disallowInAnd(parseExpression); + } + } + var forOrForInOrForOfStatement; + if (parseOptional(86)) { + var forInStatement = createNode(187, pos); + forInStatement.initializer = initializer; + forInStatement.expression = allowInAnd(parseExpression); + parseExpected(17); + forOrForInOrForOfStatement = forInStatement; + } + else if (parseOptional(125)) { + var forOfStatement = createNode(188, pos); + forOfStatement.initializer = initializer; + forOfStatement.expression = allowInAnd(parseAssignmentExpressionOrHigher); + parseExpected(17); + forOrForInOrForOfStatement = forOfStatement; + } + else { + var forStatement = createNode(186, pos); + forStatement.initializer = initializer; + parseExpected(22); + if (token !== 22 && token !== 17) { + forStatement.condition = allowInAnd(parseExpression); + } + parseExpected(22); + if (token !== 17) { + forStatement.incrementor = allowInAnd(parseExpression); + } + parseExpected(17); + forOrForInOrForOfStatement = forStatement; + } + forOrForInOrForOfStatement.statement = parseStatement(); + return finishNode(forOrForInOrForOfStatement); + } + function parseBreakOrContinueStatement(kind) { + var node = createNode(kind); + parseExpected(kind === 190 ? 66 : 71); + if (!canParseSemicolon()) { + node.label = parseIdentifier(); + } + parseSemicolon(); + return finishNode(node); + } + function parseReturnStatement() { + var node = createNode(191); + parseExpected(90); + if (!canParseSemicolon()) { + node.expression = allowInAnd(parseExpression); + } + parseSemicolon(); + return finishNode(node); + } + function parseWithStatement() { + var node = createNode(192); + parseExpected(101); + parseExpected(16); + node.expression = allowInAnd(parseExpression); + parseExpected(17); + node.statement = parseStatement(); + return finishNode(node); + } + function parseCaseClause() { + var node = createNode(220); + parseExpected(67); + node.expression = allowInAnd(parseExpression); + parseExpected(51); + node.statements = parseList(4, false, parseStatement); + return finishNode(node); + } + function parseDefaultClause() { + var node = createNode(221); + parseExpected(73); + parseExpected(51); + node.statements = parseList(4, false, parseStatement); + return finishNode(node); + } + function parseCaseOrDefaultClause() { + return token === 67 ? parseCaseClause() : parseDefaultClause(); + } + function parseSwitchStatement() { + var node = createNode(193); + parseExpected(92); + parseExpected(16); + node.expression = allowInAnd(parseExpression); + parseExpected(17); + var caseBlock = createNode(207, scanner.getStartPos()); + parseExpected(14); + caseBlock.clauses = parseList(3, false, parseCaseOrDefaultClause); + parseExpected(15); + node.caseBlock = finishNode(caseBlock); + return finishNode(node); + } + function parseThrowStatement() { + // ThrowStatement[Yield] : + // throw [no LineTerminator here]Expression[In, ?Yield]; + var node = createNode(195); + parseExpected(94); + node.expression = scanner.hasPrecedingLineBreak() ? undefined : allowInAnd(parseExpression); + parseSemicolon(); + return finishNode(node); + } + function parseTryStatement() { + var node = createNode(196); + parseExpected(96); + node.tryBlock = parseBlock(false, false); + node.catchClause = token === 68 ? parseCatchClause() : undefined; + if (!node.catchClause || token === 81) { + parseExpected(81); + node.finallyBlock = parseBlock(false, false); + } + return finishNode(node); + } + function parseCatchClause() { + var result = createNode(223); + parseExpected(68); + if (parseExpected(16)) { + result.variableDeclaration = parseVariableDeclaration(); + } + parseExpected(17); + result.block = parseBlock(false, false); + return finishNode(result); + } + function parseDebuggerStatement() { + var node = createNode(197); + parseExpected(72); + parseSemicolon(); + return finishNode(node); + } + function parseExpressionOrLabeledStatement() { + var fullStart = scanner.getStartPos(); + var expression = allowInAnd(parseExpression); + if (expression.kind === 65 && parseOptional(51)) { + var labeledStatement = createNode(194, fullStart); + labeledStatement.label = expression; + labeledStatement.statement = parseStatement(); + return finishNode(labeledStatement); + } + else { + var expressionStatement = createNode(182, fullStart); + expressionStatement.expression = expression; + parseSemicolon(); + return finishNode(expressionStatement); + } + } + function isStartOfStatement(inErrorRecovery) { + if (ts.isModifier(token)) { + var result = lookAhead(parseVariableStatementOrFunctionDeclarationOrClassDeclarationWithDecoratorsOrModifiers); + if (result) { + return true; + } + } + switch (token) { + case 22: + return !inErrorRecovery; + case 14: + case 98: + case 104: + case 83: + case 69: + case 84: + case 75: + case 100: + case 82: + case 71: + case 66: + case 90: + case 101: + case 92: + case 94: + case 96: + case 72: + case 68: + case 81: + return true; + case 70: + var isConstEnum = lookAhead(nextTokenIsEnumKeyword); + return !isConstEnum; + case 103: + case 117: + case 77: + case 123: + if (isDeclarationStart()) { + return false; + } + case 108: + case 106: + case 107: + case 109: + if (lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine)) { + return false; + } + default: + return isStartOfExpression(); + } + } + function nextTokenIsEnumKeyword() { + nextToken(); + return token === 77; + } + function nextTokenIsIdentifierOrKeywordOnSameLine() { + nextToken(); + return isIdentifierOrKeyword() && !scanner.hasPrecedingLineBreak(); + } + function parseStatement() { + switch (token) { + case 14: + return parseBlock(false, false); + case 98: + case 70: + return parseVariableStatement(scanner.getStartPos(), undefined, undefined); + case 83: + return parseFunctionDeclaration(scanner.getStartPos(), undefined, undefined); + case 69: + return parseClassDeclaration(scanner.getStartPos(), undefined, undefined); + case 22: + return parseEmptyStatement(); + case 84: + return parseIfStatement(); + case 75: + return parseDoStatement(); + case 100: + return parseWhileStatement(); + case 82: + return parseForOrForInOrForOfStatement(); + case 71: + return parseBreakOrContinueStatement(189); + case 66: + return parseBreakOrContinueStatement(190); + case 90: + return parseReturnStatement(); + case 101: + return parseWithStatement(); + case 92: + return parseSwitchStatement(); + case 94: + return parseThrowStatement(); + case 96: + case 68: + case 81: + return parseTryStatement(); + case 72: + return parseDebuggerStatement(); + case 104: + if (isLetDeclaration()) { + return parseVariableStatement(scanner.getStartPos(), undefined, undefined); + } + default: + if (ts.isModifier(token) || token === 52) { + var result = tryParse(parseVariableStatementOrFunctionDeclarationOrClassDeclarationWithDecoratorsOrModifiers); + if (result) { + return result; + } + } + return parseExpressionOrLabeledStatement(); + } + } + function parseVariableStatementOrFunctionDeclarationOrClassDeclarationWithDecoratorsOrModifiers() { + var start = scanner.getStartPos(); + var decorators = parseDecorators(); + var modifiers = parseModifiers(); + switch (token) { + case 70: + var nextTokenIsEnum = lookAhead(nextTokenIsEnumKeyword); + if (nextTokenIsEnum) { + return undefined; + } + return parseVariableStatement(start, decorators, modifiers); + case 104: + if (!isLetDeclaration()) { + return undefined; + } + return parseVariableStatement(start, decorators, modifiers); + case 98: + return parseVariableStatement(start, decorators, modifiers); + case 83: + return parseFunctionDeclaration(start, decorators, modifiers); + case 69: + return parseClassDeclaration(start, decorators, modifiers); + } + return undefined; + } + function parseFunctionBlockOrSemicolon(isGenerator, diagnosticMessage) { + if (token !== 14 && canParseSemicolon()) { + parseSemicolon(); + return; + } + return parseFunctionBlock(isGenerator, false, diagnosticMessage); + } + function parseArrayBindingElement() { + if (token === 23) { + return createNode(175); + } + var node = createNode(152); + node.dotDotDotToken = parseOptionalToken(21); + node.name = parseIdentifierOrPattern(); + node.initializer = parseInitializer(false); + return finishNode(node); + } + function parseObjectBindingElement() { + var node = createNode(152); + var tokenIsIdentifier = isIdentifier(); + var propertyName = parsePropertyName(); + if (tokenIsIdentifier && token !== 51) { + node.name = propertyName; + } + else { + parseExpected(51); + node.propertyName = propertyName; + node.name = parseIdentifierOrPattern(); + } + node.initializer = parseInitializer(false); + return finishNode(node); + } + function parseObjectBindingPattern() { + var node = createNode(150); + parseExpected(14); + node.elements = parseDelimitedList(10, parseObjectBindingElement); + parseExpected(15); + return finishNode(node); + } + function parseArrayBindingPattern() { + var node = createNode(151); + parseExpected(18); + node.elements = parseDelimitedList(11, parseArrayBindingElement); + parseExpected(19); + return finishNode(node); + } + function isIdentifierOrPattern() { + return token === 14 || token === 18 || isIdentifier(); + } + function parseIdentifierOrPattern() { + if (token === 18) { + return parseArrayBindingPattern(); + } + if (token === 14) { + return parseObjectBindingPattern(); + } + return parseIdentifier(); + } + function parseVariableDeclaration() { + var node = createNode(198); + node.name = parseIdentifierOrPattern(); + node.type = parseTypeAnnotation(); + if (!isInOrOfKeyword(token)) { + node.initializer = parseInitializer(false); + } + return finishNode(node); + } + function parseVariableDeclarationList(inForStatementInitializer) { + var node = createNode(199); + switch (token) { + case 98: + break; + case 104: + node.flags |= 4096; + break; + case 70: + node.flags |= 8192; + break; + default: + ts.Debug.fail(); + } + nextToken(); + if (token === 125 && lookAhead(canFollowContextualOfKeyword)) { + node.declarations = createMissingList(); + } + else { + var savedDisallowIn = inDisallowInContext(); + setDisallowInContext(inForStatementInitializer); + node.declarations = parseDelimitedList(9, parseVariableDeclaration); + setDisallowInContext(savedDisallowIn); + } + return finishNode(node); + } + function canFollowContextualOfKeyword() { + return nextTokenIsIdentifier() && nextToken() === 17; + } + function parseVariableStatement(fullStart, decorators, modifiers) { + var node = createNode(180, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + node.declarationList = parseVariableDeclarationList(false); + parseSemicolon(); + return finishNode(node); + } + function parseFunctionDeclaration(fullStart, decorators, modifiers) { + var node = createNode(200, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(83); + node.asteriskToken = parseOptionalToken(35); + node.name = node.flags & 256 ? parseOptionalIdentifier() : parseIdentifier(); + fillSignature(51, !!node.asteriskToken, false, node); + node.body = parseFunctionBlockOrSemicolon(!!node.asteriskToken, ts.Diagnostics.or_expected); + return finishNode(node); + } + function parseConstructorDeclaration(pos, decorators, modifiers) { + var node = createNode(135, pos); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(114); + fillSignature(51, false, false, node); + node.body = parseFunctionBlockOrSemicolon(false, ts.Diagnostics.or_expected); + return finishNode(node); + } + function parseMethodDeclaration(fullStart, decorators, modifiers, asteriskToken, name, questionToken, diagnosticMessage) { + var method = createNode(134, fullStart); + method.decorators = decorators; + setModifiers(method, modifiers); + method.asteriskToken = asteriskToken; + method.name = name; + method.questionToken = questionToken; + fillSignature(51, !!asteriskToken, false, method); + method.body = parseFunctionBlockOrSemicolon(!!asteriskToken, diagnosticMessage); + return finishNode(method); + } + function parsePropertyDeclaration(fullStart, decorators, modifiers, name, questionToken) { + var property = createNode(132, fullStart); + property.decorators = decorators; + setModifiers(property, modifiers); + property.name = name; + property.questionToken = questionToken; + property.type = parseTypeAnnotation(); + property.initializer = allowInAnd(parseNonParameterInitializer); + parseSemicolon(); + return finishNode(property); + } + function parsePropertyOrMethodDeclaration(fullStart, decorators, modifiers) { + var asteriskToken = parseOptionalToken(35); + var name = parsePropertyName(); + var questionToken = parseOptionalToken(50); + if (asteriskToken || token === 16 || token === 24) { + return parseMethodDeclaration(fullStart, decorators, modifiers, asteriskToken, name, questionToken, ts.Diagnostics.or_expected); + } + else { + return parsePropertyDeclaration(fullStart, decorators, modifiers, name, questionToken); + } + } + function parseNonParameterInitializer() { + return parseInitializer(false); + } + function parseAccessorDeclaration(kind, fullStart, decorators, modifiers) { + var node = createNode(kind, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + node.name = parsePropertyName(); + fillSignature(51, false, false, node); + node.body = parseFunctionBlockOrSemicolon(false); + return finishNode(node); + } + function isClassMemberModifier(idToken) { + switch (idToken) { + case 108: + case 106: + case 107: + case 109: + return true; + default: + return false; + } + } + function isClassMemberStart() { + var idToken; + if (token === 52) { + return true; + } + while (ts.isModifier(token)) { + idToken = token; + if (isClassMemberModifier(idToken)) { + return true; + } + nextToken(); + } + if (token === 35) { + return true; + } + if (isLiteralPropertyName()) { + idToken = token; + nextToken(); + } + if (token === 18) { + return true; + } + if (idToken !== undefined) { + if (!ts.isKeyword(idToken) || idToken === 120 || idToken === 116) { + return true; + } + switch (token) { + case 16: + case 24: + case 51: + case 53: + case 50: + return true; + default: + return canParseSemicolon(); + } + } + return false; + } + function parseDecorators() { + var decorators; + while (true) { + var decoratorStart = getNodePos(); + if (!parseOptional(52)) { + break; + } + if (!decorators) { + decorators = []; + decorators.pos = scanner.getStartPos(); + } + var decorator = createNode(130, decoratorStart); + decorator.expression = doInDecoratorContext(parseLeftHandSideExpressionOrHigher); + decorators.push(finishNode(decorator)); + } + if (decorators) { + decorators.end = getNodeEnd(); + } + return decorators; + } + function parseModifiers() { + var flags = 0; + var modifiers; + while (true) { + var modifierStart = scanner.getStartPos(); + var modifierKind = token; + if (!parseAnyContextualModifier()) { + break; + } + if (!modifiers) { + modifiers = []; + modifiers.pos = modifierStart; + } + flags |= ts.modifierToFlag(modifierKind); + modifiers.push(finishNode(createNode(modifierKind, modifierStart))); + } + if (modifiers) { + modifiers.flags = flags; + modifiers.end = scanner.getStartPos(); + } + return modifiers; + } + function parseClassElement() { + if (token === 22) { + var result = createNode(178); + nextToken(); + return finishNode(result); + } + var fullStart = getNodePos(); + var decorators = parseDecorators(); + var modifiers = parseModifiers(); + var accessor = tryParseAccessorDeclaration(fullStart, decorators, modifiers); + if (accessor) { + return accessor; + } + if (token === 114) { + return parseConstructorDeclaration(fullStart, decorators, modifiers); + } + if (isIndexSignature()) { + return parseIndexSignatureDeclaration(fullStart, decorators, modifiers); + } + if (isIdentifierOrKeyword() || + token === 8 || + token === 7 || + token === 35 || + token === 18) { + return parsePropertyOrMethodDeclaration(fullStart, decorators, modifiers); + } + if (decorators) { + var name_1 = createMissingNode(65, true, ts.Diagnostics.Declaration_expected); + return parsePropertyDeclaration(fullStart, decorators, modifiers, name_1, undefined); + } + ts.Debug.fail("Should not have attempted to parse class member declaration."); + } + function parseClassExpression() { + return parseClassDeclarationOrExpression(scanner.getStartPos(), undefined, undefined, 174); + } + function parseClassDeclaration(fullStart, decorators, modifiers) { + return parseClassDeclarationOrExpression(fullStart, decorators, modifiers, 201); + } + function parseClassDeclarationOrExpression(fullStart, decorators, modifiers, kind) { + var savedStrictModeContext = inStrictModeContext(); + setStrictModeContext(true); + var node = createNode(kind, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(69); + node.name = parseOptionalIdentifier(); + node.typeParameters = parseTypeParameters(); + node.heritageClauses = parseHeritageClauses(true); + if (parseExpected(14)) { + node.members = inGeneratorParameterContext() + ? doOutsideOfYieldContext(parseClassMembers) + : parseClassMembers(); + parseExpected(15); + } + else { + node.members = createMissingList(); + } + var finishedNode = finishNode(node); + setStrictModeContext(savedStrictModeContext); + return finishedNode; + } + function parseHeritageClauses(isClassHeritageClause) { + // ClassTail[Yield,GeneratorParameter] : See 14.5 + // [~GeneratorParameter]ClassHeritage[?Yield]opt { ClassBody[?Yield]opt } + // [+GeneratorParameter] ClassHeritageopt { ClassBodyopt } + if (isHeritageClause()) { + return isClassHeritageClause && inGeneratorParameterContext() + ? doOutsideOfYieldContext(parseHeritageClausesWorker) + : parseHeritageClausesWorker(); + } + return undefined; + } + function parseHeritageClausesWorker() { + return parseList(19, false, parseHeritageClause); + } + function parseHeritageClause() { + if (token === 79 || token === 102) { + var node = createNode(222); + node.token = token; + nextToken(); + node.types = parseDelimitedList(8, parseHeritageClauseElement); + return finishNode(node); + } + return undefined; + } + function parseHeritageClauseElement() { + var node = createNode(177); + node.expression = parseLeftHandSideExpressionOrHigher(); + if (token === 24) { + node.typeArguments = parseBracketedList(17, parseType, 24, 25); + } + return finishNode(node); + } + function isHeritageClause() { + return token === 79 || token === 102; + } + function parseClassMembers() { + return parseList(6, false, parseClassElement); + } + function parseInterfaceDeclaration(fullStart, decorators, modifiers) { + var node = createNode(202, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(103); + node.name = parseIdentifier(); + node.typeParameters = parseTypeParameters(); + node.heritageClauses = parseHeritageClauses(false); + node.members = parseObjectTypeMembers(); + return finishNode(node); + } + function parseTypeAliasDeclaration(fullStart, decorators, modifiers) { + var node = createNode(203, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(123); + node.name = parseIdentifier(); + parseExpected(53); + node.type = parseType(); + parseSemicolon(); + return finishNode(node); + } + function parseEnumMember() { + var node = createNode(226, scanner.getStartPos()); + node.name = parsePropertyName(); + node.initializer = allowInAnd(parseNonParameterInitializer); + return finishNode(node); + } + function parseEnumDeclaration(fullStart, decorators, modifiers) { + var node = createNode(204, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(77); + node.name = parseIdentifier(); + if (parseExpected(14)) { + node.members = parseDelimitedList(7, parseEnumMember); + parseExpected(15); + } + else { + node.members = createMissingList(); + } + return finishNode(node); + } + function parseModuleBlock() { + var node = createNode(206, scanner.getStartPos()); + if (parseExpected(14)) { + node.statements = parseList(1, false, parseModuleElement); + parseExpected(15); + } + else { + node.statements = createMissingList(); + } + return finishNode(node); + } + function parseInternalModuleTail(fullStart, decorators, modifiers, flags) { + var node = createNode(205, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + node.flags |= flags; + node.name = parseIdentifier(); + node.body = parseOptional(20) + ? parseInternalModuleTail(getNodePos(), undefined, undefined, 1) + : parseModuleBlock(); + return finishNode(node); + } + function parseAmbientExternalModuleDeclaration(fullStart, decorators, modifiers) { + var node = createNode(205, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + node.name = parseLiteralNode(true); + node.body = parseModuleBlock(); + return finishNode(node); + } + function parseModuleDeclaration(fullStart, decorators, modifiers) { + parseExpected(117); + return token === 8 + ? parseAmbientExternalModuleDeclaration(fullStart, decorators, modifiers) + : parseInternalModuleTail(fullStart, decorators, modifiers, modifiers ? modifiers.flags : 0); + } + function isExternalModuleReference() { + return token === 118 && + lookAhead(nextTokenIsOpenParen); + } + function nextTokenIsOpenParen() { + return nextToken() === 16; + } + function nextTokenIsCommaOrFromKeyword() { + nextToken(); + return token === 23 || + token === 124; + } + function parseImportDeclarationOrImportEqualsDeclaration(fullStart, decorators, modifiers) { + parseExpected(85); + var afterImportPos = scanner.getStartPos(); + var identifier; + if (isIdentifier()) { + identifier = parseIdentifier(); + if (token !== 23 && token !== 124) { + var importEqualsDeclaration = createNode(208, fullStart); + importEqualsDeclaration.decorators = decorators; + setModifiers(importEqualsDeclaration, modifiers); + importEqualsDeclaration.name = identifier; + parseExpected(53); + importEqualsDeclaration.moduleReference = parseModuleReference(); + parseSemicolon(); + return finishNode(importEqualsDeclaration); + } + } + var importDeclaration = createNode(209, fullStart); + importDeclaration.decorators = decorators; + setModifiers(importDeclaration, modifiers); + if (identifier || + token === 35 || + token === 14) { + importDeclaration.importClause = parseImportClause(identifier, afterImportPos); + parseExpected(124); + } + importDeclaration.moduleSpecifier = parseModuleSpecifier(); + parseSemicolon(); + return finishNode(importDeclaration); + } + function parseImportClause(identifier, fullStart) { + //ImportClause: + // ImportedDefaultBinding + // NameSpaceImport + // NamedImports + // ImportedDefaultBinding, NameSpaceImport + // ImportedDefaultBinding, NamedImports + var importClause = createNode(210, fullStart); + if (identifier) { + importClause.name = identifier; + } + if (!importClause.name || + parseOptional(23)) { + importClause.namedBindings = token === 35 ? parseNamespaceImport() : parseNamedImportsOrExports(212); + } + return finishNode(importClause); + } + function parseModuleReference() { + return isExternalModuleReference() + ? parseExternalModuleReference() + : parseEntityName(false); + } + function parseExternalModuleReference() { + var node = createNode(219); + parseExpected(118); + parseExpected(16); + node.expression = parseModuleSpecifier(); + parseExpected(17); + return finishNode(node); + } + function parseModuleSpecifier() { + var result = parseExpression(); + if (result.kind === 8) { + internIdentifier(result.text); + } + return result; + } + function parseNamespaceImport() { + var namespaceImport = createNode(211); + parseExpected(35); + parseExpected(111); + namespaceImport.name = parseIdentifier(); + return finishNode(namespaceImport); + } + function parseNamedImportsOrExports(kind) { + var node = createNode(kind); + node.elements = parseBracketedList(20, kind === 212 ? parseImportSpecifier : parseExportSpecifier, 14, 15); + return finishNode(node); + } + function parseExportSpecifier() { + return parseImportOrExportSpecifier(217); + } + function parseImportSpecifier() { + return parseImportOrExportSpecifier(213); + } + function parseImportOrExportSpecifier(kind) { + var node = createNode(kind); + var checkIdentifierIsKeyword = ts.isKeyword(token) && !isIdentifier(); + var checkIdentifierStart = scanner.getTokenPos(); + var checkIdentifierEnd = scanner.getTextPos(); + var identifierName = parseIdentifierName(); + if (token === 111) { + node.propertyName = identifierName; + parseExpected(111); + checkIdentifierIsKeyword = ts.isKeyword(token) && !isIdentifier(); + checkIdentifierStart = scanner.getTokenPos(); + checkIdentifierEnd = scanner.getTextPos(); + node.name = parseIdentifierName(); + } + else { + node.name = identifierName; + } + if (kind === 213 && checkIdentifierIsKeyword) { + parseErrorAtPosition(checkIdentifierStart, checkIdentifierEnd - checkIdentifierStart, ts.Diagnostics.Identifier_expected); + } + return finishNode(node); + } + function parseExportDeclaration(fullStart, decorators, modifiers) { + var node = createNode(215, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + if (parseOptional(35)) { + parseExpected(124); + node.moduleSpecifier = parseModuleSpecifier(); + } + else { + node.exportClause = parseNamedImportsOrExports(216); + if (parseOptional(124)) { + node.moduleSpecifier = parseModuleSpecifier(); + } + } + parseSemicolon(); + return finishNode(node); + } + function parseExportAssignment(fullStart, decorators, modifiers) { + var node = createNode(214, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + if (parseOptional(53)) { + node.isExportEquals = true; + } + else { + parseExpected(73); + } + node.expression = parseAssignmentExpressionOrHigher(); + parseSemicolon(); + return finishNode(node); + } + function isLetDeclaration() { + return inStrictModeContext() || lookAhead(nextTokenIsIdentifierOrStartOfDestructuringOnTheSameLine); + } + function isDeclarationStart(followsModifier) { + switch (token) { + case 98: + case 70: + case 83: + return true; + case 104: + return isLetDeclaration(); + case 69: + case 103: + case 77: + case 123: + return lookAhead(nextTokenIsIdentifierOrKeyword); + case 85: + return lookAhead(nextTokenCanFollowImportKeyword); + case 117: + return lookAhead(nextTokenIsIdentifierOrKeywordOrStringLiteral); + case 78: + return lookAhead(nextTokenCanFollowExportKeyword); + case 115: + case 108: + case 106: + case 107: + case 109: + return lookAhead(nextTokenIsDeclarationStart); + case 52: + return !followsModifier; + } + } + function isIdentifierOrKeyword() { + return token >= 65; + } + function nextTokenIsIdentifierOrKeyword() { + nextToken(); + return isIdentifierOrKeyword(); + } + function nextTokenIsIdentifierOrKeywordOrStringLiteral() { + nextToken(); + return isIdentifierOrKeyword() || token === 8; + } + function nextTokenCanFollowImportKeyword() { + nextToken(); + return isIdentifierOrKeyword() || token === 8 || + token === 35 || token === 14; + } + function nextTokenCanFollowExportKeyword() { + nextToken(); + return token === 53 || token === 35 || + token === 14 || token === 73 || isDeclarationStart(true); + } + function nextTokenIsDeclarationStart() { + nextToken(); + return isDeclarationStart(true); + } + function nextTokenIsAsKeyword() { + return nextToken() === 111; + } + function parseDeclaration() { + var fullStart = getNodePos(); + var decorators = parseDecorators(); + var modifiers = parseModifiers(); + if (token === 78) { + nextToken(); + if (token === 73 || token === 53) { + return parseExportAssignment(fullStart, decorators, modifiers); + } + if (token === 35 || token === 14) { + return parseExportDeclaration(fullStart, decorators, modifiers); + } + } + switch (token) { + case 98: + case 104: + case 70: + return parseVariableStatement(fullStart, decorators, modifiers); + case 83: + return parseFunctionDeclaration(fullStart, decorators, modifiers); + case 69: + return parseClassDeclaration(fullStart, decorators, modifiers); + case 103: + return parseInterfaceDeclaration(fullStart, decorators, modifiers); + case 123: + return parseTypeAliasDeclaration(fullStart, decorators, modifiers); + case 77: + return parseEnumDeclaration(fullStart, decorators, modifiers); + case 117: + return parseModuleDeclaration(fullStart, decorators, modifiers); + case 85: + return parseImportDeclarationOrImportEqualsDeclaration(fullStart, decorators, modifiers); + default: + if (decorators) { + var node = createMissingNode(218, true, ts.Diagnostics.Declaration_expected); + node.pos = fullStart; + node.decorators = decorators; + setModifiers(node, modifiers); + return finishNode(node); + } + ts.Debug.fail("Mismatch between isDeclarationStart and parseDeclaration"); + } + } + function isSourceElement(inErrorRecovery) { + return isDeclarationStart() || isStartOfStatement(inErrorRecovery); + } + function parseSourceElement() { + return parseSourceElementOrModuleElement(); + } + function parseModuleElement() { + return parseSourceElementOrModuleElement(); + } + function parseSourceElementOrModuleElement() { + return isDeclarationStart() + ? parseDeclaration() + : parseStatement(); + } + function processReferenceComments(sourceFile) { + var triviaScanner = ts.createScanner(sourceFile.languageVersion, false, sourceText); + var referencedFiles = []; + var amdDependencies = []; + var amdModuleName; + while (true) { + var kind = triviaScanner.scan(); + if (kind === 5 || kind === 4 || kind === 3) { + continue; + } + if (kind !== 2) { + break; + } + var range = { pos: triviaScanner.getTokenPos(), end: triviaScanner.getTextPos(), kind: triviaScanner.getToken() }; + var comment = sourceText.substring(range.pos, range.end); + var referencePathMatchResult = ts.getFileReferenceFromReferencePath(comment, range); + if (referencePathMatchResult) { + var fileReference = referencePathMatchResult.fileReference; + sourceFile.hasNoDefaultLib = referencePathMatchResult.isNoDefaultLib; + var diagnosticMessage = referencePathMatchResult.diagnosticMessage; + if (fileReference) { + referencedFiles.push(fileReference); + } + if (diagnosticMessage) { + sourceFile.parseDiagnostics.push(ts.createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, diagnosticMessage)); + } + } + else { + var amdModuleNameRegEx = /^\/\/\/\s*= changeStart, "Adjusting an element that was entirely before the change range"); + ts.Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); + ts.Debug.assert(element.pos <= element.end); + element.pos = Math.min(element.pos, changeRangeNewEnd); + if (element.end >= changeRangeOldEnd) { + element.end += delta; + } + else { + element.end = Math.min(element.end, changeRangeNewEnd); + } + ts.Debug.assert(element.pos <= element.end); + if (element.parent) { + ts.Debug.assert(element.pos >= element.parent.pos); + ts.Debug.assert(element.end <= element.parent.end); + } + } + function checkNodePositions(node, aggressiveChecks) { + if (aggressiveChecks) { + var pos = node.pos; + forEachChild(node, function (child) { + ts.Debug.assert(child.pos >= pos); + pos = child.end; + }); + ts.Debug.assert(pos <= node.end); + } + } + function updateTokenPositionsAndMarkElements(sourceFile, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta, oldText, newText, aggressiveChecks) { + visitNode(sourceFile); + return; + function visitNode(child) { + ts.Debug.assert(child.pos <= child.end); + if (child.pos > changeRangeOldEnd) { + moveElementEntirelyPastChangeRange(child, false, delta, oldText, newText, aggressiveChecks); + return; + } + var fullEnd = child.end; + if (fullEnd >= changeStart) { + child.intersectsChange = true; + child._children = undefined; + adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); + forEachChild(child, visitNode, visitArray); + checkNodePositions(child, aggressiveChecks); + return; + } + ts.Debug.assert(fullEnd < changeStart); + } + function visitArray(array) { + ts.Debug.assert(array.pos <= array.end); + if (array.pos > changeRangeOldEnd) { + moveElementEntirelyPastChangeRange(array, true, delta, oldText, newText, aggressiveChecks); + return; + } + var fullEnd = array.end; + if (fullEnd >= changeStart) { + array.intersectsChange = true; + array._children = undefined; + adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); + for (var _i = 0; _i < array.length; _i++) { + var node = array[_i]; + visitNode(node); + } + return; + } + ts.Debug.assert(fullEnd < changeStart); + } + } + function extendToAffectedRange(sourceFile, changeRange) { + var maxLookahead = 1; + var start = changeRange.span.start; + for (var i = 0; start > 0 && i <= maxLookahead; i++) { + var nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start); + ts.Debug.assert(nearestNode.pos <= start); + var position = nearestNode.pos; + start = Math.max(0, position - 1); + } + var finalSpan = ts.createTextSpanFromBounds(start, ts.textSpanEnd(changeRange.span)); + var finalLength = changeRange.newLength + (changeRange.span.start - start); + return ts.createTextChangeRange(finalSpan, finalLength); + } + function findNearestNodeStartingBeforeOrAtPosition(sourceFile, position) { + var bestResult = sourceFile; + var lastNodeEntirelyBeforePosition; + forEachChild(sourceFile, visit); + if (lastNodeEntirelyBeforePosition) { + var lastChildOfLastEntireNodeBeforePosition = getLastChild(lastNodeEntirelyBeforePosition); + if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) { + bestResult = lastChildOfLastEntireNodeBeforePosition; + } + } + return bestResult; + function getLastChild(node) { + while (true) { + var lastChild = getLastChildWorker(node); + if (lastChild) { + node = lastChild; + } + else { + return node; + } + } + } + function getLastChildWorker(node) { + var last = undefined; + forEachChild(node, function (child) { + if (ts.nodeIsPresent(child)) { + last = child; + } + }); + return last; + } + function visit(child) { + if (ts.nodeIsMissing(child)) { + return; + } + if (child.pos <= position) { + if (child.pos >= bestResult.pos) { + bestResult = child; + } + if (position < child.end) { + forEachChild(child, visit); + return true; + } + else { + ts.Debug.assert(child.end <= position); + lastNodeEntirelyBeforePosition = child; + } + } + else { + ts.Debug.assert(child.pos > position); + return true; + } + } + } + function checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks) { + var oldText = sourceFile.text; + if (textChangeRange) { + ts.Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length); + if (aggressiveChecks || ts.Debug.shouldAssert(3)) { + var oldTextPrefix = oldText.substr(0, textChangeRange.span.start); + var newTextPrefix = newText.substr(0, textChangeRange.span.start); + ts.Debug.assert(oldTextPrefix === newTextPrefix); + var oldTextSuffix = oldText.substring(ts.textSpanEnd(textChangeRange.span), oldText.length); + var newTextSuffix = newText.substring(ts.textSpanEnd(ts.textChangeRangeNewSpan(textChangeRange)), newText.length); + ts.Debug.assert(oldTextSuffix === newTextSuffix); + } + } + } + function createSyntaxCursor(sourceFile) { + var currentArray = sourceFile.statements; + var currentArrayIndex = 0; + ts.Debug.assert(currentArrayIndex < currentArray.length); + var current = currentArray[currentArrayIndex]; + var lastQueriedPosition = -1; + return { + currentNode: function (position) { + if (position !== lastQueriedPosition) { + if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) { + currentArrayIndex++; + current = currentArray[currentArrayIndex]; + } + if (!current || current.pos !== position) { + findHighestListElementThatStartsAtPosition(position); + } + } + lastQueriedPosition = position; + ts.Debug.assert(!current || current.pos === position); + return current; + } + }; + function findHighestListElementThatStartsAtPosition(position) { + currentArray = undefined; + currentArrayIndex = -1; + current = undefined; + forEachChild(sourceFile, visitNode, visitArray); + return; + function visitNode(node) { + if (position >= node.pos && position < node.end) { + forEachChild(node, visitNode, visitArray); + return true; + } + return false; + } + function visitArray(array) { + if (position >= array.pos && position < array.end) { + for (var i = 0, n = array.length; i < n; i++) { + var child = array[i]; + if (child) { + if (child.pos === position) { + currentArray = array; + currentArrayIndex = i; + current = child; + return true; + } + else { + if (child.pos < position && position < child.end) { + forEachChild(child, visitNode, visitArray); + return true; + } + } + } + } + } + return false; + } + } + } + var InvalidPosition; + (function (InvalidPosition) { + InvalidPosition[InvalidPosition["Value"] = -1] = "Value"; + })(InvalidPosition || (InvalidPosition = {})); + })(IncrementalParser || (IncrementalParser = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/program.js b/dist/typescript/compiler/program.js new file mode 100644 index 000000000..564ba3673 --- /dev/null +++ b/dist/typescript/compiler/program.js @@ -0,0 +1,488 @@ +/// +/// +var ts; +(function (ts) { + ts.programTime = 0; + ts.emitTime = 0; + ts.ioReadTime = 0; + ts.ioWriteTime = 0; + ts.version = "1.5.0"; + function findConfigFile(searchPath) { + var fileName = "tsconfig.json"; + while (true) { + if (ts.sys.fileExists(fileName)) { + return fileName; + } + var parentPath = ts.getDirectoryPath(searchPath); + if (parentPath === searchPath) { + break; + } + searchPath = parentPath; + fileName = "../" + fileName; + } + return undefined; + } + ts.findConfigFile = findConfigFile; + function createCompilerHost(options, setParentNodes) { + var currentDirectory; + var existingDirectories = {}; + function getCanonicalFileName(fileName) { + return ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(); + } + var unsupportedFileEncodingErrorCode = -2147024809; + function getSourceFile(fileName, languageVersion, onError) { + var text; + try { + var start = new Date().getTime(); + text = ts.sys.readFile(fileName, options.charset); + ts.ioReadTime += new Date().getTime() - start; + } + catch (e) { + if (onError) { + onError(e.number === unsupportedFileEncodingErrorCode + ? ts.createCompilerDiagnostic(ts.Diagnostics.Unsupported_file_encoding).messageText + : e.message); + } + text = ""; + } + return text !== undefined ? ts.createSourceFile(fileName, text, languageVersion, setParentNodes) : undefined; + } + function directoryExists(directoryPath) { + if (ts.hasProperty(existingDirectories, directoryPath)) { + return true; + } + if (ts.sys.directoryExists(directoryPath)) { + existingDirectories[directoryPath] = true; + return true; + } + return false; + } + function ensureDirectoriesExist(directoryPath) { + if (directoryPath.length > ts.getRootLength(directoryPath) && !directoryExists(directoryPath)) { + var parentDirectory = ts.getDirectoryPath(directoryPath); + ensureDirectoriesExist(parentDirectory); + ts.sys.createDirectory(directoryPath); + } + } + function writeFile(fileName, data, writeByteOrderMark, onError) { + try { + var start = new Date().getTime(); + ensureDirectoriesExist(ts.getDirectoryPath(ts.normalizePath(fileName))); + ts.sys.writeFile(fileName, data, writeByteOrderMark); + ts.ioWriteTime += new Date().getTime() - start; + } + catch (e) { + if (onError) { + onError(e.message); + } + } + } + return { + getSourceFile: getSourceFile, + getDefaultLibFileName: function (options) { return ts.combinePaths(ts.getDirectoryPath(ts.normalizePath(ts.sys.getExecutingFilePath())), ts.getDefaultLibFileName(options)); }, + writeFile: writeFile, + getCurrentDirectory: function () { return currentDirectory || (currentDirectory = ts.sys.getCurrentDirectory()); }, + useCaseSensitiveFileNames: function () { return ts.sys.useCaseSensitiveFileNames; }, + getCanonicalFileName: getCanonicalFileName, + getNewLine: function () { return ts.sys.newLine; } + }; + } + ts.createCompilerHost = createCompilerHost; + function getPreEmitDiagnostics(program) { + var diagnostics = program.getSyntacticDiagnostics().concat(program.getGlobalDiagnostics()).concat(program.getSemanticDiagnostics()); + if (program.getCompilerOptions().declaration) { + diagnostics.concat(program.getDeclarationDiagnostics()); + } + return ts.sortAndDeduplicateDiagnostics(diagnostics); + } + ts.getPreEmitDiagnostics = getPreEmitDiagnostics; + function flattenDiagnosticMessageText(messageText, newLine) { + if (typeof messageText === "string") { + return messageText; + } + else { + var diagnosticChain = messageText; + var result = ""; + var indent = 0; + while (diagnosticChain) { + if (indent) { + result += newLine; + for (var i = 0; i < indent; i++) { + result += " "; + } + } + result += diagnosticChain.messageText; + indent++; + diagnosticChain = diagnosticChain.next; + } + return result; + } + } + ts.flattenDiagnosticMessageText = flattenDiagnosticMessageText; + function createProgram(rootNames, options, host) { + var program; + var files = []; + var filesByName = {}; + var diagnostics = ts.createDiagnosticCollection(); + var seenNoDefaultLib = options.noLib; + var commonSourceDirectory; + var diagnosticsProducingTypeChecker; + var noDiagnosticsTypeChecker; + var start = new Date().getTime(); + host = host || createCompilerHost(options); + ts.forEach(rootNames, function (name) { return processRootFile(name, false); }); + if (!seenNoDefaultLib) { + processRootFile(host.getDefaultLibFileName(options), true); + } + verifyCompilerOptions(); + ts.programTime += new Date().getTime() - start; + program = { + getSourceFile: getSourceFile, + getSourceFiles: function () { return files; }, + getCompilerOptions: function () { return options; }, + getSyntacticDiagnostics: getSyntacticDiagnostics, + getGlobalDiagnostics: getGlobalDiagnostics, + getSemanticDiagnostics: getSemanticDiagnostics, + getDeclarationDiagnostics: getDeclarationDiagnostics, + getTypeChecker: getTypeChecker, + getDiagnosticsProducingTypeChecker: getDiagnosticsProducingTypeChecker, + getCommonSourceDirectory: function () { return commonSourceDirectory; }, + emit: emit, + getCurrentDirectory: function () { return host.getCurrentDirectory(); }, + getNodeCount: function () { return getDiagnosticsProducingTypeChecker().getNodeCount(); }, + getIdentifierCount: function () { return getDiagnosticsProducingTypeChecker().getIdentifierCount(); }, + getSymbolCount: function () { return getDiagnosticsProducingTypeChecker().getSymbolCount(); }, + getTypeCount: function () { return getDiagnosticsProducingTypeChecker().getTypeCount(); }, + }; + return program; + function getEmitHost(writeFileCallback) { + return { + getCanonicalFileName: function (fileName) { return host.getCanonicalFileName(fileName); }, + getCommonSourceDirectory: program.getCommonSourceDirectory, + getCompilerOptions: program.getCompilerOptions, + getCurrentDirectory: function () { return host.getCurrentDirectory(); }, + getNewLine: function () { return host.getNewLine(); }, + getSourceFile: program.getSourceFile, + getSourceFiles: program.getSourceFiles, + writeFile: writeFileCallback || (function (fileName, data, writeByteOrderMark, onError) { return host.writeFile(fileName, data, writeByteOrderMark, onError); }), + }; + } + function getDiagnosticsProducingTypeChecker() { + return diagnosticsProducingTypeChecker || (diagnosticsProducingTypeChecker = ts.createTypeChecker(program, true)); + } + function getTypeChecker() { + return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = ts.createTypeChecker(program, false)); + } + function emit(sourceFile, writeFileCallback) { + if (options.noEmitOnError && getPreEmitDiagnostics(this).length > 0) { + return { diagnostics: [], sourceMaps: undefined, emitSkipped: true }; + } + var emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile); + var start = new Date().getTime(); + var emitResult = ts.emitFiles(emitResolver, getEmitHost(writeFileCallback), sourceFile); + ts.emitTime += new Date().getTime() - start; + return emitResult; + } + function getSourceFile(fileName) { + fileName = host.getCanonicalFileName(fileName); + return ts.hasProperty(filesByName, fileName) ? filesByName[fileName] : undefined; + } + function getDiagnosticsHelper(sourceFile, getDiagnostics) { + if (sourceFile) { + return getDiagnostics(sourceFile); + } + var allDiagnostics = []; + ts.forEach(program.getSourceFiles(), function (sourceFile) { + ts.addRange(allDiagnostics, getDiagnostics(sourceFile)); + }); + return ts.sortAndDeduplicateDiagnostics(allDiagnostics); + } + function getSyntacticDiagnostics(sourceFile) { + return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile); + } + function getSemanticDiagnostics(sourceFile) { + return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile); + } + function getDeclarationDiagnostics(sourceFile) { + return getDiagnosticsHelper(sourceFile, getDeclarationDiagnosticsForFile); + } + function getSyntacticDiagnosticsForFile(sourceFile) { + return sourceFile.parseDiagnostics; + } + function getSemanticDiagnosticsForFile(sourceFile) { + var typeChecker = getDiagnosticsProducingTypeChecker(); + ts.Debug.assert(!!sourceFile.bindDiagnostics); + var bindDiagnostics = sourceFile.bindDiagnostics; + var checkDiagnostics = typeChecker.getDiagnostics(sourceFile); + var programDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName); + return bindDiagnostics.concat(checkDiagnostics).concat(programDiagnostics); + } + function getDeclarationDiagnosticsForFile(sourceFile) { + if (!ts.isDeclarationFile(sourceFile)) { + var resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile); + var writeFile = function () { }; + return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile); + } + } + function getGlobalDiagnostics() { + var typeChecker = getDiagnosticsProducingTypeChecker(); + var allDiagnostics = []; + ts.addRange(allDiagnostics, typeChecker.getGlobalDiagnostics()); + ts.addRange(allDiagnostics, diagnostics.getGlobalDiagnostics()); + return ts.sortAndDeduplicateDiagnostics(allDiagnostics); + } + function hasExtension(fileName) { + return ts.getBaseFileName(fileName).indexOf(".") >= 0; + } + function processRootFile(fileName, isDefaultLib) { + processSourceFile(ts.normalizePath(fileName), isDefaultLib); + } + function processSourceFile(fileName, isDefaultLib, refFile, refPos, refEnd) { + var start; + var length; + if (refEnd !== undefined && refPos !== undefined) { + start = refPos; + length = refEnd - refPos; + } + var diagnostic; + if (hasExtension(fileName)) { + if (!options.allowNonTsExtensions && !ts.fileExtensionIs(host.getCanonicalFileName(fileName), ".ts")) { + diagnostic = ts.Diagnostics.File_0_must_have_extension_ts_or_d_ts; + } + else if (!findSourceFile(fileName, isDefaultLib, refFile, refPos, refEnd)) { + diagnostic = ts.Diagnostics.File_0_not_found; + } + else if (refFile && host.getCanonicalFileName(fileName) === host.getCanonicalFileName(refFile.fileName)) { + diagnostic = ts.Diagnostics.A_file_cannot_have_a_reference_to_itself; + } + } + else { + if (options.allowNonTsExtensions && !findSourceFile(fileName, isDefaultLib, refFile, refPos, refEnd)) { + diagnostic = ts.Diagnostics.File_0_not_found; + } + else if (!findSourceFile(fileName + ".ts", isDefaultLib, refFile, refPos, refEnd) && !findSourceFile(fileName + ".d.ts", isDefaultLib, refFile, refPos, refEnd)) { + diagnostic = ts.Diagnostics.File_0_not_found; + fileName += ".ts"; + } + } + if (diagnostic) { + if (refFile) { + diagnostics.add(ts.createFileDiagnostic(refFile, start, length, diagnostic, fileName)); + } + else { + diagnostics.add(ts.createCompilerDiagnostic(diagnostic, fileName)); + } + } + } + function findSourceFile(fileName, isDefaultLib, refFile, refStart, refLength) { + var canonicalName = host.getCanonicalFileName(fileName); + if (ts.hasProperty(filesByName, canonicalName)) { + return getSourceFileFromCache(fileName, canonicalName, false); + } + else { + var normalizedAbsolutePath = ts.getNormalizedAbsolutePath(fileName, host.getCurrentDirectory()); + var canonicalAbsolutePath = host.getCanonicalFileName(normalizedAbsolutePath); + if (ts.hasProperty(filesByName, canonicalAbsolutePath)) { + return getSourceFileFromCache(normalizedAbsolutePath, canonicalAbsolutePath, true); + } + var file = filesByName[canonicalName] = host.getSourceFile(fileName, options.target, function (hostErrorMessage) { + if (refFile) { + diagnostics.add(ts.createFileDiagnostic(refFile, refStart, refLength, ts.Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage)); + } + else { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage)); + } + }); + if (file) { + seenNoDefaultLib = seenNoDefaultLib || file.hasNoDefaultLib; + filesByName[canonicalAbsolutePath] = file; + if (!options.noResolve) { + var basePath = ts.getDirectoryPath(fileName); + processReferencedFiles(file, basePath); + processImportedModules(file, basePath); + } + if (isDefaultLib) { + files.unshift(file); + } + else { + files.push(file); + } + } + return file; + } + function getSourceFileFromCache(fileName, canonicalName, useAbsolutePath) { + var file = filesByName[canonicalName]; + if (file && host.useCaseSensitiveFileNames()) { + var sourceFileName = useAbsolutePath ? ts.getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory()) : file.fileName; + if (canonicalName !== sourceFileName) { + diagnostics.add(ts.createFileDiagnostic(refFile, refStart, refLength, ts.Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, fileName, sourceFileName)); + } + } + return file; + } + } + function processReferencedFiles(file, basePath) { + ts.forEach(file.referencedFiles, function (ref) { + var referencedFileName = ts.isRootedDiskPath(ref.fileName) ? ref.fileName : ts.combinePaths(basePath, ref.fileName); + processSourceFile(ts.normalizePath(referencedFileName), false, file, ref.pos, ref.end); + }); + } + function processImportedModules(file, basePath) { + ts.forEach(file.statements, function (node) { + if (node.kind === 209 || node.kind === 208 || node.kind === 215) { + var moduleNameExpr = ts.getExternalModuleName(node); + if (moduleNameExpr && moduleNameExpr.kind === 8) { + var moduleNameText = moduleNameExpr.text; + if (moduleNameText) { + var searchPath = basePath; + while (true) { + var searchName = ts.normalizePath(ts.combinePaths(searchPath, moduleNameText)); + if (findModuleSourceFile(searchName + ".ts", moduleNameExpr) || findModuleSourceFile(searchName + ".d.ts", moduleNameExpr)) { + break; + } + var parentPath = ts.getDirectoryPath(searchPath); + if (parentPath === searchPath) { + break; + } + searchPath = parentPath; + } + } + } + } + else if (node.kind === 205 && node.name.kind === 8 && (node.flags & 2 || ts.isDeclarationFile(file))) { + ts.forEachChild(node.body, function (node) { + if (ts.isExternalModuleImportEqualsDeclaration(node) && + ts.getExternalModuleImportEqualsDeclarationExpression(node).kind === 8) { + var nameLiteral = ts.getExternalModuleImportEqualsDeclarationExpression(node); + var moduleName = nameLiteral.text; + if (moduleName) { + var searchName = ts.normalizePath(ts.combinePaths(basePath, moduleName)); + var tsFile = findModuleSourceFile(searchName + ".ts", nameLiteral); + if (!tsFile) { + findModuleSourceFile(searchName + ".d.ts", nameLiteral); + } + } + } + }); + } + }); + function findModuleSourceFile(fileName, nameLiteral) { + return findSourceFile(fileName, false, file, nameLiteral.pos, nameLiteral.end - nameLiteral.pos); + } + } + function computeCommonSourceDirectory(sourceFiles) { + var commonPathComponents; + var currentDirectory = host.getCurrentDirectory(); + ts.forEach(files, function (sourceFile) { + if (ts.isDeclarationFile(sourceFile)) { + return; + } + var sourcePathComponents = ts.getNormalizedPathComponents(sourceFile.fileName, currentDirectory); + sourcePathComponents.pop(); + if (!commonPathComponents) { + commonPathComponents = sourcePathComponents; + return; + } + for (var i = 0, n = Math.min(commonPathComponents.length, sourcePathComponents.length); i < n; i++) { + if (commonPathComponents[i] !== sourcePathComponents[i]) { + if (i === 0) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files)); + return; + } + commonPathComponents.length = i; + break; + } + } + if (sourcePathComponents.length < commonPathComponents.length) { + commonPathComponents.length = sourcePathComponents.length; + } + }); + return ts.getNormalizedPathFromPathComponents(commonPathComponents); + } + function checkSourceFilesBelongToPath(sourceFiles, rootDirectory) { + var allFilesBelongToPath = true; + if (sourceFiles) { + var currentDirectory = host.getCurrentDirectory(); + var absoluteRootDirectoryPath = host.getCanonicalFileName(ts.getNormalizedAbsolutePath(rootDirectory, currentDirectory)); + for (var _i = 0; _i < sourceFiles.length; _i++) { + var sourceFile = sourceFiles[_i]; + if (!ts.isDeclarationFile(sourceFile)) { + var absoluteSourceFilePath = host.getCanonicalFileName(ts.getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory)); + if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, options.rootDir)); + allFilesBelongToPath = false; + } + } + } + } + return allFilesBelongToPath; + } + function verifyCompilerOptions() { + if (options.separateCompilation) { + if (options.sourceMap) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Option_sourceMap_cannot_be_specified_with_option_separateCompilation)); + } + if (options.declaration) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Option_declaration_cannot_be_specified_with_option_separateCompilation)); + } + if (options.noEmitOnError) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Option_noEmitOnError_cannot_be_specified_with_option_separateCompilation)); + } + if (options.out) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Option_out_cannot_be_specified_with_option_separateCompilation)); + } + } + if (!options.sourceMap && (options.mapRoot || options.sourceRoot)) { + if (options.mapRoot) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option)); + } + if (options.sourceRoot) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option)); + } + return; + } + var languageVersion = options.target || 0; + var firstExternalModuleSourceFile = ts.forEach(files, function (f) { return ts.isExternalModule(f) ? f : undefined; }); + if (options.separateCompilation) { + if (!options.module && languageVersion < 2) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Option_separateCompilation_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES6_or_higher)); + } + var firstNonExternalModuleSourceFile = ts.forEach(files, function (f) { return !ts.isExternalModule(f) && !ts.isDeclarationFile(f) ? f : undefined; }); + if (firstNonExternalModuleSourceFile) { + var span = ts.getErrorSpanForNode(firstNonExternalModuleSourceFile, firstNonExternalModuleSourceFile); + diagnostics.add(ts.createFileDiagnostic(firstNonExternalModuleSourceFile, span.start, span.length, ts.Diagnostics.Cannot_compile_non_external_modules_when_the_separateCompilation_flag_is_provided)); + } + } + else if (firstExternalModuleSourceFile && languageVersion < 2 && !options.module) { + var span = ts.getErrorSpanForNode(firstExternalModuleSourceFile, firstExternalModuleSourceFile.externalModuleIndicator); + diagnostics.add(ts.createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, ts.Diagnostics.Cannot_compile_external_modules_unless_the_module_flag_is_provided)); + } + if (options.module && languageVersion >= 2) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Cannot_compile_external_modules_into_amd_commonjs_or_umd_when_targeting_ES6_or_higher)); + } + if (options.outDir || + options.sourceRoot || + (options.mapRoot && + (!options.out || firstExternalModuleSourceFile !== undefined))) { + if (options.rootDir && checkSourceFilesBelongToPath(files, options.rootDir)) { + commonSourceDirectory = ts.getNormalizedAbsolutePath(options.rootDir, host.getCurrentDirectory()); + } + else { + commonSourceDirectory = computeCommonSourceDirectory(files); + } + if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== ts.directorySeparator) { + commonSourceDirectory += ts.directorySeparator; + } + } + if (options.noEmit) { + if (options.out || options.outDir) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Option_noEmit_cannot_be_specified_with_option_out_or_outDir)); + } + if (options.declaration) { + diagnostics.add(ts.createCompilerDiagnostic(ts.Diagnostics.Option_noEmit_cannot_be_specified_with_option_declaration)); + } + } + } + } + ts.createProgram = createProgram; +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/scanner.js b/dist/typescript/compiler/scanner.js new file mode 100644 index 000000000..a466f1c1e --- /dev/null +++ b/dist/typescript/compiler/scanner.js @@ -0,0 +1,1245 @@ +/// +/// +var ts; +(function (ts) { + var textToToken = { + "any": 112, + "as": 111, + "boolean": 113, + "break": 66, + "case": 67, + "catch": 68, + "class": 69, + "continue": 71, + "const": 70, + "constructor": 114, + "debugger": 72, + "declare": 115, + "default": 73, + "delete": 74, + "do": 75, + "else": 76, + "enum": 77, + "export": 78, + "extends": 79, + "false": 80, + "finally": 81, + "for": 82, + "from": 124, + "function": 83, + "get": 116, + "if": 84, + "implements": 102, + "import": 85, + "in": 86, + "instanceof": 87, + "interface": 103, + "let": 104, + "module": 117, + "new": 88, + "null": 89, + "number": 119, + "package": 105, + "private": 106, + "protected": 107, + "public": 108, + "require": 118, + "return": 90, + "set": 120, + "static": 109, + "string": 121, + "super": 91, + "switch": 92, + "symbol": 122, + "this": 93, + "throw": 94, + "true": 95, + "try": 96, + "type": 123, + "typeof": 97, + "var": 98, + "void": 99, + "while": 100, + "with": 101, + "yield": 110, + "of": 125, + "{": 14, + "}": 15, + "(": 16, + ")": 17, + "[": 18, + "]": 19, + ".": 20, + "...": 21, + ";": 22, + ",": 23, + "<": 24, + ">": 25, + "<=": 26, + ">=": 27, + "==": 28, + "!=": 29, + "===": 30, + "!==": 31, + "=>": 32, + "+": 33, + "-": 34, + "*": 35, + "/": 36, + "%": 37, + "++": 38, + "--": 39, + "<<": 40, + ">>": 41, + ">>>": 42, + "&": 43, + "|": 44, + "^": 45, + "!": 46, + "~": 47, + "&&": 48, + "||": 49, + "?": 50, + ":": 51, + "=": 53, + "+=": 54, + "-=": 55, + "*=": 56, + "/=": 57, + "%=": 58, + "<<=": 59, + ">>=": 60, + ">>>=": 61, + "&=": 62, + "|=": 63, + "^=": 64, + "@": 52, + }; + var unicodeES3IdentifierStart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1569, 1594, 1600, 1610, 1649, 1747, 1749, 1749, 1765, 1766, 1786, 1788, 1808, 1808, 1810, 1836, 1920, 1957, 2309, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2784, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3294, 3294, 3296, 3297, 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3424, 3425, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, 3840, 3840, 3904, 3911, 3913, 3946, 3976, 3979, 4096, 4129, 4131, 4135, 4137, 4138, 4176, 4181, 4256, 4293, 4304, 4342, 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6067, 6176, 6263, 6272, 6312, 7680, 7835, 7840, 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8319, 8319, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12346, 12353, 12436, 12445, 12446, 12449, 12538, 12540, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65138, 65140, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500,]; + var unicodeES3IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 768, 846, 864, 866, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, 1155, 1158, 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1441, 1443, 1465, 1467, 1469, 1471, 1471, 1473, 1474, 1476, 1476, 1488, 1514, 1520, 1522, 1569, 1594, 1600, 1621, 1632, 1641, 1648, 1747, 1749, 1756, 1759, 1768, 1770, 1773, 1776, 1788, 1808, 1836, 1840, 1866, 1920, 1968, 2305, 2307, 2309, 2361, 2364, 2381, 2384, 2388, 2392, 2403, 2406, 2415, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2492, 2494, 2500, 2503, 2504, 2507, 2509, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2562, 2562, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2649, 2652, 2654, 2654, 2662, 2676, 2689, 2691, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2784, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, 2873, 2876, 2883, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2913, 2918, 2927, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3031, 3031, 3047, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3134, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3168, 3169, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3262, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3297, 3302, 3311, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3390, 3395, 3398, 3400, 3402, 3405, 3415, 3415, 3424, 3425, 3430, 3439, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3805, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3946, 3953, 3972, 3974, 3979, 3984, 3991, 3993, 4028, 4038, 4038, 4096, 4129, 4131, 4135, 4137, 4138, 4140, 4146, 4150, 4153, 4160, 4169, 4176, 4185, 4256, 4293, 4304, 4342, 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 4969, 4977, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6099, 6112, 6121, 6160, 6169, 6176, 6263, 6272, 6313, 7680, 7835, 7840, 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8255, 8256, 8319, 8319, 8400, 8412, 8417, 8417, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12346, 12353, 12436, 12441, 12442, 12445, 12446, 12449, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65056, 65059, 65075, 65076, 65101, 65103, 65136, 65138, 65140, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65381, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500,]; + var unicodeES5IdentifierStart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2208, 2208, 2210, 2220, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, 7413, 7414, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500,]; + var unicodeES5IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1520, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2048, 2093, 2112, 2139, 2208, 2208, 2210, 2220, 2276, 2302, 2304, 2403, 2406, 2415, 2417, 2423, 2425, 2431, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3161, 3168, 3171, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3299, 3302, 3311, 3313, 3314, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3396, 3398, 3400, 3402, 3406, 3415, 3415, 3424, 3427, 3430, 3439, 3450, 3455, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5908, 5920, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6160, 6169, 6176, 6263, 6272, 6314, 6320, 6389, 6400, 6428, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6617, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6912, 6987, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7376, 7378, 7380, 7414, 7424, 7654, 7676, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8204, 8205, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 11823, 11823, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12442, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42647, 42655, 42737, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43047, 43072, 43123, 43136, 43204, 43216, 43225, 43232, 43255, 43259, 43259, 43264, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43643, 43648, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65062, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500,]; + function lookupInUnicodeMap(code, map) { + if (code < map[0]) { + return false; + } + var lo = 0; + var hi = map.length; + var mid; + while (lo + 1 < hi) { + mid = lo + (hi - lo) / 2; + mid -= mid % 2; + if (map[mid] <= code && code <= map[mid + 1]) { + return true; + } + if (code < map[mid]) { + hi = mid; + } + else { + lo = mid + 2; + } + } + return false; + } + function isUnicodeIdentifierStart(code, languageVersion) { + return languageVersion >= 1 ? + lookupInUnicodeMap(code, unicodeES5IdentifierStart) : + lookupInUnicodeMap(code, unicodeES3IdentifierStart); + } + ts.isUnicodeIdentifierStart = isUnicodeIdentifierStart; + function isUnicodeIdentifierPart(code, languageVersion) { + return languageVersion >= 1 ? + lookupInUnicodeMap(code, unicodeES5IdentifierPart) : + lookupInUnicodeMap(code, unicodeES3IdentifierPart); + } + function makeReverseMap(source) { + var result = []; + for (var name_1 in source) { + if (source.hasOwnProperty(name_1)) { + result[source[name_1]] = name_1; + } + } + return result; + } + var tokenStrings = makeReverseMap(textToToken); + function tokenToString(t) { + return tokenStrings[t]; + } + ts.tokenToString = tokenToString; + function stringToToken(s) { + return textToToken[s]; + } + ts.stringToToken = stringToToken; + function computeLineStarts(text) { + var result = new Array(); + var pos = 0; + var lineStart = 0; + while (pos < text.length) { + var ch = text.charCodeAt(pos++); + switch (ch) { + case 13: + if (text.charCodeAt(pos) === 10) { + pos++; + } + case 10: + result.push(lineStart); + lineStart = pos; + break; + default: + if (ch > 127 && isLineBreak(ch)) { + result.push(lineStart); + lineStart = pos; + } + break; + } + } + result.push(lineStart); + return result; + } + ts.computeLineStarts = computeLineStarts; + function getPositionOfLineAndCharacter(sourceFile, line, character) { + return computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character); + } + ts.getPositionOfLineAndCharacter = getPositionOfLineAndCharacter; + function computePositionOfLineAndCharacter(lineStarts, line, character) { + ts.Debug.assert(line >= 0 && line < lineStarts.length); + return lineStarts[line] + character; + } + ts.computePositionOfLineAndCharacter = computePositionOfLineAndCharacter; + function getLineStarts(sourceFile) { + return sourceFile.lineMap || (sourceFile.lineMap = computeLineStarts(sourceFile.text)); + } + ts.getLineStarts = getLineStarts; + function computeLineAndCharacterOfPosition(lineStarts, position) { + var lineNumber = ts.binarySearch(lineStarts, position); + if (lineNumber < 0) { + lineNumber = ~lineNumber - 1; + } + return { + line: lineNumber, + character: position - lineStarts[lineNumber] + }; + } + ts.computeLineAndCharacterOfPosition = computeLineAndCharacterOfPosition; + function getLineAndCharacterOfPosition(sourceFile, position) { + return computeLineAndCharacterOfPosition(getLineStarts(sourceFile), position); + } + ts.getLineAndCharacterOfPosition = getLineAndCharacterOfPosition; + var hasOwnProperty = Object.prototype.hasOwnProperty; + function isWhiteSpace(ch) { + return ch === 32 || + ch === 9 || + ch === 11 || + ch === 12 || + ch === 160 || + ch === 133 || + ch === 5760 || + ch >= 8192 && ch <= 8203 || + ch === 8239 || + ch === 8287 || + ch === 12288 || + ch === 65279; + } + ts.isWhiteSpace = isWhiteSpace; + function isLineBreak(ch) { + // ES5 7.3: + // The ECMAScript line terminator characters are listed in Table 3. + // Table 3: Line Terminator Characters + // Code Unit Value Name Formal Name + // \u000A Line Feed + // \u000D Carriage Return + // \u2028 Line separator + // \u2029 Paragraph separator + // Only the characters in Table 3 are treated as line terminators. Other new line or line + // breaking characters are treated as white space but not as line terminators. + return ch === 10 || + ch === 13 || + ch === 8232 || + ch === 8233; + } + ts.isLineBreak = isLineBreak; + function isDigit(ch) { + return ch >= 48 && ch <= 57; + } + function isOctalDigit(ch) { + return ch >= 48 && ch <= 55; + } + ts.isOctalDigit = isOctalDigit; + function skipTrivia(text, pos, stopAfterLineBreak) { + while (true) { + var ch = text.charCodeAt(pos); + switch (ch) { + case 13: + if (text.charCodeAt(pos + 1) === 10) { + pos++; + } + case 10: + pos++; + if (stopAfterLineBreak) { + return pos; + } + continue; + case 9: + case 11: + case 12: + case 32: + pos++; + continue; + case 47: + if (text.charCodeAt(pos + 1) === 47) { + pos += 2; + while (pos < text.length) { + if (isLineBreak(text.charCodeAt(pos))) { + break; + } + pos++; + } + continue; + } + if (text.charCodeAt(pos + 1) === 42) { + pos += 2; + while (pos < text.length) { + if (text.charCodeAt(pos) === 42 && text.charCodeAt(pos + 1) === 47) { + pos += 2; + break; + } + pos++; + } + continue; + } + break; + case 60: + case 61: + case 62: + if (isConflictMarkerTrivia(text, pos)) { + pos = scanConflictMarkerTrivia(text, pos); + continue; + } + break; + default: + if (ch > 127 && (isWhiteSpace(ch) || isLineBreak(ch))) { + pos++; + continue; + } + break; + } + return pos; + } + } + ts.skipTrivia = skipTrivia; + var mergeConflictMarkerLength = "<<<<<<<".length; + function isConflictMarkerTrivia(text, pos) { + ts.Debug.assert(pos >= 0); + if (pos === 0 || isLineBreak(text.charCodeAt(pos - 1))) { + var ch = text.charCodeAt(pos); + if ((pos + mergeConflictMarkerLength) < text.length) { + for (var i = 0, n = mergeConflictMarkerLength; i < n; i++) { + if (text.charCodeAt(pos + i) !== ch) { + return false; + } + } + return ch === 61 || + text.charCodeAt(pos + mergeConflictMarkerLength) === 32; + } + } + return false; + } + function scanConflictMarkerTrivia(text, pos, error) { + if (error) { + error(ts.Diagnostics.Merge_conflict_marker_encountered, mergeConflictMarkerLength); + } + var ch = text.charCodeAt(pos); + var len = text.length; + if (ch === 60 || ch === 62) { + while (pos < len && !isLineBreak(text.charCodeAt(pos))) { + pos++; + } + } + else { + ts.Debug.assert(ch === 61); + while (pos < len) { + var ch_1 = text.charCodeAt(pos); + if (ch_1 === 62 && isConflictMarkerTrivia(text, pos)) { + break; + } + pos++; + } + } + return pos; + } + function getCommentRanges(text, pos, trailing) { + var result; + var collecting = trailing || pos === 0; + while (true) { + var ch = text.charCodeAt(pos); + switch (ch) { + case 13: + if (text.charCodeAt(pos + 1) === 10) { + pos++; + } + case 10: + pos++; + if (trailing) { + return result; + } + collecting = true; + if (result && result.length) { + result[result.length - 1].hasTrailingNewLine = true; + } + continue; + case 9: + case 11: + case 12: + case 32: + pos++; + continue; + case 47: + var nextChar = text.charCodeAt(pos + 1); + var hasTrailingNewLine = false; + if (nextChar === 47 || nextChar === 42) { + var kind = nextChar === 47 ? 2 : 3; + var startPos = pos; + pos += 2; + if (nextChar === 47) { + while (pos < text.length) { + if (isLineBreak(text.charCodeAt(pos))) { + hasTrailingNewLine = true; + break; + } + pos++; + } + } + else { + while (pos < text.length) { + if (text.charCodeAt(pos) === 42 && text.charCodeAt(pos + 1) === 47) { + pos += 2; + break; + } + pos++; + } + } + if (collecting) { + if (!result) { + result = []; + } + result.push({ pos: startPos, end: pos, hasTrailingNewLine: hasTrailingNewLine, kind: kind }); + } + continue; + } + break; + default: + if (ch > 127 && (isWhiteSpace(ch) || isLineBreak(ch))) { + if (result && result.length && isLineBreak(ch)) { + result[result.length - 1].hasTrailingNewLine = true; + } + pos++; + continue; + } + break; + } + return result; + } + } + function getLeadingCommentRanges(text, pos) { + return getCommentRanges(text, pos, false); + } + ts.getLeadingCommentRanges = getLeadingCommentRanges; + function getTrailingCommentRanges(text, pos) { + return getCommentRanges(text, pos, true); + } + ts.getTrailingCommentRanges = getTrailingCommentRanges; + function isIdentifierStart(ch, languageVersion) { + return ch >= 65 && ch <= 90 || ch >= 97 && ch <= 122 || + ch === 36 || ch === 95 || + ch > 127 && isUnicodeIdentifierStart(ch, languageVersion); + } + ts.isIdentifierStart = isIdentifierStart; + function isIdentifierPart(ch, languageVersion) { + return ch >= 65 && ch <= 90 || ch >= 97 && ch <= 122 || + ch >= 48 && ch <= 57 || ch === 36 || ch === 95 || + ch > 127 && isUnicodeIdentifierPart(ch, languageVersion); + } + ts.isIdentifierPart = isIdentifierPart; + function createScanner(languageVersion, skipTrivia, text, onError, start, length) { + var pos; + var end; + var startPos; + var tokenPos; + var token; + var tokenValue; + var precedingLineBreak; + var hasExtendedUnicodeEscape; + var tokenIsUnterminated; + setText(text, start, length); + return { + getStartPos: function () { return startPos; }, + getTextPos: function () { return pos; }, + getToken: function () { return token; }, + getTokenPos: function () { return tokenPos; }, + getTokenText: function () { return text.substring(tokenPos, pos); }, + getTokenValue: function () { return tokenValue; }, + hasExtendedUnicodeEscape: function () { return hasExtendedUnicodeEscape; }, + hasPrecedingLineBreak: function () { return precedingLineBreak; }, + isIdentifier: function () { return token === 65 || token > 101; }, + isReservedWord: function () { return token >= 66 && token <= 101; }, + isUnterminated: function () { return tokenIsUnterminated; }, + reScanGreaterToken: reScanGreaterToken, + reScanSlashToken: reScanSlashToken, + reScanTemplateToken: reScanTemplateToken, + scan: scan, + setText: setText, + setScriptTarget: setScriptTarget, + setOnError: setOnError, + setTextPos: setTextPos, + tryScan: tryScan, + lookAhead: lookAhead, + }; + function error(message, length) { + if (onError) { + onError(message, length || 0); + } + } + function isIdentifierStart(ch) { + return ch >= 65 && ch <= 90 || ch >= 97 && ch <= 122 || + ch === 36 || ch === 95 || + ch > 127 && isUnicodeIdentifierStart(ch, languageVersion); + } + function isIdentifierPart(ch) { + return ch >= 65 && ch <= 90 || ch >= 97 && ch <= 122 || + ch >= 48 && ch <= 57 || ch === 36 || ch === 95 || + ch > 127 && isUnicodeIdentifierPart(ch, languageVersion); + } + function scanNumber() { + var start = pos; + while (isDigit(text.charCodeAt(pos))) + pos++; + if (text.charCodeAt(pos) === 46) { + pos++; + while (isDigit(text.charCodeAt(pos))) + pos++; + } + var end = pos; + if (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101) { + pos++; + if (text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) + pos++; + if (isDigit(text.charCodeAt(pos))) { + pos++; + while (isDigit(text.charCodeAt(pos))) + pos++; + end = pos; + } + else { + error(ts.Diagnostics.Digit_expected); + } + } + return +(text.substring(start, end)); + } + function scanOctalDigits() { + var start = pos; + while (isOctalDigit(text.charCodeAt(pos))) { + pos++; + } + return +(text.substring(start, pos)); + } + function scanExactNumberOfHexDigits(count) { + return scanHexDigits(count, false); + } + function scanMinimumNumberOfHexDigits(count) { + return scanHexDigits(count, true); + } + function scanHexDigits(minCount, scanAsManyAsPossible) { + var digits = 0; + var value = 0; + while (digits < minCount || scanAsManyAsPossible) { + var ch = text.charCodeAt(pos); + if (ch >= 48 && ch <= 57) { + value = value * 16 + ch - 48; + } + else if (ch >= 65 && ch <= 70) { + value = value * 16 + ch - 65 + 10; + } + else if (ch >= 97 && ch <= 102) { + value = value * 16 + ch - 97 + 10; + } + else { + break; + } + pos++; + digits++; + } + if (digits < minCount) { + value = -1; + } + return value; + } + function scanString() { + var quote = text.charCodeAt(pos++); + var result = ""; + var start = pos; + while (true) { + if (pos >= end) { + result += text.substring(start, pos); + tokenIsUnterminated = true; + error(ts.Diagnostics.Unterminated_string_literal); + break; + } + var ch = text.charCodeAt(pos); + if (ch === quote) { + result += text.substring(start, pos); + pos++; + break; + } + if (ch === 92) { + result += text.substring(start, pos); + result += scanEscapeSequence(); + start = pos; + continue; + } + if (isLineBreak(ch)) { + result += text.substring(start, pos); + tokenIsUnterminated = true; + error(ts.Diagnostics.Unterminated_string_literal); + break; + } + pos++; + } + return result; + } + function scanTemplateAndSetTokenValue() { + var startedWithBacktick = text.charCodeAt(pos) === 96; + pos++; + var start = pos; + var contents = ""; + var resultingToken; + while (true) { + if (pos >= end) { + contents += text.substring(start, pos); + tokenIsUnterminated = true; + error(ts.Diagnostics.Unterminated_template_literal); + resultingToken = startedWithBacktick ? 10 : 13; + break; + } + var currChar = text.charCodeAt(pos); + if (currChar === 96) { + contents += text.substring(start, pos); + pos++; + resultingToken = startedWithBacktick ? 10 : 13; + break; + } + if (currChar === 36 && pos + 1 < end && text.charCodeAt(pos + 1) === 123) { + contents += text.substring(start, pos); + pos += 2; + resultingToken = startedWithBacktick ? 11 : 12; + break; + } + if (currChar === 92) { + contents += text.substring(start, pos); + contents += scanEscapeSequence(); + start = pos; + continue; + } + if (currChar === 13) { + contents += text.substring(start, pos); + pos++; + if (pos < end && text.charCodeAt(pos) === 10) { + pos++; + } + contents += "\n"; + start = pos; + continue; + } + pos++; + } + ts.Debug.assert(resultingToken !== undefined); + tokenValue = contents; + return resultingToken; + } + function scanEscapeSequence() { + pos++; + if (pos >= end) { + error(ts.Diagnostics.Unexpected_end_of_text); + return ""; + } + var ch = text.charCodeAt(pos++); + switch (ch) { + case 48: + return "\0"; + case 98: + return "\b"; + case 116: + return "\t"; + case 110: + return "\n"; + case 118: + return "\v"; + case 102: + return "\f"; + case 114: + return "\r"; + case 39: + return "\'"; + case 34: + return "\""; + case 117: + if (pos < end && text.charCodeAt(pos) === 123) { + hasExtendedUnicodeEscape = true; + pos++; + return scanExtendedUnicodeEscape(); + } + return scanHexadecimalEscape(4); + case 120: + return scanHexadecimalEscape(2); + case 13: + if (pos < end && text.charCodeAt(pos) === 10) { + pos++; + } + case 10: + case 8232: + case 8233: + return ""; + default: + return String.fromCharCode(ch); + } + } + function scanHexadecimalEscape(numDigits) { + var escapedValue = scanExactNumberOfHexDigits(numDigits); + if (escapedValue >= 0) { + return String.fromCharCode(escapedValue); + } + else { + error(ts.Diagnostics.Hexadecimal_digit_expected); + return ""; + } + } + function scanExtendedUnicodeEscape() { + var escapedValue = scanMinimumNumberOfHexDigits(1); + var isInvalidExtendedEscape = false; + if (escapedValue < 0) { + error(ts.Diagnostics.Hexadecimal_digit_expected); + isInvalidExtendedEscape = true; + } + else if (escapedValue > 0x10FFFF) { + error(ts.Diagnostics.An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive); + isInvalidExtendedEscape = true; + } + if (pos >= end) { + error(ts.Diagnostics.Unexpected_end_of_text); + isInvalidExtendedEscape = true; + } + else if (text.charCodeAt(pos) == 125) { + pos++; + } + else { + error(ts.Diagnostics.Unterminated_Unicode_escape_sequence); + isInvalidExtendedEscape = true; + } + if (isInvalidExtendedEscape) { + return ""; + } + return utf16EncodeAsString(escapedValue); + } + function utf16EncodeAsString(codePoint) { + ts.Debug.assert(0x0 <= codePoint && codePoint <= 0x10FFFF); + if (codePoint <= 65535) { + return String.fromCharCode(codePoint); + } + var codeUnit1 = Math.floor((codePoint - 65536) / 1024) + 0xD800; + var codeUnit2 = ((codePoint - 65536) % 1024) + 0xDC00; + return String.fromCharCode(codeUnit1, codeUnit2); + } + function peekUnicodeEscape() { + if (pos + 5 < end && text.charCodeAt(pos + 1) === 117) { + var start_1 = pos; + pos += 2; + var value = scanExactNumberOfHexDigits(4); + pos = start_1; + return value; + } + return -1; + } + function scanIdentifierParts() { + var result = ""; + var start = pos; + while (pos < end) { + var ch = text.charCodeAt(pos); + if (isIdentifierPart(ch)) { + pos++; + } + else if (ch === 92) { + ch = peekUnicodeEscape(); + if (!(ch >= 0 && isIdentifierPart(ch))) { + break; + } + result += text.substring(start, pos); + result += String.fromCharCode(ch); + pos += 6; + start = pos; + } + else { + break; + } + } + result += text.substring(start, pos); + return result; + } + function getIdentifierToken() { + var len = tokenValue.length; + if (len >= 2 && len <= 11) { + var ch = tokenValue.charCodeAt(0); + if (ch >= 97 && ch <= 122 && hasOwnProperty.call(textToToken, tokenValue)) { + return token = textToToken[tokenValue]; + } + } + return token = 65; + } + function scanBinaryOrOctalDigits(base) { + ts.Debug.assert(base !== 2 || base !== 8, "Expected either base 2 or base 8"); + var value = 0; + var numberOfDigits = 0; + while (true) { + var ch = text.charCodeAt(pos); + var valueOfCh = ch - 48; + if (!isDigit(ch) || valueOfCh >= base) { + break; + } + value = value * base + valueOfCh; + pos++; + numberOfDigits++; + } + if (numberOfDigits === 0) { + return -1; + } + return value; + } + function scan() { + startPos = pos; + hasExtendedUnicodeEscape = false; + precedingLineBreak = false; + tokenIsUnterminated = false; + while (true) { + tokenPos = pos; + if (pos >= end) { + return token = 1; + } + var ch = text.charCodeAt(pos); + switch (ch) { + case 10: + case 13: + precedingLineBreak = true; + if (skipTrivia) { + pos++; + continue; + } + else { + if (ch === 13 && pos + 1 < end && text.charCodeAt(pos + 1) === 10) { + pos += 2; + } + else { + pos++; + } + return token = 4; + } + case 9: + case 11: + case 12: + case 32: + if (skipTrivia) { + pos++; + continue; + } + else { + while (pos < end && isWhiteSpace(text.charCodeAt(pos))) { + pos++; + } + return token = 5; + } + case 33: + if (text.charCodeAt(pos + 1) === 61) { + if (text.charCodeAt(pos + 2) === 61) { + return pos += 3, token = 31; + } + return pos += 2, token = 29; + } + return pos++, token = 46; + case 34: + case 39: + tokenValue = scanString(); + return token = 8; + case 96: + return token = scanTemplateAndSetTokenValue(); + case 37: + if (text.charCodeAt(pos + 1) === 61) { + return pos += 2, token = 58; + } + return pos++, token = 37; + case 38: + if (text.charCodeAt(pos + 1) === 38) { + return pos += 2, token = 48; + } + if (text.charCodeAt(pos + 1) === 61) { + return pos += 2, token = 62; + } + return pos++, token = 43; + case 40: + return pos++, token = 16; + case 41: + return pos++, token = 17; + case 42: + if (text.charCodeAt(pos + 1) === 61) { + return pos += 2, token = 56; + } + return pos++, token = 35; + case 43: + if (text.charCodeAt(pos + 1) === 43) { + return pos += 2, token = 38; + } + if (text.charCodeAt(pos + 1) === 61) { + return pos += 2, token = 54; + } + return pos++, token = 33; + case 44: + return pos++, token = 23; + case 45: + if (text.charCodeAt(pos + 1) === 45) { + return pos += 2, token = 39; + } + if (text.charCodeAt(pos + 1) === 61) { + return pos += 2, token = 55; + } + return pos++, token = 34; + case 46: + if (isDigit(text.charCodeAt(pos + 1))) { + tokenValue = "" + scanNumber(); + return token = 7; + } + if (text.charCodeAt(pos + 1) === 46 && text.charCodeAt(pos + 2) === 46) { + return pos += 3, token = 21; + } + return pos++, token = 20; + case 47: + if (text.charCodeAt(pos + 1) === 47) { + pos += 2; + while (pos < end) { + if (isLineBreak(text.charCodeAt(pos))) { + break; + } + pos++; + } + if (skipTrivia) { + continue; + } + else { + return token = 2; + } + } + if (text.charCodeAt(pos + 1) === 42) { + pos += 2; + var commentClosed = false; + while (pos < end) { + var ch_2 = text.charCodeAt(pos); + if (ch_2 === 42 && text.charCodeAt(pos + 1) === 47) { + pos += 2; + commentClosed = true; + break; + } + if (isLineBreak(ch_2)) { + precedingLineBreak = true; + } + pos++; + } + if (!commentClosed) { + error(ts.Diagnostics.Asterisk_Slash_expected); + } + if (skipTrivia) { + continue; + } + else { + tokenIsUnterminated = !commentClosed; + return token = 3; + } + } + if (text.charCodeAt(pos + 1) === 61) { + return pos += 2, token = 57; + } + return pos++, token = 36; + case 48: + if (pos + 2 < end && (text.charCodeAt(pos + 1) === 88 || text.charCodeAt(pos + 1) === 120)) { + pos += 2; + var value = scanMinimumNumberOfHexDigits(1); + if (value < 0) { + error(ts.Diagnostics.Hexadecimal_digit_expected); + value = 0; + } + tokenValue = "" + value; + return token = 7; + } + else if (pos + 2 < end && (text.charCodeAt(pos + 1) === 66 || text.charCodeAt(pos + 1) === 98)) { + pos += 2; + var value = scanBinaryOrOctalDigits(2); + if (value < 0) { + error(ts.Diagnostics.Binary_digit_expected); + value = 0; + } + tokenValue = "" + value; + return token = 7; + } + else if (pos + 2 < end && (text.charCodeAt(pos + 1) === 79 || text.charCodeAt(pos + 1) === 111)) { + pos += 2; + var value = scanBinaryOrOctalDigits(8); + if (value < 0) { + error(ts.Diagnostics.Octal_digit_expected); + value = 0; + } + tokenValue = "" + value; + return token = 7; + } + if (pos + 1 < end && isOctalDigit(text.charCodeAt(pos + 1))) { + tokenValue = "" + scanOctalDigits(); + return token = 7; + } + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + tokenValue = "" + scanNumber(); + return token = 7; + case 58: + return pos++, token = 51; + case 59: + return pos++, token = 22; + case 60: + if (isConflictMarkerTrivia(text, pos)) { + pos = scanConflictMarkerTrivia(text, pos, error); + if (skipTrivia) { + continue; + } + else { + return token = 6; + } + } + if (text.charCodeAt(pos + 1) === 60) { + if (text.charCodeAt(pos + 2) === 61) { + return pos += 3, token = 59; + } + return pos += 2, token = 40; + } + if (text.charCodeAt(pos + 1) === 61) { + return pos += 2, token = 26; + } + return pos++, token = 24; + case 61: + if (isConflictMarkerTrivia(text, pos)) { + pos = scanConflictMarkerTrivia(text, pos, error); + if (skipTrivia) { + continue; + } + else { + return token = 6; + } + } + if (text.charCodeAt(pos + 1) === 61) { + if (text.charCodeAt(pos + 2) === 61) { + return pos += 3, token = 30; + } + return pos += 2, token = 28; + } + if (text.charCodeAt(pos + 1) === 62) { + return pos += 2, token = 32; + } + return pos++, token = 53; + case 62: + if (isConflictMarkerTrivia(text, pos)) { + pos = scanConflictMarkerTrivia(text, pos, error); + if (skipTrivia) { + continue; + } + else { + return token = 6; + } + } + return pos++, token = 25; + case 63: + return pos++, token = 50; + case 91: + return pos++, token = 18; + case 93: + return pos++, token = 19; + case 94: + if (text.charCodeAt(pos + 1) === 61) { + return pos += 2, token = 64; + } + return pos++, token = 45; + case 123: + return pos++, token = 14; + case 124: + if (text.charCodeAt(pos + 1) === 124) { + return pos += 2, token = 49; + } + if (text.charCodeAt(pos + 1) === 61) { + return pos += 2, token = 63; + } + return pos++, token = 44; + case 125: + return pos++, token = 15; + case 126: + return pos++, token = 47; + case 64: + return pos++, token = 52; + case 92: + var cookedChar = peekUnicodeEscape(); + if (cookedChar >= 0 && isIdentifierStart(cookedChar)) { + pos += 6; + tokenValue = String.fromCharCode(cookedChar) + scanIdentifierParts(); + return token = getIdentifierToken(); + } + error(ts.Diagnostics.Invalid_character); + return pos++, token = 0; + default: + if (isIdentifierStart(ch)) { + pos++; + while (pos < end && isIdentifierPart(ch = text.charCodeAt(pos))) + pos++; + tokenValue = text.substring(tokenPos, pos); + if (ch === 92) { + tokenValue += scanIdentifierParts(); + } + return token = getIdentifierToken(); + } + else if (isWhiteSpace(ch)) { + pos++; + continue; + } + else if (isLineBreak(ch)) { + precedingLineBreak = true; + pos++; + continue; + } + error(ts.Diagnostics.Invalid_character); + return pos++, token = 0; + } + } + } + function reScanGreaterToken() { + if (token === 25) { + if (text.charCodeAt(pos) === 62) { + if (text.charCodeAt(pos + 1) === 62) { + if (text.charCodeAt(pos + 2) === 61) { + return pos += 3, token = 61; + } + return pos += 2, token = 42; + } + if (text.charCodeAt(pos + 1) === 61) { + return pos += 2, token = 60; + } + return pos++, token = 41; + } + if (text.charCodeAt(pos) === 61) { + return pos++, token = 27; + } + } + return token; + } + function reScanSlashToken() { + if (token === 36 || token === 57) { + var p = tokenPos + 1; + var inEscape = false; + var inCharacterClass = false; + while (true) { + if (p >= end) { + tokenIsUnterminated = true; + error(ts.Diagnostics.Unterminated_regular_expression_literal); + break; + } + var ch = text.charCodeAt(p); + if (isLineBreak(ch)) { + tokenIsUnterminated = true; + error(ts.Diagnostics.Unterminated_regular_expression_literal); + break; + } + if (inEscape) { + inEscape = false; + } + else if (ch === 47 && !inCharacterClass) { + p++; + break; + } + else if (ch === 91) { + inCharacterClass = true; + } + else if (ch === 92) { + inEscape = true; + } + else if (ch === 93) { + inCharacterClass = false; + } + p++; + } + while (p < end && isIdentifierPart(text.charCodeAt(p))) { + p++; + } + pos = p; + tokenValue = text.substring(tokenPos, pos); + token = 9; + } + return token; + } + function reScanTemplateToken() { + ts.Debug.assert(token === 15, "'reScanTemplateToken' should only be called on a '}'"); + pos = tokenPos; + return token = scanTemplateAndSetTokenValue(); + } + function speculationHelper(callback, isLookahead) { + var savePos = pos; + var saveStartPos = startPos; + var saveTokenPos = tokenPos; + var saveToken = token; + var saveTokenValue = tokenValue; + var savePrecedingLineBreak = precedingLineBreak; + var result = callback(); + if (!result || isLookahead) { + pos = savePos; + startPos = saveStartPos; + tokenPos = saveTokenPos; + token = saveToken; + tokenValue = saveTokenValue; + precedingLineBreak = savePrecedingLineBreak; + } + return result; + } + function lookAhead(callback) { + return speculationHelper(callback, true); + } + function tryScan(callback) { + return speculationHelper(callback, false); + } + function setText(newText, start, length) { + text = newText || ""; + end = length === undefined ? text.length : start + length; + setTextPos(start || 0); + } + function setOnError(errorCallback) { + onError = errorCallback; + } + function setScriptTarget(scriptTarget) { + languageVersion = scriptTarget; + } + function setTextPos(textPos) { + ts.Debug.assert(textPos >= 0); + pos = textPos; + startPos = textPos; + tokenPos = textPos; + token = 0; + precedingLineBreak = false; + tokenValue = undefined; + hasExtendedUnicodeEscape = false; + tokenIsUnterminated = false; + } + } + ts.createScanner = createScanner; +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/sys.js b/dist/typescript/compiler/sys.js new file mode 100644 index 000000000..d4765b752 --- /dev/null +++ b/dist/typescript/compiler/sys.js @@ -0,0 +1,252 @@ +/// +var ts; +(function (ts) { + ts.sys = (function () { + function getWScriptSystem() { + var fso = new ActiveXObject("Scripting.FileSystemObject"); + var fileStream = new ActiveXObject("ADODB.Stream"); + fileStream.Type = 2; + var binaryStream = new ActiveXObject("ADODB.Stream"); + binaryStream.Type = 1; + var args = []; + for (var i = 0; i < WScript.Arguments.length; i++) { + args[i] = WScript.Arguments.Item(i); + } + function readFile(fileName, encoding) { + if (!fso.FileExists(fileName)) { + return undefined; + } + fileStream.Open(); + try { + if (encoding) { + fileStream.Charset = encoding; + fileStream.LoadFromFile(fileName); + } + else { + fileStream.Charset = "x-ansi"; + fileStream.LoadFromFile(fileName); + var bom = fileStream.ReadText(2) || ""; + fileStream.Position = 0; + fileStream.Charset = bom.length >= 2 && (bom.charCodeAt(0) === 0xFF && bom.charCodeAt(1) === 0xFE || bom.charCodeAt(0) === 0xFE && bom.charCodeAt(1) === 0xFF) ? "unicode" : "utf-8"; + } + return fileStream.ReadText(); + } + catch (e) { + throw e; + } + finally { + fileStream.Close(); + } + } + function writeFile(fileName, data, writeByteOrderMark) { + fileStream.Open(); + binaryStream.Open(); + try { + fileStream.Charset = "utf-8"; + fileStream.WriteText(data); + if (writeByteOrderMark) { + fileStream.Position = 0; + } + else { + fileStream.Position = 3; + } + fileStream.CopyTo(binaryStream); + binaryStream.SaveToFile(fileName, 2); + } + finally { + binaryStream.Close(); + fileStream.Close(); + } + } + function getNames(collection) { + var result = []; + for (var e = new Enumerator(collection); !e.atEnd(); e.moveNext()) { + result.push(e.item().Name); + } + return result.sort(); + } + function readDirectory(path, extension) { + var result = []; + visitDirectory(path); + return result; + function visitDirectory(path) { + var folder = fso.GetFolder(path || "."); + var files = getNames(folder.files); + for (var _i = 0; _i < files.length; _i++) { + var name_1 = files[_i]; + if (!extension || ts.fileExtensionIs(name_1, extension)) { + result.push(ts.combinePaths(path, name_1)); + } + } + var subfolders = getNames(folder.subfolders); + for (var _a = 0; _a < subfolders.length; _a++) { + var current = subfolders[_a]; + visitDirectory(ts.combinePaths(path, current)); + } + } + } + return { + args: args, + newLine: "\r\n", + useCaseSensitiveFileNames: false, + write: function (s) { + WScript.StdOut.Write(s); + }, + readFile: readFile, + writeFile: writeFile, + resolvePath: function (path) { + return fso.GetAbsolutePathName(path); + }, + fileExists: function (path) { + return fso.FileExists(path); + }, + directoryExists: function (path) { + return fso.FolderExists(path); + }, + createDirectory: function (directoryName) { + if (!this.directoryExists(directoryName)) { + fso.CreateFolder(directoryName); + } + }, + getExecutingFilePath: function () { + return WScript.ScriptFullName; + }, + getCurrentDirectory: function () { + return new ActiveXObject("WScript.Shell").CurrentDirectory; + }, + readDirectory: readDirectory, + exit: function (exitCode) { + try { + WScript.Quit(exitCode); + } + catch (e) { + } + } + }; + } + function getNodeSystem() { + var _fs = require("fs"); + var _path = require("path"); + var _os = require('os'); + var platform = _os.platform(); + var useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin"; + function readFile(fileName, encoding) { + if (!_fs.existsSync(fileName)) { + return undefined; + } + var buffer = _fs.readFileSync(fileName); + var len = buffer.length; + if (len >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) { + len &= ~1; + for (var i = 0; i < len; i += 2) { + var temp = buffer[i]; + buffer[i] = buffer[i + 1]; + buffer[i + 1] = temp; + } + return buffer.toString("utf16le", 2); + } + if (len >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) { + return buffer.toString("utf16le", 2); + } + if (len >= 3 && buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) { + return buffer.toString("utf8", 3); + } + return buffer.toString("utf8"); + } + function writeFile(fileName, data, writeByteOrderMark) { + if (writeByteOrderMark) { + data = '\uFEFF' + data; + } + _fs.writeFileSync(fileName, data, "utf8"); + } + function readDirectory(path, extension) { + var result = []; + visitDirectory(path); + return result; + function visitDirectory(path) { + var files = _fs.readdirSync(path || ".").sort(); + var directories = []; + for (var _i = 0; _i < files.length; _i++) { + var current = files[_i]; + var name = ts.combinePaths(path, current); + var stat = _fs.lstatSync(name); + if (stat.isFile()) { + if (!extension || ts.fileExtensionIs(name, extension)) { + result.push(name); + } + } + else if (stat.isDirectory()) { + directories.push(name); + } + } + for (var _a = 0; _a < directories.length; _a++) { + var current = directories[_a]; + visitDirectory(current); + } + } + } + return { + args: process.argv.slice(2), + newLine: _os.EOL, + useCaseSensitiveFileNames: useCaseSensitiveFileNames, + write: function (s) { + _fs.writeSync(1, s); + }, + readFile: readFile, + writeFile: writeFile, + watchFile: function (fileName, callback) { + _fs.watchFile(fileName, { persistent: true, interval: 250 }, fileChanged); + return { + close: function () { _fs.unwatchFile(fileName, fileChanged); } + }; + function fileChanged(curr, prev) { + if (+curr.mtime <= +prev.mtime) { + return; + } + callback(fileName); + } + ; + }, + resolvePath: function (path) { + return _path.resolve(path); + }, + fileExists: function (path) { + return _fs.existsSync(path); + }, + directoryExists: function (path) { + return _fs.existsSync(path) && _fs.statSync(path).isDirectory(); + }, + createDirectory: function (directoryName) { + if (!this.directoryExists(directoryName)) { + _fs.mkdirSync(directoryName); + } + }, + getExecutingFilePath: function () { + return __filename; + }, + getCurrentDirectory: function () { + return process.cwd(); + }, + readDirectory: readDirectory, + getMemoryUsage: function () { + if (global.gc) { + global.gc(); + } + return process.memoryUsage().heapUsed; + }, + exit: function (exitCode) { + process.exit(exitCode); + } + }; + } + if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") { + return getWScriptSystem(); + } + else if (typeof module !== "undefined" && module.exports) { + return getNodeSystem(); + } + else { + return undefined; + } + })(); +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/tsc.js b/dist/typescript/compiler/tsc.js new file mode 100644 index 000000000..543206ec0 --- /dev/null +++ b/dist/typescript/compiler/tsc.js @@ -0,0 +1,365 @@ +/// +/// +var ts; +(function (ts) { + function validateLocaleAndSetLanguage(locale, errors) { + var matchResult = /^([a-z]+)([_\-]([a-z]+))?$/.exec(locale.toLowerCase()); + if (!matchResult) { + errors.push(ts.createCompilerDiagnostic(ts.Diagnostics.Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1, 'en', 'ja-jp')); + return false; + } + var language = matchResult[1]; + var territory = matchResult[3]; + if (!trySetLanguageAndTerritory(language, territory, errors) && + !trySetLanguageAndTerritory(language, undefined, errors)) { + errors.push(ts.createCompilerDiagnostic(ts.Diagnostics.Unsupported_locale_0, locale)); + return false; + } + return true; + } + function trySetLanguageAndTerritory(language, territory, errors) { + var compilerFilePath = ts.normalizePath(ts.sys.getExecutingFilePath()); + var containingDirectoryPath = ts.getDirectoryPath(compilerFilePath); + var filePath = ts.combinePaths(containingDirectoryPath, language); + if (territory) { + filePath = filePath + "-" + territory; + } + filePath = ts.sys.resolvePath(ts.combinePaths(filePath, "diagnosticMessages.generated.json")); + if (!ts.sys.fileExists(filePath)) { + return false; + } + try { + var fileContents = ts.sys.readFile(filePath); + } + catch (e) { + errors.push(ts.createCompilerDiagnostic(ts.Diagnostics.Unable_to_open_file_0, filePath)); + return false; + } + try { + ts.localizedDiagnosticMessages = JSON.parse(fileContents); + } + catch (e) { + errors.push(ts.createCompilerDiagnostic(ts.Diagnostics.Corrupted_locale_file_0, filePath)); + return false; + } + return true; + } + function countLines(program) { + var count = 0; + ts.forEach(program.getSourceFiles(), function (file) { + count += ts.getLineStarts(file).length; + }); + return count; + } + function getDiagnosticText(message) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var diagnostic = ts.createCompilerDiagnostic.apply(undefined, arguments); + return diagnostic.messageText; + } + function reportDiagnostic(diagnostic) { + var output = ""; + if (diagnostic.file) { + var loc = ts.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start); + output += diagnostic.file.fileName + "(" + (loc.line + 1) + "," + (loc.character + 1) + "): "; + } + var category = ts.DiagnosticCategory[diagnostic.category].toLowerCase(); + output += category + " TS" + diagnostic.code + ": " + ts.flattenDiagnosticMessageText(diagnostic.messageText, ts.sys.newLine) + ts.sys.newLine; + ts.sys.write(output); + } + function reportDiagnostics(diagnostics) { + for (var i = 0; i < diagnostics.length; i++) { + reportDiagnostic(diagnostics[i]); + } + } + function padLeft(s, length) { + while (s.length < length) { + s = " " + s; + } + return s; + } + function padRight(s, length) { + while (s.length < length) { + s = s + " "; + } + return s; + } + function reportStatisticalValue(name, value) { + ts.sys.write(padRight(name + ":", 12) + padLeft(value.toString(), 10) + ts.sys.newLine); + } + function reportCountStatistic(name, count) { + reportStatisticalValue(name, "" + count); + } + function reportTimeStatistic(name, time) { + reportStatisticalValue(name, (time / 1000).toFixed(2) + "s"); + } + function isJSONSupported() { + return typeof JSON === "object" && typeof JSON.parse === "function"; + } + function executeCommandLine(args) { + var commandLine = ts.parseCommandLine(args); + var configFileName; + var configFileWatcher; + var cachedProgram; + var rootFileNames; + var compilerOptions; + var compilerHost; + var hostGetSourceFile; + var timerHandle; + if (commandLine.options.locale) { + if (!isJSONSupported()) { + reportDiagnostic(ts.createCompilerDiagnostic(ts.Diagnostics.The_current_host_does_not_support_the_0_option, "--locale")); + return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); + } + validateLocaleAndSetLanguage(commandLine.options.locale, commandLine.errors); + } + if (commandLine.errors.length > 0) { + reportDiagnostics(commandLine.errors); + return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); + } + if (commandLine.options.version) { + reportDiagnostic(ts.createCompilerDiagnostic(ts.Diagnostics.Version_0, ts.version)); + return ts.sys.exit(ts.ExitStatus.Success); + } + if (commandLine.options.help) { + printVersion(); + printHelp(); + return ts.sys.exit(ts.ExitStatus.Success); + } + if (commandLine.options.project) { + if (!isJSONSupported()) { + reportDiagnostic(ts.createCompilerDiagnostic(ts.Diagnostics.The_current_host_does_not_support_the_0_option, "--project")); + return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); + } + configFileName = ts.normalizePath(ts.combinePaths(commandLine.options.project, "tsconfig.json")); + if (commandLine.fileNames.length !== 0) { + reportDiagnostic(ts.createCompilerDiagnostic(ts.Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line)); + return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); + } + } + else if (commandLine.fileNames.length === 0 && isJSONSupported()) { + var searchPath = ts.normalizePath(ts.sys.getCurrentDirectory()); + configFileName = ts.findConfigFile(searchPath); + } + if (commandLine.fileNames.length === 0 && !configFileName) { + printVersion(); + printHelp(); + return ts.sys.exit(ts.ExitStatus.Success); + } + if (commandLine.options.watch) { + if (!ts.sys.watchFile) { + reportDiagnostic(ts.createCompilerDiagnostic(ts.Diagnostics.The_current_host_does_not_support_the_0_option, "--watch")); + return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); + } + if (configFileName) { + configFileWatcher = ts.sys.watchFile(configFileName, configFileChanged); + } + } + performCompilation(); + function performCompilation() { + if (!cachedProgram) { + if (configFileName) { + var result = ts.readConfigFile(configFileName); + if (result.error) { + reportDiagnostic(result.error); + return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); + } + var configObject = result.config; + var configParseResult = ts.parseConfigFile(configObject, ts.sys, ts.getDirectoryPath(configFileName)); + if (configParseResult.errors.length > 0) { + reportDiagnostics(configParseResult.errors); + return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); + } + rootFileNames = configParseResult.fileNames; + compilerOptions = ts.extend(commandLine.options, configParseResult.options); + } + else { + rootFileNames = commandLine.fileNames; + compilerOptions = commandLine.options; + } + compilerHost = ts.createCompilerHost(compilerOptions); + hostGetSourceFile = compilerHost.getSourceFile; + compilerHost.getSourceFile = getSourceFile; + } + var compileResult = compile(rootFileNames, compilerOptions, compilerHost); + if (!compilerOptions.watch) { + return ts.sys.exit(compileResult.exitStatus); + } + setCachedProgram(compileResult.program); + reportDiagnostic(ts.createCompilerDiagnostic(ts.Diagnostics.Compilation_complete_Watching_for_file_changes)); + } + function getSourceFile(fileName, languageVersion, onError) { + if (cachedProgram) { + var sourceFile = cachedProgram.getSourceFile(fileName); + if (sourceFile && sourceFile.fileWatcher) { + return sourceFile; + } + } + var sourceFile = hostGetSourceFile(fileName, languageVersion, onError); + if (sourceFile && compilerOptions.watch) { + sourceFile.fileWatcher = ts.sys.watchFile(sourceFile.fileName, function () { return sourceFileChanged(sourceFile); }); + } + return sourceFile; + } + function setCachedProgram(program) { + if (cachedProgram) { + var newSourceFiles = program ? program.getSourceFiles() : undefined; + ts.forEach(cachedProgram.getSourceFiles(), function (sourceFile) { + if (!(newSourceFiles && ts.contains(newSourceFiles, sourceFile))) { + if (sourceFile.fileWatcher) { + sourceFile.fileWatcher.close(); + sourceFile.fileWatcher = undefined; + } + } + }); + } + cachedProgram = program; + } + function sourceFileChanged(sourceFile) { + sourceFile.fileWatcher.close(); + sourceFile.fileWatcher = undefined; + startTimer(); + } + function configFileChanged() { + setCachedProgram(undefined); + startTimer(); + } + function startTimer() { + if (timerHandle) { + clearTimeout(timerHandle); + } + timerHandle = setTimeout(recompile, 250); + } + function recompile() { + timerHandle = undefined; + reportDiagnostic(ts.createCompilerDiagnostic(ts.Diagnostics.File_change_detected_Starting_incremental_compilation)); + performCompilation(); + } + } + ts.executeCommandLine = executeCommandLine; + function compile(fileNames, compilerOptions, compilerHost) { + ts.ioReadTime = 0; + ts.ioWriteTime = 0; + ts.programTime = 0; + ts.bindTime = 0; + ts.checkTime = 0; + ts.emitTime = 0; + var program = ts.createProgram(fileNames, compilerOptions, compilerHost); + var exitStatus = compileProgram(); + if (compilerOptions.listFiles) { + ts.forEach(program.getSourceFiles(), function (file) { + ts.sys.write(file.fileName + ts.sys.newLine); + }); + } + if (compilerOptions.diagnostics) { + var memoryUsed = ts.sys.getMemoryUsage ? ts.sys.getMemoryUsage() : -1; + reportCountStatistic("Files", program.getSourceFiles().length); + reportCountStatistic("Lines", countLines(program)); + reportCountStatistic("Nodes", program.getNodeCount()); + reportCountStatistic("Identifiers", program.getIdentifierCount()); + reportCountStatistic("Symbols", program.getSymbolCount()); + reportCountStatistic("Types", program.getTypeCount()); + if (memoryUsed >= 0) { + reportStatisticalValue("Memory used", Math.round(memoryUsed / 1000) + "K"); + } + reportTimeStatistic("I/O read", ts.ioReadTime); + reportTimeStatistic("I/O write", ts.ioWriteTime); + reportTimeStatistic("Parse time", ts.programTime); + reportTimeStatistic("Bind time", ts.bindTime); + reportTimeStatistic("Check time", ts.checkTime); + reportTimeStatistic("Emit time", ts.emitTime); + reportTimeStatistic("Total time", ts.programTime + ts.bindTime + ts.checkTime + ts.emitTime); + } + return { program: program, exitStatus: exitStatus }; + function compileProgram() { + var diagnostics = program.getSyntacticDiagnostics(); + reportDiagnostics(diagnostics); + if (diagnostics.length === 0) { + var diagnostics = program.getGlobalDiagnostics(); + reportDiagnostics(diagnostics); + if (diagnostics.length === 0) { + var diagnostics = program.getSemanticDiagnostics(); + reportDiagnostics(diagnostics); + } + } + if (compilerOptions.noEmit) { + return diagnostics.length + ? ts.ExitStatus.DiagnosticsPresent_OutputsSkipped + : ts.ExitStatus.Success; + } + var emitOutput = program.emit(); + reportDiagnostics(emitOutput.diagnostics); + if (emitOutput.emitSkipped) { + return ts.ExitStatus.DiagnosticsPresent_OutputsSkipped; + } + if (diagnostics.length > 0 || emitOutput.diagnostics.length > 0) { + return ts.ExitStatus.DiagnosticsPresent_OutputsGenerated; + } + return ts.ExitStatus.Success; + } + } + function printVersion() { + ts.sys.write(getDiagnosticText(ts.Diagnostics.Version_0, ts.version) + ts.sys.newLine); + } + function printHelp() { + var output = ""; + var syntaxLength = getDiagnosticText(ts.Diagnostics.Syntax_Colon_0, "").length; + var examplesLength = getDiagnosticText(ts.Diagnostics.Examples_Colon_0, "").length; + var marginLength = Math.max(syntaxLength, examplesLength); + var syntax = makePadding(marginLength - syntaxLength); + syntax += "tsc [" + getDiagnosticText(ts.Diagnostics.options) + "] [" + getDiagnosticText(ts.Diagnostics.file) + " ...]"; + output += getDiagnosticText(ts.Diagnostics.Syntax_Colon_0, syntax); + output += ts.sys.newLine + ts.sys.newLine; + var padding = makePadding(marginLength); + output += getDiagnosticText(ts.Diagnostics.Examples_Colon_0, makePadding(marginLength - examplesLength) + "tsc hello.ts") + ts.sys.newLine; + output += padding + "tsc --out file.js file.ts" + ts.sys.newLine; + output += padding + "tsc @args.txt" + ts.sys.newLine; + output += ts.sys.newLine; + output += getDiagnosticText(ts.Diagnostics.Options_Colon) + ts.sys.newLine; + var optsList = ts.filter(ts.optionDeclarations.slice(), function (v) { return !v.experimental; }); + optsList.sort(function (a, b) { return ts.compareValues(a.name.toLowerCase(), b.name.toLowerCase()); }); + var marginLength = 0; + var usageColumn = []; + var descriptionColumn = []; + for (var i = 0; i < optsList.length; i++) { + var option = optsList[i]; + if (!option.description) { + continue; + } + var usageText = " "; + if (option.shortName) { + usageText += "-" + option.shortName; + usageText += getParamType(option); + usageText += ", "; + } + usageText += "--" + option.name; + usageText += getParamType(option); + usageColumn.push(usageText); + descriptionColumn.push(getDiagnosticText(option.description)); + marginLength = Math.max(usageText.length, marginLength); + } + var usageText = " @<" + getDiagnosticText(ts.Diagnostics.file) + ">"; + usageColumn.push(usageText); + descriptionColumn.push(getDiagnosticText(ts.Diagnostics.Insert_command_line_options_and_files_from_a_file)); + marginLength = Math.max(usageText.length, marginLength); + for (var i = 0; i < usageColumn.length; i++) { + var usage = usageColumn[i]; + var description = descriptionColumn[i]; + output += usage + makePadding(marginLength - usage.length + 2) + description + ts.sys.newLine; + } + ts.sys.write(output); + return; + function getParamType(option) { + if (option.paramType !== undefined) { + return " " + getDiagnosticText(option.paramType); + } + return ""; + } + function makePadding(paddingLength) { + return Array(paddingLength + 1).join(" "); + } + } +})(ts || (ts = {})); +ts.executeCommandLine(ts.sys.args); diff --git a/dist/typescript/compiler/types.js b/dist/typescript/compiler/types.js new file mode 100644 index 000000000..dbcc11b11 --- /dev/null +++ b/dist/typescript/compiler/types.js @@ -0,0 +1,596 @@ +var ts; +(function (ts) { + (function (SyntaxKind) { + SyntaxKind[SyntaxKind["Unknown"] = 0] = "Unknown"; + SyntaxKind[SyntaxKind["EndOfFileToken"] = 1] = "EndOfFileToken"; + SyntaxKind[SyntaxKind["SingleLineCommentTrivia"] = 2] = "SingleLineCommentTrivia"; + SyntaxKind[SyntaxKind["MultiLineCommentTrivia"] = 3] = "MultiLineCommentTrivia"; + SyntaxKind[SyntaxKind["NewLineTrivia"] = 4] = "NewLineTrivia"; + SyntaxKind[SyntaxKind["WhitespaceTrivia"] = 5] = "WhitespaceTrivia"; + SyntaxKind[SyntaxKind["ConflictMarkerTrivia"] = 6] = "ConflictMarkerTrivia"; + SyntaxKind[SyntaxKind["NumericLiteral"] = 7] = "NumericLiteral"; + SyntaxKind[SyntaxKind["StringLiteral"] = 8] = "StringLiteral"; + SyntaxKind[SyntaxKind["RegularExpressionLiteral"] = 9] = "RegularExpressionLiteral"; + SyntaxKind[SyntaxKind["NoSubstitutionTemplateLiteral"] = 10] = "NoSubstitutionTemplateLiteral"; + SyntaxKind[SyntaxKind["TemplateHead"] = 11] = "TemplateHead"; + SyntaxKind[SyntaxKind["TemplateMiddle"] = 12] = "TemplateMiddle"; + SyntaxKind[SyntaxKind["TemplateTail"] = 13] = "TemplateTail"; + SyntaxKind[SyntaxKind["OpenBraceToken"] = 14] = "OpenBraceToken"; + SyntaxKind[SyntaxKind["CloseBraceToken"] = 15] = "CloseBraceToken"; + SyntaxKind[SyntaxKind["OpenParenToken"] = 16] = "OpenParenToken"; + SyntaxKind[SyntaxKind["CloseParenToken"] = 17] = "CloseParenToken"; + SyntaxKind[SyntaxKind["OpenBracketToken"] = 18] = "OpenBracketToken"; + SyntaxKind[SyntaxKind["CloseBracketToken"] = 19] = "CloseBracketToken"; + SyntaxKind[SyntaxKind["DotToken"] = 20] = "DotToken"; + SyntaxKind[SyntaxKind["DotDotDotToken"] = 21] = "DotDotDotToken"; + SyntaxKind[SyntaxKind["SemicolonToken"] = 22] = "SemicolonToken"; + SyntaxKind[SyntaxKind["CommaToken"] = 23] = "CommaToken"; + SyntaxKind[SyntaxKind["LessThanToken"] = 24] = "LessThanToken"; + SyntaxKind[SyntaxKind["GreaterThanToken"] = 25] = "GreaterThanToken"; + SyntaxKind[SyntaxKind["LessThanEqualsToken"] = 26] = "LessThanEqualsToken"; + SyntaxKind[SyntaxKind["GreaterThanEqualsToken"] = 27] = "GreaterThanEqualsToken"; + SyntaxKind[SyntaxKind["EqualsEqualsToken"] = 28] = "EqualsEqualsToken"; + SyntaxKind[SyntaxKind["ExclamationEqualsToken"] = 29] = "ExclamationEqualsToken"; + SyntaxKind[SyntaxKind["EqualsEqualsEqualsToken"] = 30] = "EqualsEqualsEqualsToken"; + SyntaxKind[SyntaxKind["ExclamationEqualsEqualsToken"] = 31] = "ExclamationEqualsEqualsToken"; + SyntaxKind[SyntaxKind["EqualsGreaterThanToken"] = 32] = "EqualsGreaterThanToken"; + SyntaxKind[SyntaxKind["PlusToken"] = 33] = "PlusToken"; + SyntaxKind[SyntaxKind["MinusToken"] = 34] = "MinusToken"; + SyntaxKind[SyntaxKind["AsteriskToken"] = 35] = "AsteriskToken"; + SyntaxKind[SyntaxKind["SlashToken"] = 36] = "SlashToken"; + SyntaxKind[SyntaxKind["PercentToken"] = 37] = "PercentToken"; + SyntaxKind[SyntaxKind["PlusPlusToken"] = 38] = "PlusPlusToken"; + SyntaxKind[SyntaxKind["MinusMinusToken"] = 39] = "MinusMinusToken"; + SyntaxKind[SyntaxKind["LessThanLessThanToken"] = 40] = "LessThanLessThanToken"; + SyntaxKind[SyntaxKind["GreaterThanGreaterThanToken"] = 41] = "GreaterThanGreaterThanToken"; + SyntaxKind[SyntaxKind["GreaterThanGreaterThanGreaterThanToken"] = 42] = "GreaterThanGreaterThanGreaterThanToken"; + SyntaxKind[SyntaxKind["AmpersandToken"] = 43] = "AmpersandToken"; + SyntaxKind[SyntaxKind["BarToken"] = 44] = "BarToken"; + SyntaxKind[SyntaxKind["CaretToken"] = 45] = "CaretToken"; + SyntaxKind[SyntaxKind["ExclamationToken"] = 46] = "ExclamationToken"; + SyntaxKind[SyntaxKind["TildeToken"] = 47] = "TildeToken"; + SyntaxKind[SyntaxKind["AmpersandAmpersandToken"] = 48] = "AmpersandAmpersandToken"; + SyntaxKind[SyntaxKind["BarBarToken"] = 49] = "BarBarToken"; + SyntaxKind[SyntaxKind["QuestionToken"] = 50] = "QuestionToken"; + SyntaxKind[SyntaxKind["ColonToken"] = 51] = "ColonToken"; + SyntaxKind[SyntaxKind["AtToken"] = 52] = "AtToken"; + SyntaxKind[SyntaxKind["EqualsToken"] = 53] = "EqualsToken"; + SyntaxKind[SyntaxKind["PlusEqualsToken"] = 54] = "PlusEqualsToken"; + SyntaxKind[SyntaxKind["MinusEqualsToken"] = 55] = "MinusEqualsToken"; + SyntaxKind[SyntaxKind["AsteriskEqualsToken"] = 56] = "AsteriskEqualsToken"; + SyntaxKind[SyntaxKind["SlashEqualsToken"] = 57] = "SlashEqualsToken"; + SyntaxKind[SyntaxKind["PercentEqualsToken"] = 58] = "PercentEqualsToken"; + SyntaxKind[SyntaxKind["LessThanLessThanEqualsToken"] = 59] = "LessThanLessThanEqualsToken"; + SyntaxKind[SyntaxKind["GreaterThanGreaterThanEqualsToken"] = 60] = "GreaterThanGreaterThanEqualsToken"; + SyntaxKind[SyntaxKind["GreaterThanGreaterThanGreaterThanEqualsToken"] = 61] = "GreaterThanGreaterThanGreaterThanEqualsToken"; + SyntaxKind[SyntaxKind["AmpersandEqualsToken"] = 62] = "AmpersandEqualsToken"; + SyntaxKind[SyntaxKind["BarEqualsToken"] = 63] = "BarEqualsToken"; + SyntaxKind[SyntaxKind["CaretEqualsToken"] = 64] = "CaretEqualsToken"; + SyntaxKind[SyntaxKind["Identifier"] = 65] = "Identifier"; + SyntaxKind[SyntaxKind["BreakKeyword"] = 66] = "BreakKeyword"; + SyntaxKind[SyntaxKind["CaseKeyword"] = 67] = "CaseKeyword"; + SyntaxKind[SyntaxKind["CatchKeyword"] = 68] = "CatchKeyword"; + SyntaxKind[SyntaxKind["ClassKeyword"] = 69] = "ClassKeyword"; + SyntaxKind[SyntaxKind["ConstKeyword"] = 70] = "ConstKeyword"; + SyntaxKind[SyntaxKind["ContinueKeyword"] = 71] = "ContinueKeyword"; + SyntaxKind[SyntaxKind["DebuggerKeyword"] = 72] = "DebuggerKeyword"; + SyntaxKind[SyntaxKind["DefaultKeyword"] = 73] = "DefaultKeyword"; + SyntaxKind[SyntaxKind["DeleteKeyword"] = 74] = "DeleteKeyword"; + SyntaxKind[SyntaxKind["DoKeyword"] = 75] = "DoKeyword"; + SyntaxKind[SyntaxKind["ElseKeyword"] = 76] = "ElseKeyword"; + SyntaxKind[SyntaxKind["EnumKeyword"] = 77] = "EnumKeyword"; + SyntaxKind[SyntaxKind["ExportKeyword"] = 78] = "ExportKeyword"; + SyntaxKind[SyntaxKind["ExtendsKeyword"] = 79] = "ExtendsKeyword"; + SyntaxKind[SyntaxKind["FalseKeyword"] = 80] = "FalseKeyword"; + SyntaxKind[SyntaxKind["FinallyKeyword"] = 81] = "FinallyKeyword"; + SyntaxKind[SyntaxKind["ForKeyword"] = 82] = "ForKeyword"; + SyntaxKind[SyntaxKind["FunctionKeyword"] = 83] = "FunctionKeyword"; + SyntaxKind[SyntaxKind["IfKeyword"] = 84] = "IfKeyword"; + SyntaxKind[SyntaxKind["ImportKeyword"] = 85] = "ImportKeyword"; + SyntaxKind[SyntaxKind["InKeyword"] = 86] = "InKeyword"; + SyntaxKind[SyntaxKind["InstanceOfKeyword"] = 87] = "InstanceOfKeyword"; + SyntaxKind[SyntaxKind["NewKeyword"] = 88] = "NewKeyword"; + SyntaxKind[SyntaxKind["NullKeyword"] = 89] = "NullKeyword"; + SyntaxKind[SyntaxKind["ReturnKeyword"] = 90] = "ReturnKeyword"; + SyntaxKind[SyntaxKind["SuperKeyword"] = 91] = "SuperKeyword"; + SyntaxKind[SyntaxKind["SwitchKeyword"] = 92] = "SwitchKeyword"; + SyntaxKind[SyntaxKind["ThisKeyword"] = 93] = "ThisKeyword"; + SyntaxKind[SyntaxKind["ThrowKeyword"] = 94] = "ThrowKeyword"; + SyntaxKind[SyntaxKind["TrueKeyword"] = 95] = "TrueKeyword"; + SyntaxKind[SyntaxKind["TryKeyword"] = 96] = "TryKeyword"; + SyntaxKind[SyntaxKind["TypeOfKeyword"] = 97] = "TypeOfKeyword"; + SyntaxKind[SyntaxKind["VarKeyword"] = 98] = "VarKeyword"; + SyntaxKind[SyntaxKind["VoidKeyword"] = 99] = "VoidKeyword"; + SyntaxKind[SyntaxKind["WhileKeyword"] = 100] = "WhileKeyword"; + SyntaxKind[SyntaxKind["WithKeyword"] = 101] = "WithKeyword"; + SyntaxKind[SyntaxKind["ImplementsKeyword"] = 102] = "ImplementsKeyword"; + SyntaxKind[SyntaxKind["InterfaceKeyword"] = 103] = "InterfaceKeyword"; + SyntaxKind[SyntaxKind["LetKeyword"] = 104] = "LetKeyword"; + SyntaxKind[SyntaxKind["PackageKeyword"] = 105] = "PackageKeyword"; + SyntaxKind[SyntaxKind["PrivateKeyword"] = 106] = "PrivateKeyword"; + SyntaxKind[SyntaxKind["ProtectedKeyword"] = 107] = "ProtectedKeyword"; + SyntaxKind[SyntaxKind["PublicKeyword"] = 108] = "PublicKeyword"; + SyntaxKind[SyntaxKind["StaticKeyword"] = 109] = "StaticKeyword"; + SyntaxKind[SyntaxKind["YieldKeyword"] = 110] = "YieldKeyword"; + SyntaxKind[SyntaxKind["AsKeyword"] = 111] = "AsKeyword"; + SyntaxKind[SyntaxKind["AnyKeyword"] = 112] = "AnyKeyword"; + SyntaxKind[SyntaxKind["BooleanKeyword"] = 113] = "BooleanKeyword"; + SyntaxKind[SyntaxKind["ConstructorKeyword"] = 114] = "ConstructorKeyword"; + SyntaxKind[SyntaxKind["DeclareKeyword"] = 115] = "DeclareKeyword"; + SyntaxKind[SyntaxKind["GetKeyword"] = 116] = "GetKeyword"; + SyntaxKind[SyntaxKind["ModuleKeyword"] = 117] = "ModuleKeyword"; + SyntaxKind[SyntaxKind["RequireKeyword"] = 118] = "RequireKeyword"; + SyntaxKind[SyntaxKind["NumberKeyword"] = 119] = "NumberKeyword"; + SyntaxKind[SyntaxKind["SetKeyword"] = 120] = "SetKeyword"; + SyntaxKind[SyntaxKind["StringKeyword"] = 121] = "StringKeyword"; + SyntaxKind[SyntaxKind["SymbolKeyword"] = 122] = "SymbolKeyword"; + SyntaxKind[SyntaxKind["TypeKeyword"] = 123] = "TypeKeyword"; + SyntaxKind[SyntaxKind["FromKeyword"] = 124] = "FromKeyword"; + SyntaxKind[SyntaxKind["OfKeyword"] = 125] = "OfKeyword"; + SyntaxKind[SyntaxKind["QualifiedName"] = 126] = "QualifiedName"; + SyntaxKind[SyntaxKind["ComputedPropertyName"] = 127] = "ComputedPropertyName"; + SyntaxKind[SyntaxKind["TypeParameter"] = 128] = "TypeParameter"; + SyntaxKind[SyntaxKind["Parameter"] = 129] = "Parameter"; + SyntaxKind[SyntaxKind["Decorator"] = 130] = "Decorator"; + SyntaxKind[SyntaxKind["PropertySignature"] = 131] = "PropertySignature"; + SyntaxKind[SyntaxKind["PropertyDeclaration"] = 132] = "PropertyDeclaration"; + SyntaxKind[SyntaxKind["MethodSignature"] = 133] = "MethodSignature"; + SyntaxKind[SyntaxKind["MethodDeclaration"] = 134] = "MethodDeclaration"; + SyntaxKind[SyntaxKind["Constructor"] = 135] = "Constructor"; + SyntaxKind[SyntaxKind["GetAccessor"] = 136] = "GetAccessor"; + SyntaxKind[SyntaxKind["SetAccessor"] = 137] = "SetAccessor"; + SyntaxKind[SyntaxKind["CallSignature"] = 138] = "CallSignature"; + SyntaxKind[SyntaxKind["ConstructSignature"] = 139] = "ConstructSignature"; + SyntaxKind[SyntaxKind["IndexSignature"] = 140] = "IndexSignature"; + SyntaxKind[SyntaxKind["TypeReference"] = 141] = "TypeReference"; + SyntaxKind[SyntaxKind["FunctionType"] = 142] = "FunctionType"; + SyntaxKind[SyntaxKind["ConstructorType"] = 143] = "ConstructorType"; + SyntaxKind[SyntaxKind["TypeQuery"] = 144] = "TypeQuery"; + SyntaxKind[SyntaxKind["TypeLiteral"] = 145] = "TypeLiteral"; + SyntaxKind[SyntaxKind["ArrayType"] = 146] = "ArrayType"; + SyntaxKind[SyntaxKind["TupleType"] = 147] = "TupleType"; + SyntaxKind[SyntaxKind["UnionType"] = 148] = "UnionType"; + SyntaxKind[SyntaxKind["ParenthesizedType"] = 149] = "ParenthesizedType"; + SyntaxKind[SyntaxKind["ObjectBindingPattern"] = 150] = "ObjectBindingPattern"; + SyntaxKind[SyntaxKind["ArrayBindingPattern"] = 151] = "ArrayBindingPattern"; + SyntaxKind[SyntaxKind["BindingElement"] = 152] = "BindingElement"; + SyntaxKind[SyntaxKind["ArrayLiteralExpression"] = 153] = "ArrayLiteralExpression"; + SyntaxKind[SyntaxKind["ObjectLiteralExpression"] = 154] = "ObjectLiteralExpression"; + SyntaxKind[SyntaxKind["PropertyAccessExpression"] = 155] = "PropertyAccessExpression"; + SyntaxKind[SyntaxKind["ElementAccessExpression"] = 156] = "ElementAccessExpression"; + SyntaxKind[SyntaxKind["CallExpression"] = 157] = "CallExpression"; + SyntaxKind[SyntaxKind["NewExpression"] = 158] = "NewExpression"; + SyntaxKind[SyntaxKind["TaggedTemplateExpression"] = 159] = "TaggedTemplateExpression"; + SyntaxKind[SyntaxKind["TypeAssertionExpression"] = 160] = "TypeAssertionExpression"; + SyntaxKind[SyntaxKind["ParenthesizedExpression"] = 161] = "ParenthesizedExpression"; + SyntaxKind[SyntaxKind["FunctionExpression"] = 162] = "FunctionExpression"; + SyntaxKind[SyntaxKind["ArrowFunction"] = 163] = "ArrowFunction"; + SyntaxKind[SyntaxKind["DeleteExpression"] = 164] = "DeleteExpression"; + SyntaxKind[SyntaxKind["TypeOfExpression"] = 165] = "TypeOfExpression"; + SyntaxKind[SyntaxKind["VoidExpression"] = 166] = "VoidExpression"; + SyntaxKind[SyntaxKind["PrefixUnaryExpression"] = 167] = "PrefixUnaryExpression"; + SyntaxKind[SyntaxKind["PostfixUnaryExpression"] = 168] = "PostfixUnaryExpression"; + SyntaxKind[SyntaxKind["BinaryExpression"] = 169] = "BinaryExpression"; + SyntaxKind[SyntaxKind["ConditionalExpression"] = 170] = "ConditionalExpression"; + SyntaxKind[SyntaxKind["TemplateExpression"] = 171] = "TemplateExpression"; + SyntaxKind[SyntaxKind["YieldExpression"] = 172] = "YieldExpression"; + SyntaxKind[SyntaxKind["SpreadElementExpression"] = 173] = "SpreadElementExpression"; + SyntaxKind[SyntaxKind["ClassExpression"] = 174] = "ClassExpression"; + SyntaxKind[SyntaxKind["OmittedExpression"] = 175] = "OmittedExpression"; + SyntaxKind[SyntaxKind["TemplateSpan"] = 176] = "TemplateSpan"; + SyntaxKind[SyntaxKind["HeritageClauseElement"] = 177] = "HeritageClauseElement"; + SyntaxKind[SyntaxKind["SemicolonClassElement"] = 178] = "SemicolonClassElement"; + SyntaxKind[SyntaxKind["Block"] = 179] = "Block"; + SyntaxKind[SyntaxKind["VariableStatement"] = 180] = "VariableStatement"; + SyntaxKind[SyntaxKind["EmptyStatement"] = 181] = "EmptyStatement"; + SyntaxKind[SyntaxKind["ExpressionStatement"] = 182] = "ExpressionStatement"; + SyntaxKind[SyntaxKind["IfStatement"] = 183] = "IfStatement"; + SyntaxKind[SyntaxKind["DoStatement"] = 184] = "DoStatement"; + SyntaxKind[SyntaxKind["WhileStatement"] = 185] = "WhileStatement"; + SyntaxKind[SyntaxKind["ForStatement"] = 186] = "ForStatement"; + SyntaxKind[SyntaxKind["ForInStatement"] = 187] = "ForInStatement"; + SyntaxKind[SyntaxKind["ForOfStatement"] = 188] = "ForOfStatement"; + SyntaxKind[SyntaxKind["ContinueStatement"] = 189] = "ContinueStatement"; + SyntaxKind[SyntaxKind["BreakStatement"] = 190] = "BreakStatement"; + SyntaxKind[SyntaxKind["ReturnStatement"] = 191] = "ReturnStatement"; + SyntaxKind[SyntaxKind["WithStatement"] = 192] = "WithStatement"; + SyntaxKind[SyntaxKind["SwitchStatement"] = 193] = "SwitchStatement"; + SyntaxKind[SyntaxKind["LabeledStatement"] = 194] = "LabeledStatement"; + SyntaxKind[SyntaxKind["ThrowStatement"] = 195] = "ThrowStatement"; + SyntaxKind[SyntaxKind["TryStatement"] = 196] = "TryStatement"; + SyntaxKind[SyntaxKind["DebuggerStatement"] = 197] = "DebuggerStatement"; + SyntaxKind[SyntaxKind["VariableDeclaration"] = 198] = "VariableDeclaration"; + SyntaxKind[SyntaxKind["VariableDeclarationList"] = 199] = "VariableDeclarationList"; + SyntaxKind[SyntaxKind["FunctionDeclaration"] = 200] = "FunctionDeclaration"; + SyntaxKind[SyntaxKind["ClassDeclaration"] = 201] = "ClassDeclaration"; + SyntaxKind[SyntaxKind["InterfaceDeclaration"] = 202] = "InterfaceDeclaration"; + SyntaxKind[SyntaxKind["TypeAliasDeclaration"] = 203] = "TypeAliasDeclaration"; + SyntaxKind[SyntaxKind["EnumDeclaration"] = 204] = "EnumDeclaration"; + SyntaxKind[SyntaxKind["ModuleDeclaration"] = 205] = "ModuleDeclaration"; + SyntaxKind[SyntaxKind["ModuleBlock"] = 206] = "ModuleBlock"; + SyntaxKind[SyntaxKind["CaseBlock"] = 207] = "CaseBlock"; + SyntaxKind[SyntaxKind["ImportEqualsDeclaration"] = 208] = "ImportEqualsDeclaration"; + SyntaxKind[SyntaxKind["ImportDeclaration"] = 209] = "ImportDeclaration"; + SyntaxKind[SyntaxKind["ImportClause"] = 210] = "ImportClause"; + SyntaxKind[SyntaxKind["NamespaceImport"] = 211] = "NamespaceImport"; + SyntaxKind[SyntaxKind["NamedImports"] = 212] = "NamedImports"; + SyntaxKind[SyntaxKind["ImportSpecifier"] = 213] = "ImportSpecifier"; + SyntaxKind[SyntaxKind["ExportAssignment"] = 214] = "ExportAssignment"; + SyntaxKind[SyntaxKind["ExportDeclaration"] = 215] = "ExportDeclaration"; + SyntaxKind[SyntaxKind["NamedExports"] = 216] = "NamedExports"; + SyntaxKind[SyntaxKind["ExportSpecifier"] = 217] = "ExportSpecifier"; + SyntaxKind[SyntaxKind["MissingDeclaration"] = 218] = "MissingDeclaration"; + SyntaxKind[SyntaxKind["ExternalModuleReference"] = 219] = "ExternalModuleReference"; + SyntaxKind[SyntaxKind["CaseClause"] = 220] = "CaseClause"; + SyntaxKind[SyntaxKind["DefaultClause"] = 221] = "DefaultClause"; + SyntaxKind[SyntaxKind["HeritageClause"] = 222] = "HeritageClause"; + SyntaxKind[SyntaxKind["CatchClause"] = 223] = "CatchClause"; + SyntaxKind[SyntaxKind["PropertyAssignment"] = 224] = "PropertyAssignment"; + SyntaxKind[SyntaxKind["ShorthandPropertyAssignment"] = 225] = "ShorthandPropertyAssignment"; + SyntaxKind[SyntaxKind["EnumMember"] = 226] = "EnumMember"; + SyntaxKind[SyntaxKind["SourceFile"] = 227] = "SourceFile"; + SyntaxKind[SyntaxKind["SyntaxList"] = 228] = "SyntaxList"; + SyntaxKind[SyntaxKind["Count"] = 229] = "Count"; + SyntaxKind[SyntaxKind["FirstAssignment"] = 53] = "FirstAssignment"; + SyntaxKind[SyntaxKind["LastAssignment"] = 64] = "LastAssignment"; + SyntaxKind[SyntaxKind["FirstReservedWord"] = 66] = "FirstReservedWord"; + SyntaxKind[SyntaxKind["LastReservedWord"] = 101] = "LastReservedWord"; + SyntaxKind[SyntaxKind["FirstKeyword"] = 66] = "FirstKeyword"; + SyntaxKind[SyntaxKind["LastKeyword"] = 125] = "LastKeyword"; + SyntaxKind[SyntaxKind["FirstFutureReservedWord"] = 102] = "FirstFutureReservedWord"; + SyntaxKind[SyntaxKind["LastFutureReservedWord"] = 110] = "LastFutureReservedWord"; + SyntaxKind[SyntaxKind["FirstTypeNode"] = 141] = "FirstTypeNode"; + SyntaxKind[SyntaxKind["LastTypeNode"] = 149] = "LastTypeNode"; + SyntaxKind[SyntaxKind["FirstPunctuation"] = 14] = "FirstPunctuation"; + SyntaxKind[SyntaxKind["LastPunctuation"] = 64] = "LastPunctuation"; + SyntaxKind[SyntaxKind["FirstToken"] = 0] = "FirstToken"; + SyntaxKind[SyntaxKind["LastToken"] = 125] = "LastToken"; + SyntaxKind[SyntaxKind["FirstTriviaToken"] = 2] = "FirstTriviaToken"; + SyntaxKind[SyntaxKind["LastTriviaToken"] = 6] = "LastTriviaToken"; + SyntaxKind[SyntaxKind["FirstLiteralToken"] = 7] = "FirstLiteralToken"; + SyntaxKind[SyntaxKind["LastLiteralToken"] = 10] = "LastLiteralToken"; + SyntaxKind[SyntaxKind["FirstTemplateToken"] = 10] = "FirstTemplateToken"; + SyntaxKind[SyntaxKind["LastTemplateToken"] = 13] = "LastTemplateToken"; + SyntaxKind[SyntaxKind["FirstBinaryOperator"] = 24] = "FirstBinaryOperator"; + SyntaxKind[SyntaxKind["LastBinaryOperator"] = 64] = "LastBinaryOperator"; + SyntaxKind[SyntaxKind["FirstNode"] = 126] = "FirstNode"; + })(ts.SyntaxKind || (ts.SyntaxKind = {})); + var SyntaxKind = ts.SyntaxKind; + (function (NodeFlags) { + NodeFlags[NodeFlags["Export"] = 1] = "Export"; + NodeFlags[NodeFlags["Ambient"] = 2] = "Ambient"; + NodeFlags[NodeFlags["Public"] = 16] = "Public"; + NodeFlags[NodeFlags["Private"] = 32] = "Private"; + NodeFlags[NodeFlags["Protected"] = 64] = "Protected"; + NodeFlags[NodeFlags["Static"] = 128] = "Static"; + NodeFlags[NodeFlags["Default"] = 256] = "Default"; + NodeFlags[NodeFlags["MultiLine"] = 512] = "MultiLine"; + NodeFlags[NodeFlags["Synthetic"] = 1024] = "Synthetic"; + NodeFlags[NodeFlags["DeclarationFile"] = 2048] = "DeclarationFile"; + NodeFlags[NodeFlags["Let"] = 4096] = "Let"; + NodeFlags[NodeFlags["Const"] = 8192] = "Const"; + NodeFlags[NodeFlags["OctalLiteral"] = 16384] = "OctalLiteral"; + NodeFlags[NodeFlags["ExportContext"] = 32768] = "ExportContext"; + NodeFlags[NodeFlags["Modifier"] = 499] = "Modifier"; + NodeFlags[NodeFlags["AccessibilityModifier"] = 112] = "AccessibilityModifier"; + NodeFlags[NodeFlags["BlockScoped"] = 12288] = "BlockScoped"; + })(ts.NodeFlags || (ts.NodeFlags = {})); + var NodeFlags = ts.NodeFlags; + (function (ParserContextFlags) { + ParserContextFlags[ParserContextFlags["StrictMode"] = 1] = "StrictMode"; + ParserContextFlags[ParserContextFlags["DisallowIn"] = 2] = "DisallowIn"; + ParserContextFlags[ParserContextFlags["Yield"] = 4] = "Yield"; + ParserContextFlags[ParserContextFlags["GeneratorParameter"] = 8] = "GeneratorParameter"; + ParserContextFlags[ParserContextFlags["Decorator"] = 16] = "Decorator"; + ParserContextFlags[ParserContextFlags["ThisNodeHasError"] = 32] = "ThisNodeHasError"; + ParserContextFlags[ParserContextFlags["ParserGeneratedFlags"] = 63] = "ParserGeneratedFlags"; + ParserContextFlags[ParserContextFlags["ThisNodeOrAnySubNodesHasError"] = 64] = "ThisNodeOrAnySubNodesHasError"; + ParserContextFlags[ParserContextFlags["HasAggregatedChildData"] = 128] = "HasAggregatedChildData"; + })(ts.ParserContextFlags || (ts.ParserContextFlags = {})); + var ParserContextFlags = ts.ParserContextFlags; + (function (RelationComparisonResult) { + RelationComparisonResult[RelationComparisonResult["Succeeded"] = 1] = "Succeeded"; + RelationComparisonResult[RelationComparisonResult["Failed"] = 2] = "Failed"; + RelationComparisonResult[RelationComparisonResult["FailedAndReported"] = 3] = "FailedAndReported"; + })(ts.RelationComparisonResult || (ts.RelationComparisonResult = {})); + var RelationComparisonResult = ts.RelationComparisonResult; + (function (ExitStatus) { + ExitStatus[ExitStatus["Success"] = 0] = "Success"; + ExitStatus[ExitStatus["DiagnosticsPresent_OutputsSkipped"] = 1] = "DiagnosticsPresent_OutputsSkipped"; + ExitStatus[ExitStatus["DiagnosticsPresent_OutputsGenerated"] = 2] = "DiagnosticsPresent_OutputsGenerated"; + })(ts.ExitStatus || (ts.ExitStatus = {})); + var ExitStatus = ts.ExitStatus; + (function (TypeFormatFlags) { + TypeFormatFlags[TypeFormatFlags["None"] = 0] = "None"; + TypeFormatFlags[TypeFormatFlags["WriteArrayAsGenericType"] = 1] = "WriteArrayAsGenericType"; + TypeFormatFlags[TypeFormatFlags["UseTypeOfFunction"] = 2] = "UseTypeOfFunction"; + TypeFormatFlags[TypeFormatFlags["NoTruncation"] = 4] = "NoTruncation"; + TypeFormatFlags[TypeFormatFlags["WriteArrowStyleSignature"] = 8] = "WriteArrowStyleSignature"; + TypeFormatFlags[TypeFormatFlags["WriteOwnNameForAnyLike"] = 16] = "WriteOwnNameForAnyLike"; + TypeFormatFlags[TypeFormatFlags["WriteTypeArgumentsOfSignature"] = 32] = "WriteTypeArgumentsOfSignature"; + TypeFormatFlags[TypeFormatFlags["InElementType"] = 64] = "InElementType"; + TypeFormatFlags[TypeFormatFlags["UseFullyQualifiedType"] = 128] = "UseFullyQualifiedType"; + })(ts.TypeFormatFlags || (ts.TypeFormatFlags = {})); + var TypeFormatFlags = ts.TypeFormatFlags; + (function (SymbolFormatFlags) { + SymbolFormatFlags[SymbolFormatFlags["None"] = 0] = "None"; + SymbolFormatFlags[SymbolFormatFlags["WriteTypeParametersOrArguments"] = 1] = "WriteTypeParametersOrArguments"; + SymbolFormatFlags[SymbolFormatFlags["UseOnlyExternalAliasing"] = 2] = "UseOnlyExternalAliasing"; + })(ts.SymbolFormatFlags || (ts.SymbolFormatFlags = {})); + var SymbolFormatFlags = ts.SymbolFormatFlags; + (function (SymbolAccessibility) { + SymbolAccessibility[SymbolAccessibility["Accessible"] = 0] = "Accessible"; + SymbolAccessibility[SymbolAccessibility["NotAccessible"] = 1] = "NotAccessible"; + SymbolAccessibility[SymbolAccessibility["CannotBeNamed"] = 2] = "CannotBeNamed"; + })(ts.SymbolAccessibility || (ts.SymbolAccessibility = {})); + var SymbolAccessibility = ts.SymbolAccessibility; + (function (SymbolFlags) { + SymbolFlags[SymbolFlags["FunctionScopedVariable"] = 1] = "FunctionScopedVariable"; + SymbolFlags[SymbolFlags["BlockScopedVariable"] = 2] = "BlockScopedVariable"; + SymbolFlags[SymbolFlags["Property"] = 4] = "Property"; + SymbolFlags[SymbolFlags["EnumMember"] = 8] = "EnumMember"; + SymbolFlags[SymbolFlags["Function"] = 16] = "Function"; + SymbolFlags[SymbolFlags["Class"] = 32] = "Class"; + SymbolFlags[SymbolFlags["Interface"] = 64] = "Interface"; + SymbolFlags[SymbolFlags["ConstEnum"] = 128] = "ConstEnum"; + SymbolFlags[SymbolFlags["RegularEnum"] = 256] = "RegularEnum"; + SymbolFlags[SymbolFlags["ValueModule"] = 512] = "ValueModule"; + SymbolFlags[SymbolFlags["NamespaceModule"] = 1024] = "NamespaceModule"; + SymbolFlags[SymbolFlags["TypeLiteral"] = 2048] = "TypeLiteral"; + SymbolFlags[SymbolFlags["ObjectLiteral"] = 4096] = "ObjectLiteral"; + SymbolFlags[SymbolFlags["Method"] = 8192] = "Method"; + SymbolFlags[SymbolFlags["Constructor"] = 16384] = "Constructor"; + SymbolFlags[SymbolFlags["GetAccessor"] = 32768] = "GetAccessor"; + SymbolFlags[SymbolFlags["SetAccessor"] = 65536] = "SetAccessor"; + SymbolFlags[SymbolFlags["Signature"] = 131072] = "Signature"; + SymbolFlags[SymbolFlags["TypeParameter"] = 262144] = "TypeParameter"; + SymbolFlags[SymbolFlags["TypeAlias"] = 524288] = "TypeAlias"; + SymbolFlags[SymbolFlags["ExportValue"] = 1048576] = "ExportValue"; + SymbolFlags[SymbolFlags["ExportType"] = 2097152] = "ExportType"; + SymbolFlags[SymbolFlags["ExportNamespace"] = 4194304] = "ExportNamespace"; + SymbolFlags[SymbolFlags["Alias"] = 8388608] = "Alias"; + SymbolFlags[SymbolFlags["Instantiated"] = 16777216] = "Instantiated"; + SymbolFlags[SymbolFlags["Merged"] = 33554432] = "Merged"; + SymbolFlags[SymbolFlags["Transient"] = 67108864] = "Transient"; + SymbolFlags[SymbolFlags["Prototype"] = 134217728] = "Prototype"; + SymbolFlags[SymbolFlags["UnionProperty"] = 268435456] = "UnionProperty"; + SymbolFlags[SymbolFlags["Optional"] = 536870912] = "Optional"; + SymbolFlags[SymbolFlags["ExportStar"] = 1073741824] = "ExportStar"; + SymbolFlags[SymbolFlags["Enum"] = 384] = "Enum"; + SymbolFlags[SymbolFlags["Variable"] = 3] = "Variable"; + SymbolFlags[SymbolFlags["Value"] = 107455] = "Value"; + SymbolFlags[SymbolFlags["Type"] = 793056] = "Type"; + SymbolFlags[SymbolFlags["Namespace"] = 1536] = "Namespace"; + SymbolFlags[SymbolFlags["Module"] = 1536] = "Module"; + SymbolFlags[SymbolFlags["Accessor"] = 98304] = "Accessor"; + SymbolFlags[SymbolFlags["FunctionScopedVariableExcludes"] = 107454] = "FunctionScopedVariableExcludes"; + SymbolFlags[SymbolFlags["BlockScopedVariableExcludes"] = 107455] = "BlockScopedVariableExcludes"; + SymbolFlags[SymbolFlags["ParameterExcludes"] = 107455] = "ParameterExcludes"; + SymbolFlags[SymbolFlags["PropertyExcludes"] = 107455] = "PropertyExcludes"; + SymbolFlags[SymbolFlags["EnumMemberExcludes"] = 107455] = "EnumMemberExcludes"; + SymbolFlags[SymbolFlags["FunctionExcludes"] = 106927] = "FunctionExcludes"; + SymbolFlags[SymbolFlags["ClassExcludes"] = 899583] = "ClassExcludes"; + SymbolFlags[SymbolFlags["InterfaceExcludes"] = 792992] = "InterfaceExcludes"; + SymbolFlags[SymbolFlags["RegularEnumExcludes"] = 899327] = "RegularEnumExcludes"; + SymbolFlags[SymbolFlags["ConstEnumExcludes"] = 899967] = "ConstEnumExcludes"; + SymbolFlags[SymbolFlags["ValueModuleExcludes"] = 106639] = "ValueModuleExcludes"; + SymbolFlags[SymbolFlags["NamespaceModuleExcludes"] = 0] = "NamespaceModuleExcludes"; + SymbolFlags[SymbolFlags["MethodExcludes"] = 99263] = "MethodExcludes"; + SymbolFlags[SymbolFlags["GetAccessorExcludes"] = 41919] = "GetAccessorExcludes"; + SymbolFlags[SymbolFlags["SetAccessorExcludes"] = 74687] = "SetAccessorExcludes"; + SymbolFlags[SymbolFlags["TypeParameterExcludes"] = 530912] = "TypeParameterExcludes"; + SymbolFlags[SymbolFlags["TypeAliasExcludes"] = 793056] = "TypeAliasExcludes"; + SymbolFlags[SymbolFlags["AliasExcludes"] = 8388608] = "AliasExcludes"; + SymbolFlags[SymbolFlags["ModuleMember"] = 8914931] = "ModuleMember"; + SymbolFlags[SymbolFlags["ExportHasLocal"] = 944] = "ExportHasLocal"; + SymbolFlags[SymbolFlags["HasLocals"] = 255504] = "HasLocals"; + SymbolFlags[SymbolFlags["HasExports"] = 1952] = "HasExports"; + SymbolFlags[SymbolFlags["HasMembers"] = 6240] = "HasMembers"; + SymbolFlags[SymbolFlags["IsContainer"] = 262128] = "IsContainer"; + SymbolFlags[SymbolFlags["PropertyOrAccessor"] = 98308] = "PropertyOrAccessor"; + SymbolFlags[SymbolFlags["Export"] = 7340032] = "Export"; + })(ts.SymbolFlags || (ts.SymbolFlags = {})); + var SymbolFlags = ts.SymbolFlags; + (function (NodeCheckFlags) { + NodeCheckFlags[NodeCheckFlags["TypeChecked"] = 1] = "TypeChecked"; + NodeCheckFlags[NodeCheckFlags["LexicalThis"] = 2] = "LexicalThis"; + NodeCheckFlags[NodeCheckFlags["CaptureThis"] = 4] = "CaptureThis"; + NodeCheckFlags[NodeCheckFlags["EmitExtends"] = 8] = "EmitExtends"; + NodeCheckFlags[NodeCheckFlags["SuperInstance"] = 16] = "SuperInstance"; + NodeCheckFlags[NodeCheckFlags["SuperStatic"] = 32] = "SuperStatic"; + NodeCheckFlags[NodeCheckFlags["ContextChecked"] = 64] = "ContextChecked"; + NodeCheckFlags[NodeCheckFlags["EnumValuesComputed"] = 128] = "EnumValuesComputed"; + NodeCheckFlags[NodeCheckFlags["BlockScopedBindingInLoop"] = 256] = "BlockScopedBindingInLoop"; + NodeCheckFlags[NodeCheckFlags["EmitDecorate"] = 512] = "EmitDecorate"; + NodeCheckFlags[NodeCheckFlags["EmitParam"] = 1024] = "EmitParam"; + NodeCheckFlags[NodeCheckFlags["LexicalModuleMergesWithClass"] = 2048] = "LexicalModuleMergesWithClass"; + })(ts.NodeCheckFlags || (ts.NodeCheckFlags = {})); + var NodeCheckFlags = ts.NodeCheckFlags; + (function (TypeFlags) { + TypeFlags[TypeFlags["Any"] = 1] = "Any"; + TypeFlags[TypeFlags["String"] = 2] = "String"; + TypeFlags[TypeFlags["Number"] = 4] = "Number"; + TypeFlags[TypeFlags["Boolean"] = 8] = "Boolean"; + TypeFlags[TypeFlags["Void"] = 16] = "Void"; + TypeFlags[TypeFlags["Undefined"] = 32] = "Undefined"; + TypeFlags[TypeFlags["Null"] = 64] = "Null"; + TypeFlags[TypeFlags["Enum"] = 128] = "Enum"; + TypeFlags[TypeFlags["StringLiteral"] = 256] = "StringLiteral"; + TypeFlags[TypeFlags["TypeParameter"] = 512] = "TypeParameter"; + TypeFlags[TypeFlags["Class"] = 1024] = "Class"; + TypeFlags[TypeFlags["Interface"] = 2048] = "Interface"; + TypeFlags[TypeFlags["Reference"] = 4096] = "Reference"; + TypeFlags[TypeFlags["Tuple"] = 8192] = "Tuple"; + TypeFlags[TypeFlags["Union"] = 16384] = "Union"; + TypeFlags[TypeFlags["Anonymous"] = 32768] = "Anonymous"; + TypeFlags[TypeFlags["FromSignature"] = 65536] = "FromSignature"; + TypeFlags[TypeFlags["ObjectLiteral"] = 131072] = "ObjectLiteral"; + TypeFlags[TypeFlags["ContainsUndefinedOrNull"] = 262144] = "ContainsUndefinedOrNull"; + TypeFlags[TypeFlags["ContainsObjectLiteral"] = 524288] = "ContainsObjectLiteral"; + TypeFlags[TypeFlags["ESSymbol"] = 1048576] = "ESSymbol"; + TypeFlags[TypeFlags["Intrinsic"] = 1048703] = "Intrinsic"; + TypeFlags[TypeFlags["Primitive"] = 1049086] = "Primitive"; + TypeFlags[TypeFlags["StringLike"] = 258] = "StringLike"; + TypeFlags[TypeFlags["NumberLike"] = 132] = "NumberLike"; + TypeFlags[TypeFlags["ObjectType"] = 48128] = "ObjectType"; + TypeFlags[TypeFlags["RequiresWidening"] = 786432] = "RequiresWidening"; + })(ts.TypeFlags || (ts.TypeFlags = {})); + var TypeFlags = ts.TypeFlags; + (function (SignatureKind) { + SignatureKind[SignatureKind["Call"] = 0] = "Call"; + SignatureKind[SignatureKind["Construct"] = 1] = "Construct"; + })(ts.SignatureKind || (ts.SignatureKind = {})); + var SignatureKind = ts.SignatureKind; + (function (IndexKind) { + IndexKind[IndexKind["String"] = 0] = "String"; + IndexKind[IndexKind["Number"] = 1] = "Number"; + })(ts.IndexKind || (ts.IndexKind = {})); + var IndexKind = ts.IndexKind; + (function (DiagnosticCategory) { + DiagnosticCategory[DiagnosticCategory["Warning"] = 0] = "Warning"; + DiagnosticCategory[DiagnosticCategory["Error"] = 1] = "Error"; + DiagnosticCategory[DiagnosticCategory["Message"] = 2] = "Message"; + })(ts.DiagnosticCategory || (ts.DiagnosticCategory = {})); + var DiagnosticCategory = ts.DiagnosticCategory; + (function (ModuleKind) { + ModuleKind[ModuleKind["None"] = 0] = "None"; + ModuleKind[ModuleKind["CommonJS"] = 1] = "CommonJS"; + ModuleKind[ModuleKind["AMD"] = 2] = "AMD"; + ModuleKind[ModuleKind["UMD"] = 3] = "UMD"; + })(ts.ModuleKind || (ts.ModuleKind = {})); + var ModuleKind = ts.ModuleKind; + (function (ScriptTarget) { + ScriptTarget[ScriptTarget["ES3"] = 0] = "ES3"; + ScriptTarget[ScriptTarget["ES5"] = 1] = "ES5"; + ScriptTarget[ScriptTarget["ES6"] = 2] = "ES6"; + ScriptTarget[ScriptTarget["Latest"] = 2] = "Latest"; + })(ts.ScriptTarget || (ts.ScriptTarget = {})); + var ScriptTarget = ts.ScriptTarget; + (function (CharacterCodes) { + CharacterCodes[CharacterCodes["nullCharacter"] = 0] = "nullCharacter"; + CharacterCodes[CharacterCodes["maxAsciiCharacter"] = 127] = "maxAsciiCharacter"; + CharacterCodes[CharacterCodes["lineFeed"] = 10] = "lineFeed"; + CharacterCodes[CharacterCodes["carriageReturn"] = 13] = "carriageReturn"; + CharacterCodes[CharacterCodes["lineSeparator"] = 8232] = "lineSeparator"; + CharacterCodes[CharacterCodes["paragraphSeparator"] = 8233] = "paragraphSeparator"; + CharacterCodes[CharacterCodes["nextLine"] = 133] = "nextLine"; + CharacterCodes[CharacterCodes["space"] = 32] = "space"; + CharacterCodes[CharacterCodes["nonBreakingSpace"] = 160] = "nonBreakingSpace"; + CharacterCodes[CharacterCodes["enQuad"] = 8192] = "enQuad"; + CharacterCodes[CharacterCodes["emQuad"] = 8193] = "emQuad"; + CharacterCodes[CharacterCodes["enSpace"] = 8194] = "enSpace"; + CharacterCodes[CharacterCodes["emSpace"] = 8195] = "emSpace"; + CharacterCodes[CharacterCodes["threePerEmSpace"] = 8196] = "threePerEmSpace"; + CharacterCodes[CharacterCodes["fourPerEmSpace"] = 8197] = "fourPerEmSpace"; + CharacterCodes[CharacterCodes["sixPerEmSpace"] = 8198] = "sixPerEmSpace"; + CharacterCodes[CharacterCodes["figureSpace"] = 8199] = "figureSpace"; + CharacterCodes[CharacterCodes["punctuationSpace"] = 8200] = "punctuationSpace"; + CharacterCodes[CharacterCodes["thinSpace"] = 8201] = "thinSpace"; + CharacterCodes[CharacterCodes["hairSpace"] = 8202] = "hairSpace"; + CharacterCodes[CharacterCodes["zeroWidthSpace"] = 8203] = "zeroWidthSpace"; + CharacterCodes[CharacterCodes["narrowNoBreakSpace"] = 8239] = "narrowNoBreakSpace"; + CharacterCodes[CharacterCodes["ideographicSpace"] = 12288] = "ideographicSpace"; + CharacterCodes[CharacterCodes["mathematicalSpace"] = 8287] = "mathematicalSpace"; + CharacterCodes[CharacterCodes["ogham"] = 5760] = "ogham"; + CharacterCodes[CharacterCodes["_"] = 95] = "_"; + CharacterCodes[CharacterCodes["$"] = 36] = "$"; + CharacterCodes[CharacterCodes["_0"] = 48] = "_0"; + CharacterCodes[CharacterCodes["_1"] = 49] = "_1"; + CharacterCodes[CharacterCodes["_2"] = 50] = "_2"; + CharacterCodes[CharacterCodes["_3"] = 51] = "_3"; + CharacterCodes[CharacterCodes["_4"] = 52] = "_4"; + CharacterCodes[CharacterCodes["_5"] = 53] = "_5"; + CharacterCodes[CharacterCodes["_6"] = 54] = "_6"; + CharacterCodes[CharacterCodes["_7"] = 55] = "_7"; + CharacterCodes[CharacterCodes["_8"] = 56] = "_8"; + CharacterCodes[CharacterCodes["_9"] = 57] = "_9"; + CharacterCodes[CharacterCodes["a"] = 97] = "a"; + CharacterCodes[CharacterCodes["b"] = 98] = "b"; + CharacterCodes[CharacterCodes["c"] = 99] = "c"; + CharacterCodes[CharacterCodes["d"] = 100] = "d"; + CharacterCodes[CharacterCodes["e"] = 101] = "e"; + CharacterCodes[CharacterCodes["f"] = 102] = "f"; + CharacterCodes[CharacterCodes["g"] = 103] = "g"; + CharacterCodes[CharacterCodes["h"] = 104] = "h"; + CharacterCodes[CharacterCodes["i"] = 105] = "i"; + CharacterCodes[CharacterCodes["j"] = 106] = "j"; + CharacterCodes[CharacterCodes["k"] = 107] = "k"; + CharacterCodes[CharacterCodes["l"] = 108] = "l"; + CharacterCodes[CharacterCodes["m"] = 109] = "m"; + CharacterCodes[CharacterCodes["n"] = 110] = "n"; + CharacterCodes[CharacterCodes["o"] = 111] = "o"; + CharacterCodes[CharacterCodes["p"] = 112] = "p"; + CharacterCodes[CharacterCodes["q"] = 113] = "q"; + CharacterCodes[CharacterCodes["r"] = 114] = "r"; + CharacterCodes[CharacterCodes["s"] = 115] = "s"; + CharacterCodes[CharacterCodes["t"] = 116] = "t"; + CharacterCodes[CharacterCodes["u"] = 117] = "u"; + CharacterCodes[CharacterCodes["v"] = 118] = "v"; + CharacterCodes[CharacterCodes["w"] = 119] = "w"; + CharacterCodes[CharacterCodes["x"] = 120] = "x"; + CharacterCodes[CharacterCodes["y"] = 121] = "y"; + CharacterCodes[CharacterCodes["z"] = 122] = "z"; + CharacterCodes[CharacterCodes["A"] = 65] = "A"; + CharacterCodes[CharacterCodes["B"] = 66] = "B"; + CharacterCodes[CharacterCodes["C"] = 67] = "C"; + CharacterCodes[CharacterCodes["D"] = 68] = "D"; + CharacterCodes[CharacterCodes["E"] = 69] = "E"; + CharacterCodes[CharacterCodes["F"] = 70] = "F"; + CharacterCodes[CharacterCodes["G"] = 71] = "G"; + CharacterCodes[CharacterCodes["H"] = 72] = "H"; + CharacterCodes[CharacterCodes["I"] = 73] = "I"; + CharacterCodes[CharacterCodes["J"] = 74] = "J"; + CharacterCodes[CharacterCodes["K"] = 75] = "K"; + CharacterCodes[CharacterCodes["L"] = 76] = "L"; + CharacterCodes[CharacterCodes["M"] = 77] = "M"; + CharacterCodes[CharacterCodes["N"] = 78] = "N"; + CharacterCodes[CharacterCodes["O"] = 79] = "O"; + CharacterCodes[CharacterCodes["P"] = 80] = "P"; + CharacterCodes[CharacterCodes["Q"] = 81] = "Q"; + CharacterCodes[CharacterCodes["R"] = 82] = "R"; + CharacterCodes[CharacterCodes["S"] = 83] = "S"; + CharacterCodes[CharacterCodes["T"] = 84] = "T"; + CharacterCodes[CharacterCodes["U"] = 85] = "U"; + CharacterCodes[CharacterCodes["V"] = 86] = "V"; + CharacterCodes[CharacterCodes["W"] = 87] = "W"; + CharacterCodes[CharacterCodes["X"] = 88] = "X"; + CharacterCodes[CharacterCodes["Y"] = 89] = "Y"; + CharacterCodes[CharacterCodes["Z"] = 90] = "Z"; + CharacterCodes[CharacterCodes["ampersand"] = 38] = "ampersand"; + CharacterCodes[CharacterCodes["asterisk"] = 42] = "asterisk"; + CharacterCodes[CharacterCodes["at"] = 64] = "at"; + CharacterCodes[CharacterCodes["backslash"] = 92] = "backslash"; + CharacterCodes[CharacterCodes["backtick"] = 96] = "backtick"; + CharacterCodes[CharacterCodes["bar"] = 124] = "bar"; + CharacterCodes[CharacterCodes["caret"] = 94] = "caret"; + CharacterCodes[CharacterCodes["closeBrace"] = 125] = "closeBrace"; + CharacterCodes[CharacterCodes["closeBracket"] = 93] = "closeBracket"; + CharacterCodes[CharacterCodes["closeParen"] = 41] = "closeParen"; + CharacterCodes[CharacterCodes["colon"] = 58] = "colon"; + CharacterCodes[CharacterCodes["comma"] = 44] = "comma"; + CharacterCodes[CharacterCodes["dot"] = 46] = "dot"; + CharacterCodes[CharacterCodes["doubleQuote"] = 34] = "doubleQuote"; + CharacterCodes[CharacterCodes["equals"] = 61] = "equals"; + CharacterCodes[CharacterCodes["exclamation"] = 33] = "exclamation"; + CharacterCodes[CharacterCodes["greaterThan"] = 62] = "greaterThan"; + CharacterCodes[CharacterCodes["hash"] = 35] = "hash"; + CharacterCodes[CharacterCodes["lessThan"] = 60] = "lessThan"; + CharacterCodes[CharacterCodes["minus"] = 45] = "minus"; + CharacterCodes[CharacterCodes["openBrace"] = 123] = "openBrace"; + CharacterCodes[CharacterCodes["openBracket"] = 91] = "openBracket"; + CharacterCodes[CharacterCodes["openParen"] = 40] = "openParen"; + CharacterCodes[CharacterCodes["percent"] = 37] = "percent"; + CharacterCodes[CharacterCodes["plus"] = 43] = "plus"; + CharacterCodes[CharacterCodes["question"] = 63] = "question"; + CharacterCodes[CharacterCodes["semicolon"] = 59] = "semicolon"; + CharacterCodes[CharacterCodes["singleQuote"] = 39] = "singleQuote"; + CharacterCodes[CharacterCodes["slash"] = 47] = "slash"; + CharacterCodes[CharacterCodes["tilde"] = 126] = "tilde"; + CharacterCodes[CharacterCodes["backspace"] = 8] = "backspace"; + CharacterCodes[CharacterCodes["formFeed"] = 12] = "formFeed"; + CharacterCodes[CharacterCodes["byteOrderMark"] = 65279] = "byteOrderMark"; + CharacterCodes[CharacterCodes["tab"] = 9] = "tab"; + CharacterCodes[CharacterCodes["verticalTab"] = 11] = "verticalTab"; + })(ts.CharacterCodes || (ts.CharacterCodes = {})); + var CharacterCodes = ts.CharacterCodes; +})(ts || (ts = {})); diff --git a/dist/typescript/compiler/utilities.js b/dist/typescript/compiler/utilities.js new file mode 100644 index 000000000..e532c25a3 --- /dev/null +++ b/dist/typescript/compiler/utilities.js @@ -0,0 +1,1523 @@ +/// +var ts; +(function (ts) { + function getDeclarationOfKind(symbol, kind) { + var declarations = symbol.declarations; + for (var _i = 0; _i < declarations.length; _i++) { + var declaration = declarations[_i]; + if (declaration.kind === kind) { + return declaration; + } + } + return undefined; + } + ts.getDeclarationOfKind = getDeclarationOfKind; + var stringWriters = []; + function getSingleLineStringWriter() { + if (stringWriters.length == 0) { + var str = ""; + var writeText = function (text) { return str += text; }; + return { + string: function () { return str; }, + writeKeyword: writeText, + writeOperator: writeText, + writePunctuation: writeText, + writeSpace: writeText, + writeStringLiteral: writeText, + writeParameter: writeText, + writeSymbol: writeText, + writeLine: function () { return str += " "; }, + increaseIndent: function () { }, + decreaseIndent: function () { }, + clear: function () { return str = ""; }, + trackSymbol: function () { } + }; + } + return stringWriters.pop(); + } + ts.getSingleLineStringWriter = getSingleLineStringWriter; + function releaseStringWriter(writer) { + writer.clear(); + stringWriters.push(writer); + } + ts.releaseStringWriter = releaseStringWriter; + function getFullWidth(node) { + return node.end - node.pos; + } + ts.getFullWidth = getFullWidth; + function containsParseError(node) { + aggregateChildData(node); + return (node.parserContextFlags & 64) !== 0; + } + ts.containsParseError = containsParseError; + function aggregateChildData(node) { + if (!(node.parserContextFlags & 128)) { + var thisNodeOrAnySubNodesHasError = ((node.parserContextFlags & 32) !== 0) || + ts.forEachChild(node, containsParseError); + if (thisNodeOrAnySubNodesHasError) { + node.parserContextFlags |= 64; + } + node.parserContextFlags |= 128; + } + } + function getSourceFileOfNode(node) { + while (node && node.kind !== 227) { + node = node.parent; + } + return node; + } + ts.getSourceFileOfNode = getSourceFileOfNode; + function getStartPositionOfLine(line, sourceFile) { + ts.Debug.assert(line >= 0); + return ts.getLineStarts(sourceFile)[line]; + } + ts.getStartPositionOfLine = getStartPositionOfLine; + function nodePosToString(node) { + var file = getSourceFileOfNode(node); + var loc = ts.getLineAndCharacterOfPosition(file, node.pos); + return file.fileName + "(" + (loc.line + 1) + "," + (loc.character + 1) + ")"; + } + ts.nodePosToString = nodePosToString; + function getStartPosOfNode(node) { + return node.pos; + } + ts.getStartPosOfNode = getStartPosOfNode; + function nodeIsMissing(node) { + if (!node) { + return true; + } + return node.pos === node.end && node.kind !== 1; + } + ts.nodeIsMissing = nodeIsMissing; + function nodeIsPresent(node) { + return !nodeIsMissing(node); + } + ts.nodeIsPresent = nodeIsPresent; + function getTokenPosOfNode(node, sourceFile) { + if (nodeIsMissing(node)) { + return node.pos; + } + return ts.skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos); + } + ts.getTokenPosOfNode = getTokenPosOfNode; + function getNonDecoratorTokenPosOfNode(node, sourceFile) { + if (nodeIsMissing(node) || !node.decorators) { + return getTokenPosOfNode(node, sourceFile); + } + return ts.skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.decorators.end); + } + ts.getNonDecoratorTokenPosOfNode = getNonDecoratorTokenPosOfNode; + function getSourceTextOfNodeFromSourceFile(sourceFile, node) { + if (nodeIsMissing(node)) { + return ""; + } + var text = sourceFile.text; + return text.substring(ts.skipTrivia(text, node.pos), node.end); + } + ts.getSourceTextOfNodeFromSourceFile = getSourceTextOfNodeFromSourceFile; + function getTextOfNodeFromSourceText(sourceText, node) { + if (nodeIsMissing(node)) { + return ""; + } + return sourceText.substring(ts.skipTrivia(sourceText, node.pos), node.end); + } + ts.getTextOfNodeFromSourceText = getTextOfNodeFromSourceText; + function getTextOfNode(node) { + return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node); + } + ts.getTextOfNode = getTextOfNode; + function escapeIdentifier(identifier) { + return identifier.length >= 2 && identifier.charCodeAt(0) === 95 && identifier.charCodeAt(1) === 95 ? "_" + identifier : identifier; + } + ts.escapeIdentifier = escapeIdentifier; + function unescapeIdentifier(identifier) { + return identifier.length >= 3 && identifier.charCodeAt(0) === 95 && identifier.charCodeAt(1) === 95 && identifier.charCodeAt(2) === 95 ? identifier.substr(1) : identifier; + } + ts.unescapeIdentifier = unescapeIdentifier; + function makeIdentifierFromModuleName(moduleName) { + return ts.getBaseFileName(moduleName).replace(/\W/g, "_"); + } + ts.makeIdentifierFromModuleName = makeIdentifierFromModuleName; + function isBlockOrCatchScoped(declaration) { + return (getCombinedNodeFlags(declaration) & 12288) !== 0 || + isCatchClauseVariableDeclaration(declaration); + } + ts.isBlockOrCatchScoped = isBlockOrCatchScoped; + function getEnclosingBlockScopeContainer(node) { + var current = node.parent; + while (current) { + if (isFunctionLike(current)) { + return current; + } + switch (current.kind) { + case 227: + case 207: + case 223: + case 205: + case 186: + case 187: + case 188: + return current; + case 179: + if (!isFunctionLike(current.parent)) { + return current; + } + } + current = current.parent; + } + } + ts.getEnclosingBlockScopeContainer = getEnclosingBlockScopeContainer; + function isCatchClauseVariableDeclaration(declaration) { + return declaration && + declaration.kind === 198 && + declaration.parent && + declaration.parent.kind === 223; + } + ts.isCatchClauseVariableDeclaration = isCatchClauseVariableDeclaration; + function declarationNameToString(name) { + return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name); + } + ts.declarationNameToString = declarationNameToString; + function createDiagnosticForNode(node, message, arg0, arg1, arg2) { + var sourceFile = getSourceFileOfNode(node); + var span = getErrorSpanForNode(sourceFile, node); + return ts.createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2); + } + ts.createDiagnosticForNode = createDiagnosticForNode; + function createDiagnosticForNodeFromMessageChain(node, messageChain) { + var sourceFile = getSourceFileOfNode(node); + var span = getErrorSpanForNode(sourceFile, node); + return { + file: sourceFile, + start: span.start, + length: span.length, + code: messageChain.code, + category: messageChain.category, + messageText: messageChain.next ? messageChain : messageChain.messageText + }; + } + ts.createDiagnosticForNodeFromMessageChain = createDiagnosticForNodeFromMessageChain; + function getSpanOfTokenAtPosition(sourceFile, pos) { + var scanner = ts.createScanner(sourceFile.languageVersion, true, sourceFile.text, undefined, pos); + scanner.scan(); + var start = scanner.getTokenPos(); + return ts.createTextSpanFromBounds(start, scanner.getTextPos()); + } + ts.getSpanOfTokenAtPosition = getSpanOfTokenAtPosition; + function getErrorSpanForNode(sourceFile, node) { + var errorNode = node; + switch (node.kind) { + case 227: + var pos_1 = ts.skipTrivia(sourceFile.text, 0, false); + if (pos_1 === sourceFile.text.length) { + return ts.createTextSpan(0, 0); + } + return getSpanOfTokenAtPosition(sourceFile, pos_1); + case 198: + case 152: + case 201: + case 174: + case 202: + case 205: + case 204: + case 226: + case 200: + case 162: + errorNode = node.name; + break; + } + if (errorNode === undefined) { + return getSpanOfTokenAtPosition(sourceFile, node.pos); + } + var pos = nodeIsMissing(errorNode) + ? errorNode.pos + : ts.skipTrivia(sourceFile.text, errorNode.pos); + return ts.createTextSpanFromBounds(pos, errorNode.end); + } + ts.getErrorSpanForNode = getErrorSpanForNode; + function isExternalModule(file) { + return file.externalModuleIndicator !== undefined; + } + ts.isExternalModule = isExternalModule; + function isDeclarationFile(file) { + return (file.flags & 2048) !== 0; + } + ts.isDeclarationFile = isDeclarationFile; + function isConstEnumDeclaration(node) { + return node.kind === 204 && isConst(node); + } + ts.isConstEnumDeclaration = isConstEnumDeclaration; + function walkUpBindingElementsAndPatterns(node) { + while (node && (node.kind === 152 || isBindingPattern(node))) { + node = node.parent; + } + return node; + } + function getCombinedNodeFlags(node) { + node = walkUpBindingElementsAndPatterns(node); + var flags = node.flags; + if (node.kind === 198) { + node = node.parent; + } + if (node && node.kind === 199) { + flags |= node.flags; + node = node.parent; + } + if (node && node.kind === 180) { + flags |= node.flags; + } + return flags; + } + ts.getCombinedNodeFlags = getCombinedNodeFlags; + function isConst(node) { + return !!(getCombinedNodeFlags(node) & 8192); + } + ts.isConst = isConst; + function isLet(node) { + return !!(getCombinedNodeFlags(node) & 4096); + } + ts.isLet = isLet; + function isPrologueDirective(node) { + return node.kind === 182 && node.expression.kind === 8; + } + ts.isPrologueDirective = isPrologueDirective; + function getLeadingCommentRangesOfNode(node, sourceFileOfNode) { + if (node.kind === 129 || node.kind === 128) { + return ts.concatenate(ts.getTrailingCommentRanges(sourceFileOfNode.text, node.pos), ts.getLeadingCommentRanges(sourceFileOfNode.text, node.pos)); + } + else { + return ts.getLeadingCommentRanges(sourceFileOfNode.text, node.pos); + } + } + ts.getLeadingCommentRangesOfNode = getLeadingCommentRangesOfNode; + function getJsDocComments(node, sourceFileOfNode) { + return ts.filter(getLeadingCommentRangesOfNode(node, sourceFileOfNode), isJsDocComment); + function isJsDocComment(comment) { + return sourceFileOfNode.text.charCodeAt(comment.pos + 1) === 42 && + sourceFileOfNode.text.charCodeAt(comment.pos + 2) === 42 && + sourceFileOfNode.text.charCodeAt(comment.pos + 3) !== 47; + } + } + ts.getJsDocComments = getJsDocComments; + ts.fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*/; + function forEachReturnStatement(body, visitor) { + return traverse(body); + function traverse(node) { + switch (node.kind) { + case 191: + return visitor(node); + case 207: + case 179: + case 183: + case 184: + case 185: + case 186: + case 187: + case 188: + case 192: + case 193: + case 220: + case 221: + case 194: + case 196: + case 223: + return ts.forEachChild(node, traverse); + } + } + } + ts.forEachReturnStatement = forEachReturnStatement; + function isVariableLike(node) { + if (node) { + switch (node.kind) { + case 152: + case 226: + case 129: + case 224: + case 132: + case 131: + case 225: + case 198: + return true; + } + } + return false; + } + ts.isVariableLike = isVariableLike; + function isAccessor(node) { + if (node) { + switch (node.kind) { + case 136: + case 137: + return true; + } + } + return false; + } + ts.isAccessor = isAccessor; + function isFunctionLike(node) { + if (node) { + switch (node.kind) { + case 135: + case 162: + case 200: + case 163: + case 134: + case 133: + case 136: + case 137: + case 138: + case 139: + case 140: + case 142: + case 143: + case 162: + case 163: + case 200: + return true; + } + } + return false; + } + ts.isFunctionLike = isFunctionLike; + function isFunctionBlock(node) { + return node && node.kind === 179 && isFunctionLike(node.parent); + } + ts.isFunctionBlock = isFunctionBlock; + function isObjectLiteralMethod(node) { + return node && node.kind === 134 && node.parent.kind === 154; + } + ts.isObjectLiteralMethod = isObjectLiteralMethod; + function getContainingFunction(node) { + while (true) { + node = node.parent; + if (!node || isFunctionLike(node)) { + return node; + } + } + } + ts.getContainingFunction = getContainingFunction; + function getThisContainer(node, includeArrowFunctions) { + while (true) { + node = node.parent; + if (!node) { + return undefined; + } + switch (node.kind) { + case 127: + if (node.parent.parent.kind === 201) { + return node; + } + node = node.parent; + break; + case 130: + if (node.parent.kind === 129 && isClassElement(node.parent.parent)) { + node = node.parent.parent; + } + else if (isClassElement(node.parent)) { + node = node.parent; + } + break; + case 163: + if (!includeArrowFunctions) { + continue; + } + case 200: + case 162: + case 205: + case 132: + case 131: + case 134: + case 133: + case 135: + case 136: + case 137: + case 204: + case 227: + return node; + } + } + } + ts.getThisContainer = getThisContainer; + function getSuperContainer(node, includeFunctions) { + while (true) { + node = node.parent; + if (!node) + return node; + switch (node.kind) { + case 127: + if (node.parent.parent.kind === 201) { + return node; + } + node = node.parent; + break; + case 130: + if (node.parent.kind === 129 && isClassElement(node.parent.parent)) { + node = node.parent.parent; + } + else if (isClassElement(node.parent)) { + node = node.parent; + } + break; + case 200: + case 162: + case 163: + if (!includeFunctions) { + continue; + } + case 132: + case 131: + case 134: + case 133: + case 135: + case 136: + case 137: + return node; + } + } + } + ts.getSuperContainer = getSuperContainer; + function getInvokedExpression(node) { + if (node.kind === 159) { + return node.tag; + } + return node.expression; + } + ts.getInvokedExpression = getInvokedExpression; + function nodeCanBeDecorated(node) { + switch (node.kind) { + case 201: + return true; + case 132: + return node.parent.kind === 201; + case 129: + return node.parent.body && node.parent.parent.kind === 201; + case 136: + case 137: + case 134: + return node.body && node.parent.kind === 201; + } + return false; + } + ts.nodeCanBeDecorated = nodeCanBeDecorated; + function nodeIsDecorated(node) { + switch (node.kind) { + case 201: + if (node.decorators) { + return true; + } + return false; + case 132: + case 129: + if (node.decorators) { + return true; + } + return false; + case 136: + if (node.body && node.decorators) { + return true; + } + return false; + case 134: + case 137: + if (node.body && node.decorators) { + return true; + } + return false; + } + return false; + } + ts.nodeIsDecorated = nodeIsDecorated; + function childIsDecorated(node) { + switch (node.kind) { + case 201: + return ts.forEach(node.members, nodeOrChildIsDecorated); + case 134: + case 137: + return ts.forEach(node.parameters, nodeIsDecorated); + } + return false; + } + ts.childIsDecorated = childIsDecorated; + function nodeOrChildIsDecorated(node) { + return nodeIsDecorated(node) || childIsDecorated(node); + } + ts.nodeOrChildIsDecorated = nodeOrChildIsDecorated; + function isExpression(node) { + switch (node.kind) { + case 93: + case 91: + case 89: + case 95: + case 80: + case 9: + case 153: + case 154: + case 155: + case 156: + case 157: + case 158: + case 159: + case 160: + case 161: + case 162: + case 174: + case 163: + case 166: + case 164: + case 165: + case 167: + case 168: + case 169: + case 170: + case 173: + case 171: + case 10: + case 175: + return true; + case 126: + while (node.parent.kind === 126) { + node = node.parent; + } + return node.parent.kind === 144; + case 65: + if (node.parent.kind === 144) { + return true; + } + case 7: + case 8: + var parent_1 = node.parent; + switch (parent_1.kind) { + case 198: + case 129: + case 132: + case 131: + case 226: + case 224: + case 152: + return parent_1.initializer === node; + case 182: + case 183: + case 184: + case 185: + case 191: + case 192: + case 193: + case 220: + case 195: + case 193: + return parent_1.expression === node; + case 186: + var forStatement = parent_1; + return (forStatement.initializer === node && forStatement.initializer.kind !== 199) || + forStatement.condition === node || + forStatement.incrementor === node; + case 187: + case 188: + var forInStatement = parent_1; + return (forInStatement.initializer === node && forInStatement.initializer.kind !== 199) || + forInStatement.expression === node; + case 160: + return node === parent_1.expression; + case 176: + return node === parent_1.expression; + case 127: + return node === parent_1.expression; + case 130: + return true; + default: + if (isExpression(parent_1)) { + return true; + } + } + } + return false; + } + ts.isExpression = isExpression; + function isInstantiatedModule(node, preserveConstEnums) { + var moduleState = ts.getModuleInstanceState(node); + return moduleState === 1 || + (preserveConstEnums && moduleState === 2); + } + ts.isInstantiatedModule = isInstantiatedModule; + function isExternalModuleImportEqualsDeclaration(node) { + return node.kind === 208 && node.moduleReference.kind === 219; + } + ts.isExternalModuleImportEqualsDeclaration = isExternalModuleImportEqualsDeclaration; + function getExternalModuleImportEqualsDeclarationExpression(node) { + ts.Debug.assert(isExternalModuleImportEqualsDeclaration(node)); + return node.moduleReference.expression; + } + ts.getExternalModuleImportEqualsDeclarationExpression = getExternalModuleImportEqualsDeclarationExpression; + function isInternalModuleImportEqualsDeclaration(node) { + return node.kind === 208 && node.moduleReference.kind !== 219; + } + ts.isInternalModuleImportEqualsDeclaration = isInternalModuleImportEqualsDeclaration; + function getExternalModuleName(node) { + if (node.kind === 209) { + return node.moduleSpecifier; + } + if (node.kind === 208) { + var reference = node.moduleReference; + if (reference.kind === 219) { + return reference.expression; + } + } + if (node.kind === 215) { + return node.moduleSpecifier; + } + } + ts.getExternalModuleName = getExternalModuleName; + function hasDotDotDotToken(node) { + return node && node.kind === 129 && node.dotDotDotToken !== undefined; + } + ts.hasDotDotDotToken = hasDotDotDotToken; + function hasQuestionToken(node) { + if (node) { + switch (node.kind) { + case 129: + return node.questionToken !== undefined; + case 134: + case 133: + return node.questionToken !== undefined; + case 225: + case 224: + case 132: + case 131: + return node.questionToken !== undefined; + } + } + return false; + } + ts.hasQuestionToken = hasQuestionToken; + function hasRestParameters(s) { + return s.parameters.length > 0 && s.parameters[s.parameters.length - 1].dotDotDotToken !== undefined; + } + ts.hasRestParameters = hasRestParameters; + function isLiteralKind(kind) { + return 7 <= kind && kind <= 10; + } + ts.isLiteralKind = isLiteralKind; + function isTextualLiteralKind(kind) { + return kind === 8 || kind === 10; + } + ts.isTextualLiteralKind = isTextualLiteralKind; + function isTemplateLiteralKind(kind) { + return 10 <= kind && kind <= 13; + } + ts.isTemplateLiteralKind = isTemplateLiteralKind; + function isBindingPattern(node) { + return !!node && (node.kind === 151 || node.kind === 150); + } + ts.isBindingPattern = isBindingPattern; + function isInAmbientContext(node) { + while (node) { + if (node.flags & (2 | 2048)) { + return true; + } + node = node.parent; + } + return false; + } + ts.isInAmbientContext = isInAmbientContext; + function isDeclaration(node) { + switch (node.kind) { + case 163: + case 152: + case 201: + case 135: + case 204: + case 226: + case 217: + case 200: + case 162: + case 136: + case 210: + case 208: + case 213: + case 202: + case 134: + case 133: + case 205: + case 211: + case 129: + case 224: + case 132: + case 131: + case 137: + case 225: + case 203: + case 128: + case 198: + return true; + } + return false; + } + ts.isDeclaration = isDeclaration; + function isStatement(n) { + switch (n.kind) { + case 190: + case 189: + case 197: + case 184: + case 182: + case 181: + case 187: + case 188: + case 186: + case 183: + case 194: + case 191: + case 193: + case 94: + case 196: + case 180: + case 185: + case 192: + case 214: + return true; + default: + return false; + } + } + ts.isStatement = isStatement; + function isClassElement(n) { + switch (n.kind) { + case 135: + case 132: + case 134: + case 136: + case 137: + case 133: + case 140: + return true; + default: + return false; + } + } + ts.isClassElement = isClassElement; + function isDeclarationName(name) { + if (name.kind !== 65 && name.kind !== 8 && name.kind !== 7) { + return false; + } + var parent = name.parent; + if (parent.kind === 213 || parent.kind === 217) { + if (parent.propertyName) { + return true; + } + } + if (isDeclaration(parent)) { + return parent.name === name; + } + return false; + } + ts.isDeclarationName = isDeclarationName; + function isAliasSymbolDeclaration(node) { + return node.kind === 208 || + node.kind === 210 && !!node.name || + node.kind === 211 || + node.kind === 213 || + node.kind === 217 || + node.kind === 214 && node.expression.kind === 65; + } + ts.isAliasSymbolDeclaration = isAliasSymbolDeclaration; + function getClassExtendsHeritageClauseElement(node) { + var heritageClause = getHeritageClause(node.heritageClauses, 79); + return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined; + } + ts.getClassExtendsHeritageClauseElement = getClassExtendsHeritageClauseElement; + function getClassImplementsHeritageClauseElements(node) { + var heritageClause = getHeritageClause(node.heritageClauses, 102); + return heritageClause ? heritageClause.types : undefined; + } + ts.getClassImplementsHeritageClauseElements = getClassImplementsHeritageClauseElements; + function getInterfaceBaseTypeNodes(node) { + var heritageClause = getHeritageClause(node.heritageClauses, 79); + return heritageClause ? heritageClause.types : undefined; + } + ts.getInterfaceBaseTypeNodes = getInterfaceBaseTypeNodes; + function getHeritageClause(clauses, kind) { + if (clauses) { + for (var _i = 0; _i < clauses.length; _i++) { + var clause = clauses[_i]; + if (clause.token === kind) { + return clause; + } + } + } + return undefined; + } + ts.getHeritageClause = getHeritageClause; + function tryResolveScriptReference(host, sourceFile, reference) { + if (!host.getCompilerOptions().noResolve) { + var referenceFileName = ts.isRootedDiskPath(reference.fileName) ? reference.fileName : ts.combinePaths(ts.getDirectoryPath(sourceFile.fileName), reference.fileName); + referenceFileName = ts.getNormalizedAbsolutePath(referenceFileName, host.getCurrentDirectory()); + return host.getSourceFile(referenceFileName); + } + } + ts.tryResolveScriptReference = tryResolveScriptReference; + function getAncestor(node, kind) { + while (node) { + if (node.kind === kind) { + return node; + } + node = node.parent; + } + return undefined; + } + ts.getAncestor = getAncestor; + function getFileReferenceFromReferencePath(comment, commentRange) { + var simpleReferenceRegEx = /^\/\/\/\s*/gim; + if (simpleReferenceRegEx.exec(comment)) { + if (isNoDefaultLibRegEx.exec(comment)) { + return { + isNoDefaultLib: true + }; + } + else { + var matchResult = ts.fullTripleSlashReferencePathRegEx.exec(comment); + if (matchResult) { + var start = commentRange.pos; + var end = commentRange.end; + return { + fileReference: { + pos: start, + end: end, + fileName: matchResult[3] + }, + isNoDefaultLib: false + }; + } + else { + return { + diagnosticMessage: ts.Diagnostics.Invalid_reference_directive_syntax, + isNoDefaultLib: false + }; + } + } + } + return undefined; + } + ts.getFileReferenceFromReferencePath = getFileReferenceFromReferencePath; + function isKeyword(token) { + return 66 <= token && token <= 125; + } + ts.isKeyword = isKeyword; + function isTrivia(token) { + return 2 <= token && token <= 6; + } + ts.isTrivia = isTrivia; + function hasDynamicName(declaration) { + return declaration.name && + declaration.name.kind === 127 && + !isWellKnownSymbolSyntactically(declaration.name.expression); + } + ts.hasDynamicName = hasDynamicName; + function isWellKnownSymbolSyntactically(node) { + return node.kind === 155 && isESSymbolIdentifier(node.expression); + } + ts.isWellKnownSymbolSyntactically = isWellKnownSymbolSyntactically; + function getPropertyNameForPropertyNameNode(name) { + if (name.kind === 65 || name.kind === 8 || name.kind === 7) { + return name.text; + } + if (name.kind === 127) { + var nameExpression = name.expression; + if (isWellKnownSymbolSyntactically(nameExpression)) { + var rightHandSideName = nameExpression.name.text; + return getPropertyNameForKnownSymbolName(rightHandSideName); + } + } + return undefined; + } + ts.getPropertyNameForPropertyNameNode = getPropertyNameForPropertyNameNode; + function getPropertyNameForKnownSymbolName(symbolName) { + return "__@" + symbolName; + } + ts.getPropertyNameForKnownSymbolName = getPropertyNameForKnownSymbolName; + function isESSymbolIdentifier(node) { + return node.kind === 65 && node.text === "Symbol"; + } + ts.isESSymbolIdentifier = isESSymbolIdentifier; + function isModifier(token) { + switch (token) { + case 108: + case 106: + case 107: + case 109: + case 78: + case 115: + case 70: + case 73: + return true; + } + return false; + } + ts.isModifier = isModifier; + function nodeStartsNewLexicalEnvironment(n) { + return isFunctionLike(n) || n.kind === 205 || n.kind === 227; + } + ts.nodeStartsNewLexicalEnvironment = nodeStartsNewLexicalEnvironment; + function nodeIsSynthesized(node) { + return node.pos === -1; + } + ts.nodeIsSynthesized = nodeIsSynthesized; + function createSynthesizedNode(kind, startsOnNewLine) { + var node = ts.createNode(kind); + node.pos = -1; + node.end = -1; + node.startsOnNewLine = startsOnNewLine; + return node; + } + ts.createSynthesizedNode = createSynthesizedNode; + function createSynthesizedNodeArray() { + var array = []; + array.pos = -1; + array.end = -1; + return array; + } + ts.createSynthesizedNodeArray = createSynthesizedNodeArray; + function createDiagnosticCollection() { + var nonFileDiagnostics = []; + var fileDiagnostics = {}; + var diagnosticsModified = false; + var modificationCount = 0; + return { + add: add, + getGlobalDiagnostics: getGlobalDiagnostics, + getDiagnostics: getDiagnostics, + getModificationCount: getModificationCount + }; + function getModificationCount() { + return modificationCount; + } + function add(diagnostic) { + var diagnostics; + if (diagnostic.file) { + diagnostics = fileDiagnostics[diagnostic.file.fileName]; + if (!diagnostics) { + diagnostics = []; + fileDiagnostics[diagnostic.file.fileName] = diagnostics; + } + } + else { + diagnostics = nonFileDiagnostics; + } + diagnostics.push(diagnostic); + diagnosticsModified = true; + modificationCount++; + } + function getGlobalDiagnostics() { + sortAndDeduplicate(); + return nonFileDiagnostics; + } + function getDiagnostics(fileName) { + sortAndDeduplicate(); + if (fileName) { + return fileDiagnostics[fileName] || []; + } + var allDiagnostics = []; + function pushDiagnostic(d) { + allDiagnostics.push(d); + } + ts.forEach(nonFileDiagnostics, pushDiagnostic); + for (var key in fileDiagnostics) { + if (ts.hasProperty(fileDiagnostics, key)) { + ts.forEach(fileDiagnostics[key], pushDiagnostic); + } + } + return ts.sortAndDeduplicateDiagnostics(allDiagnostics); + } + function sortAndDeduplicate() { + if (!diagnosticsModified) { + return; + } + diagnosticsModified = false; + nonFileDiagnostics = ts.sortAndDeduplicateDiagnostics(nonFileDiagnostics); + for (var key in fileDiagnostics) { + if (ts.hasProperty(fileDiagnostics, key)) { + fileDiagnostics[key] = ts.sortAndDeduplicateDiagnostics(fileDiagnostics[key]); + } + } + } + } + ts.createDiagnosticCollection = createDiagnosticCollection; + var escapedCharsRegExp = /[\\\"\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g; + var escapedCharsMap = { + "\0": "\\0", + "\t": "\\t", + "\v": "\\v", + "\f": "\\f", + "\b": "\\b", + "\r": "\\r", + "\n": "\\n", + "\\": "\\\\", + "\"": "\\\"", + "\u2028": "\\u2028", + "\u2029": "\\u2029", + "\u0085": "\\u0085" + }; + function escapeString(s) { + s = escapedCharsRegExp.test(s) ? s.replace(escapedCharsRegExp, getReplacement) : s; + return s; + function getReplacement(c) { + return escapedCharsMap[c] || get16BitUnicodeEscapeSequence(c.charCodeAt(0)); + } + } + ts.escapeString = escapeString; + function get16BitUnicodeEscapeSequence(charCode) { + var hexCharCode = charCode.toString(16).toUpperCase(); + var paddedHexCode = ("0000" + hexCharCode).slice(-4); + return "\\u" + paddedHexCode; + } + var nonAsciiCharacters = /[^\u0000-\u007F]/g; + function escapeNonAsciiCharacters(s) { + return nonAsciiCharacters.test(s) ? + s.replace(nonAsciiCharacters, function (c) { return get16BitUnicodeEscapeSequence(c.charCodeAt(0)); }) : + s; + } + ts.escapeNonAsciiCharacters = escapeNonAsciiCharacters; + var indentStrings = ["", " "]; + function getIndentString(level) { + if (indentStrings[level] === undefined) { + indentStrings[level] = getIndentString(level - 1) + indentStrings[1]; + } + return indentStrings[level]; + } + ts.getIndentString = getIndentString; + function getIndentSize() { + return indentStrings[1].length; + } + ts.getIndentSize = getIndentSize; + function createTextWriter(newLine) { + var output = ""; + var indent = 0; + var lineStart = true; + var lineCount = 0; + var linePos = 0; + function write(s) { + if (s && s.length) { + if (lineStart) { + output += getIndentString(indent); + lineStart = false; + } + output += s; + } + } + function rawWrite(s) { + if (s !== undefined) { + if (lineStart) { + lineStart = false; + } + output += s; + } + } + function writeLiteral(s) { + if (s && s.length) { + write(s); + var lineStartsOfS = ts.computeLineStarts(s); + if (lineStartsOfS.length > 1) { + lineCount = lineCount + lineStartsOfS.length - 1; + linePos = output.length - s.length + lineStartsOfS[lineStartsOfS.length - 1]; + } + } + } + function writeLine() { + if (!lineStart) { + output += newLine; + lineCount++; + linePos = output.length; + lineStart = true; + } + } + function writeTextOfNode(sourceFile, node) { + write(getSourceTextOfNodeFromSourceFile(sourceFile, node)); + } + return { + write: write, + rawWrite: rawWrite, + writeTextOfNode: writeTextOfNode, + writeLiteral: writeLiteral, + writeLine: writeLine, + increaseIndent: function () { return indent++; }, + decreaseIndent: function () { return indent--; }, + getIndent: function () { return indent; }, + getTextPos: function () { return output.length; }, + getLine: function () { return lineCount + 1; }, + getColumn: function () { return lineStart ? indent * getIndentSize() + 1 : output.length - linePos + 1; }, + getText: function () { return output; }, + }; + } + ts.createTextWriter = createTextWriter; + function getOwnEmitOutputFilePath(sourceFile, host, extension) { + var compilerOptions = host.getCompilerOptions(); + var emitOutputFilePathWithoutExtension; + if (compilerOptions.outDir) { + emitOutputFilePathWithoutExtension = ts.removeFileExtension(getSourceFilePathInNewDir(sourceFile, host, compilerOptions.outDir)); + } + else { + emitOutputFilePathWithoutExtension = ts.removeFileExtension(sourceFile.fileName); + } + return emitOutputFilePathWithoutExtension + extension; + } + ts.getOwnEmitOutputFilePath = getOwnEmitOutputFilePath; + function getSourceFilePathInNewDir(sourceFile, host, newDirPath) { + var sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.fileName, host.getCurrentDirectory()); + sourceFilePath = sourceFilePath.replace(host.getCommonSourceDirectory(), ""); + return ts.combinePaths(newDirPath, sourceFilePath); + } + ts.getSourceFilePathInNewDir = getSourceFilePathInNewDir; + function writeFile(host, diagnostics, fileName, data, writeByteOrderMark) { + host.writeFile(fileName, data, writeByteOrderMark, function (hostErrorMessage) { + diagnostics.push(ts.createCompilerDiagnostic(ts.Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage)); + }); + } + ts.writeFile = writeFile; + function getLineOfLocalPosition(currentSourceFile, pos) { + return ts.getLineAndCharacterOfPosition(currentSourceFile, pos).line; + } + ts.getLineOfLocalPosition = getLineOfLocalPosition; + function getFirstConstructorWithBody(node) { + return ts.forEach(node.members, function (member) { + if (member.kind === 135 && nodeIsPresent(member.body)) { + return member; + } + }); + } + ts.getFirstConstructorWithBody = getFirstConstructorWithBody; + function shouldEmitToOwnFile(sourceFile, compilerOptions) { + if (!isDeclarationFile(sourceFile)) { + if ((isExternalModule(sourceFile) || !compilerOptions.out) && !ts.fileExtensionIs(sourceFile.fileName, ".js")) { + return true; + } + return false; + } + return false; + } + ts.shouldEmitToOwnFile = shouldEmitToOwnFile; + function getAllAccessorDeclarations(declarations, accessor) { + var firstAccessor; + var secondAccessor; + var getAccessor; + var setAccessor; + if (hasDynamicName(accessor)) { + firstAccessor = accessor; + if (accessor.kind === 136) { + getAccessor = accessor; + } + else if (accessor.kind === 137) { + setAccessor = accessor; + } + else { + ts.Debug.fail("Accessor has wrong kind"); + } + } + else { + ts.forEach(declarations, function (member) { + if ((member.kind === 136 || member.kind === 137) + && (member.flags & 128) === (accessor.flags & 128)) { + var memberName = getPropertyNameForPropertyNameNode(member.name); + var accessorName = getPropertyNameForPropertyNameNode(accessor.name); + if (memberName === accessorName) { + if (!firstAccessor) { + firstAccessor = member; + } + else if (!secondAccessor) { + secondAccessor = member; + } + if (member.kind === 136 && !getAccessor) { + getAccessor = member; + } + if (member.kind === 137 && !setAccessor) { + setAccessor = member; + } + } + } + }); + } + return { + firstAccessor: firstAccessor, + secondAccessor: secondAccessor, + getAccessor: getAccessor, + setAccessor: setAccessor + }; + } + ts.getAllAccessorDeclarations = getAllAccessorDeclarations; + function emitNewLineBeforeLeadingComments(currentSourceFile, writer, node, leadingComments) { + if (leadingComments && leadingComments.length && node.pos !== leadingComments[0].pos && + getLineOfLocalPosition(currentSourceFile, node.pos) !== getLineOfLocalPosition(currentSourceFile, leadingComments[0].pos)) { + writer.writeLine(); + } + } + ts.emitNewLineBeforeLeadingComments = emitNewLineBeforeLeadingComments; + function emitComments(currentSourceFile, writer, comments, trailingSeparator, newLine, writeComment) { + var emitLeadingSpace = !trailingSeparator; + ts.forEach(comments, function (comment) { + if (emitLeadingSpace) { + writer.write(" "); + emitLeadingSpace = false; + } + writeComment(currentSourceFile, writer, comment, newLine); + if (comment.hasTrailingNewLine) { + writer.writeLine(); + } + else if (trailingSeparator) { + writer.write(" "); + } + else { + emitLeadingSpace = true; + } + }); + } + ts.emitComments = emitComments; + function writeCommentRange(currentSourceFile, writer, comment, newLine) { + if (currentSourceFile.text.charCodeAt(comment.pos + 1) === 42) { + var firstCommentLineAndCharacter = ts.getLineAndCharacterOfPosition(currentSourceFile, comment.pos); + var lineCount = ts.getLineStarts(currentSourceFile).length; + var firstCommentLineIndent; + for (var pos = comment.pos, currentLine = firstCommentLineAndCharacter.line; pos < comment.end; currentLine++) { + var nextLineStart = (currentLine + 1) === lineCount + ? currentSourceFile.text.length + 1 + : getStartPositionOfLine(currentLine + 1, currentSourceFile); + if (pos !== comment.pos) { + if (firstCommentLineIndent === undefined) { + firstCommentLineIndent = calculateIndent(getStartPositionOfLine(firstCommentLineAndCharacter.line, currentSourceFile), comment.pos); + } + var currentWriterIndentSpacing = writer.getIndent() * getIndentSize(); + var spacesToEmit = currentWriterIndentSpacing - firstCommentLineIndent + calculateIndent(pos, nextLineStart); + if (spacesToEmit > 0) { + var numberOfSingleSpacesToEmit = spacesToEmit % getIndentSize(); + var indentSizeSpaceString = getIndentString((spacesToEmit - numberOfSingleSpacesToEmit) / getIndentSize()); + writer.rawWrite(indentSizeSpaceString); + while (numberOfSingleSpacesToEmit) { + writer.rawWrite(" "); + numberOfSingleSpacesToEmit--; + } + } + else { + writer.rawWrite(""); + } + } + writeTrimmedCurrentLine(pos, nextLineStart); + pos = nextLineStart; + } + } + else { + writer.write(currentSourceFile.text.substring(comment.pos, comment.end)); + } + function writeTrimmedCurrentLine(pos, nextLineStart) { + var end = Math.min(comment.end, nextLineStart - 1); + var currentLineText = currentSourceFile.text.substring(pos, end).replace(/^\s+|\s+$/g, ''); + if (currentLineText) { + writer.write(currentLineText); + if (end !== comment.end) { + writer.writeLine(); + } + } + else { + writer.writeLiteral(newLine); + } + } + function calculateIndent(pos, end) { + var currentLineIndent = 0; + for (; pos < end && ts.isWhiteSpace(currentSourceFile.text.charCodeAt(pos)); pos++) { + if (currentSourceFile.text.charCodeAt(pos) === 9) { + currentLineIndent += getIndentSize() - (currentLineIndent % getIndentSize()); + } + else { + currentLineIndent++; + } + } + return currentLineIndent; + } + } + ts.writeCommentRange = writeCommentRange; + function modifierToFlag(token) { + switch (token) { + case 109: return 128; + case 108: return 16; + case 107: return 64; + case 106: return 32; + case 78: return 1; + case 115: return 2; + case 70: return 8192; + case 73: return 256; + } + return 0; + } + ts.modifierToFlag = modifierToFlag; + function isLeftHandSideExpression(expr) { + if (expr) { + switch (expr.kind) { + case 155: + case 156: + case 158: + case 157: + case 159: + case 153: + case 161: + case 154: + case 174: + case 162: + case 65: + case 9: + case 7: + case 8: + case 10: + case 171: + case 80: + case 89: + case 93: + case 95: + case 91: + return true; + } + } + return false; + } + ts.isLeftHandSideExpression = isLeftHandSideExpression; + function isAssignmentOperator(token) { + return token >= 53 && token <= 64; + } + ts.isAssignmentOperator = isAssignmentOperator; + function isSupportedHeritageClauseElement(node) { + return isSupportedHeritageClauseElementExpression(node.expression); + } + ts.isSupportedHeritageClauseElement = isSupportedHeritageClauseElement; + function isSupportedHeritageClauseElementExpression(node) { + if (node.kind === 65) { + return true; + } + else if (node.kind === 155) { + return isSupportedHeritageClauseElementExpression(node.expression); + } + else { + return false; + } + } + function isRightSideOfQualifiedNameOrPropertyAccess(node) { + return (node.parent.kind === 126 && node.parent.right === node) || + (node.parent.kind === 155 && node.parent.name === node); + } + ts.isRightSideOfQualifiedNameOrPropertyAccess = isRightSideOfQualifiedNameOrPropertyAccess; + function getLocalSymbolForExportDefault(symbol) { + return symbol && symbol.valueDeclaration && (symbol.valueDeclaration.flags & 256) ? symbol.valueDeclaration.localSymbol : undefined; + } + ts.getLocalSymbolForExportDefault = getLocalSymbolForExportDefault; +})(ts || (ts = {})); +var ts; +(function (ts) { + function getDefaultLibFileName(options) { + return options.target === 2 ? "lib.es6.d.ts" : "lib.d.ts"; + } + ts.getDefaultLibFileName = getDefaultLibFileName; + function textSpanEnd(span) { + return span.start + span.length; + } + ts.textSpanEnd = textSpanEnd; + function textSpanIsEmpty(span) { + return span.length === 0; + } + ts.textSpanIsEmpty = textSpanIsEmpty; + function textSpanContainsPosition(span, position) { + return position >= span.start && position < textSpanEnd(span); + } + ts.textSpanContainsPosition = textSpanContainsPosition; + function textSpanContainsTextSpan(span, other) { + return other.start >= span.start && textSpanEnd(other) <= textSpanEnd(span); + } + ts.textSpanContainsTextSpan = textSpanContainsTextSpan; + function textSpanOverlapsWith(span, other) { + var overlapStart = Math.max(span.start, other.start); + var overlapEnd = Math.min(textSpanEnd(span), textSpanEnd(other)); + return overlapStart < overlapEnd; + } + ts.textSpanOverlapsWith = textSpanOverlapsWith; + function textSpanOverlap(span1, span2) { + var overlapStart = Math.max(span1.start, span2.start); + var overlapEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2)); + if (overlapStart < overlapEnd) { + return createTextSpanFromBounds(overlapStart, overlapEnd); + } + return undefined; + } + ts.textSpanOverlap = textSpanOverlap; + function textSpanIntersectsWithTextSpan(span, other) { + return other.start <= textSpanEnd(span) && textSpanEnd(other) >= span.start; + } + ts.textSpanIntersectsWithTextSpan = textSpanIntersectsWithTextSpan; + function textSpanIntersectsWith(span, start, length) { + var end = start + length; + return start <= textSpanEnd(span) && end >= span.start; + } + ts.textSpanIntersectsWith = textSpanIntersectsWith; + function textSpanIntersectsWithPosition(span, position) { + return position <= textSpanEnd(span) && position >= span.start; + } + ts.textSpanIntersectsWithPosition = textSpanIntersectsWithPosition; + function textSpanIntersection(span1, span2) { + var intersectStart = Math.max(span1.start, span2.start); + var intersectEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2)); + if (intersectStart <= intersectEnd) { + return createTextSpanFromBounds(intersectStart, intersectEnd); + } + return undefined; + } + ts.textSpanIntersection = textSpanIntersection; + function createTextSpan(start, length) { + if (start < 0) { + throw new Error("start < 0"); + } + if (length < 0) { + throw new Error("length < 0"); + } + return { start: start, length: length }; + } + ts.createTextSpan = createTextSpan; + function createTextSpanFromBounds(start, end) { + return createTextSpan(start, end - start); + } + ts.createTextSpanFromBounds = createTextSpanFromBounds; + function textChangeRangeNewSpan(range) { + return createTextSpan(range.span.start, range.newLength); + } + ts.textChangeRangeNewSpan = textChangeRangeNewSpan; + function textChangeRangeIsUnchanged(range) { + return textSpanIsEmpty(range.span) && range.newLength === 0; + } + ts.textChangeRangeIsUnchanged = textChangeRangeIsUnchanged; + function createTextChangeRange(span, newLength) { + if (newLength < 0) { + throw new Error("newLength < 0"); + } + return { span: span, newLength: newLength }; + } + ts.createTextChangeRange = createTextChangeRange; + ts.unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0); + function collapseTextChangeRangesAcrossMultipleVersions(changes) { + if (changes.length === 0) { + return ts.unchangedTextChangeRange; + } + if (changes.length === 1) { + return changes[0]; + } + var change0 = changes[0]; + var oldStartN = change0.span.start; + var oldEndN = textSpanEnd(change0.span); + var newEndN = oldStartN + change0.newLength; + for (var i = 1; i < changes.length; i++) { + var nextChange = changes[i]; + var oldStart1 = oldStartN; + var oldEnd1 = oldEndN; + var newEnd1 = newEndN; + var oldStart2 = nextChange.span.start; + var oldEnd2 = textSpanEnd(nextChange.span); + var newEnd2 = oldStart2 + nextChange.newLength; + oldStartN = Math.min(oldStart1, oldStart2); + oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)); + newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)); + } + return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), newEndN - oldStartN); + } + ts.collapseTextChangeRangesAcrossMultipleVersions = collapseTextChangeRangesAcrossMultipleVersions; +})(ts || (ts = {})); diff --git a/dist/typescript/makeTypeScriptGlobal.js b/dist/typescript/makeTypeScriptGlobal.js new file mode 100644 index 000000000..d7f70695d --- /dev/null +++ b/dist/typescript/makeTypeScriptGlobal.js @@ -0,0 +1,50 @@ +var servicesFiles = [ + "../compiler/core.ts", + "../compiler/sys.ts", + "../compiler/types.ts", + "../compiler/scanner.ts", + "../compiler/parser.ts", + "../compiler/utilities.ts", + "../compiler/binder.ts", + "../compiler/checker.ts", + "../compiler/emitter.ts", + "../compiler/program.ts", + "../compiler/diagnosticInformationMap.generated.ts", + "../compiler/commandLineParser.ts", + "breakpoints.ts", + "navigationBar.ts", + "outliningElementsCollector.ts", + "services.ts", + "shims.ts", + "signatureHelp.ts", + "utilities.ts", + "formatting/formatting.ts", + "formatting/formattingContext.ts", + "formatting/formattingRequestKind.ts", + "formatting/formattingScanner.ts", + "formatting/references.ts", + "formatting/rule.ts", + "formatting/ruleAction.ts", + "formatting/ruleDescriptor.ts", + "formatting/ruleFlag.ts", + "formatting/ruleOperation.ts", + "formatting/ruleOperationContext.ts", + "formatting/rules.ts", + "formatting/rulesMap.ts", + "formatting/rulesProvider.ts", + "formatting/smartIndenter.ts", + "formatting/tokenRange.ts" +]; +var files = servicesFiles.map(function (f) { return ("./services/" + f.replace('.ts', '.js')); }); +var vm = require('vm'); +var fs = require('fs'); +var path = require('path'); +function makeTsGlobal() { + var sandbox = { ts: {} }; + vm.createContext(sandbox); + files.forEach(function (f) { + vm.runInContext(fs.readFileSync(path.resolve(__dirname, f)).toString(), sandbox); + }); + global.ts = sandbox.ts; +} +exports.makeTsGlobal = makeTsGlobal; diff --git a/dist/typescript/readme.js b/dist/typescript/readme.js new file mode 100644 index 000000000..e69de29bb diff --git a/dist/typescript/services/breakpoints.js b/dist/typescript/services/breakpoints.js new file mode 100644 index 000000000..e21105b83 --- /dev/null +++ b/dist/typescript/services/breakpoints.js @@ -0,0 +1,364 @@ +// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. +// See LICENSE.txt in the project root for complete license information. +/// +var ts; +(function (ts) { + var BreakpointResolver; + (function (BreakpointResolver) { + function spanInSourceFileAtLocation(sourceFile, position) { + if (sourceFile.flags & 2048) { + return undefined; + } + var tokenAtLocation = ts.getTokenAtPosition(sourceFile, position); + var lineOfPosition = sourceFile.getLineAndCharacterOfPosition(position).line; + if (sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getStart()).line > lineOfPosition) { + tokenAtLocation = ts.findPrecedingToken(tokenAtLocation.pos, sourceFile); + if (!tokenAtLocation || sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getEnd()).line !== lineOfPosition) { + return undefined; + } + } + if (ts.isInAmbientContext(tokenAtLocation)) { + return undefined; + } + return spanInNode(tokenAtLocation); + function textSpan(startNode, endNode) { + return ts.createTextSpanFromBounds(startNode.getStart(), (endNode || startNode).getEnd()); + } + function spanInNodeIfStartsOnSameLine(node, otherwiseOnNode) { + if (node && lineOfPosition === sourceFile.getLineAndCharacterOfPosition(node.getStart()).line) { + return spanInNode(node); + } + return spanInNode(otherwiseOnNode); + } + function spanInPreviousNode(node) { + return spanInNode(ts.findPrecedingToken(node.pos, sourceFile)); + } + function spanInNextNode(node) { + return spanInNode(ts.findNextToken(node, node.parent)); + } + function spanInNode(node) { + if (node) { + if (ts.isExpression(node)) { + if (node.parent.kind === 184) { + return spanInPreviousNode(node); + } + if (node.parent.kind === 186) { + return textSpan(node); + } + if (node.parent.kind === 169 && node.parent.operatorToken.kind === 23) { + return textSpan(node); + } + if (node.parent.kind == 163 && node.parent.body == node) { + return textSpan(node); + } + } + switch (node.kind) { + case 180: + return spanInVariableDeclaration(node.declarationList.declarations[0]); + case 198: + case 132: + case 131: + return spanInVariableDeclaration(node); + case 129: + return spanInParameterDeclaration(node); + case 200: + case 134: + case 133: + case 136: + case 137: + case 135: + case 162: + case 163: + return spanInFunctionDeclaration(node); + case 179: + if (ts.isFunctionBlock(node)) { + return spanInFunctionBlock(node); + } + case 206: + return spanInBlock(node); + case 223: + return spanInBlock(node.block); + case 182: + return textSpan(node.expression); + case 191: + return textSpan(node.getChildAt(0), node.expression); + case 185: + return textSpan(node, ts.findNextToken(node.expression, node)); + case 184: + return spanInNode(node.statement); + case 197: + return textSpan(node.getChildAt(0)); + case 183: + return textSpan(node, ts.findNextToken(node.expression, node)); + case 194: + return spanInNode(node.statement); + case 190: + case 189: + return textSpan(node.getChildAt(0), node.label); + case 186: + return spanInForStatement(node); + case 187: + case 188: + return textSpan(node, ts.findNextToken(node.expression, node)); + case 193: + return textSpan(node, ts.findNextToken(node.expression, node)); + case 220: + case 221: + return spanInNode(node.statements[0]); + case 196: + return spanInBlock(node.tryBlock); + case 195: + return textSpan(node, node.expression); + case 214: + return textSpan(node, node.expression); + case 208: + return textSpan(node, node.moduleReference); + case 209: + return textSpan(node, node.moduleSpecifier); + case 215: + return textSpan(node, node.moduleSpecifier); + case 205: + if (ts.getModuleInstanceState(node) !== 1) { + return undefined; + } + case 201: + case 204: + case 226: + case 157: + case 158: + return textSpan(node); + case 192: + return spanInNode(node.statement); + case 202: + case 203: + return undefined; + case 22: + case 1: + return spanInNodeIfStartsOnSameLine(ts.findPrecedingToken(node.pos, sourceFile)); + case 23: + return spanInPreviousNode(node); + case 14: + return spanInOpenBraceToken(node); + case 15: + return spanInCloseBraceToken(node); + case 16: + return spanInOpenParenToken(node); + case 17: + return spanInCloseParenToken(node); + case 51: + return spanInColonToken(node); + case 25: + case 24: + return spanInGreaterThanOrLessThanToken(node); + case 100: + return spanInWhileKeyword(node); + case 76: + case 68: + case 81: + return spanInNextNode(node); + default: + if (node.parent.kind === 224 && node.parent.name === node) { + return spanInNode(node.parent.initializer); + } + if (node.parent.kind === 160 && node.parent.type === node) { + return spanInNode(node.parent.expression); + } + if (ts.isFunctionLike(node.parent) && node.parent.type === node) { + return spanInPreviousNode(node); + } + return spanInNode(node.parent); + } + } + function spanInVariableDeclaration(variableDeclaration) { + if (variableDeclaration.parent.parent.kind === 187 || + variableDeclaration.parent.parent.kind === 188) { + return spanInNode(variableDeclaration.parent.parent); + } + var isParentVariableStatement = variableDeclaration.parent.parent.kind === 180; + var isDeclarationOfForStatement = variableDeclaration.parent.parent.kind === 186 && ts.contains(variableDeclaration.parent.parent.initializer.declarations, variableDeclaration); + var declarations = isParentVariableStatement + ? variableDeclaration.parent.parent.declarationList.declarations + : isDeclarationOfForStatement + ? variableDeclaration.parent.parent.initializer.declarations + : undefined; + if (variableDeclaration.initializer || (variableDeclaration.flags & 1)) { + if (declarations && declarations[0] === variableDeclaration) { + if (isParentVariableStatement) { + return textSpan(variableDeclaration.parent, variableDeclaration); + } + else { + ts.Debug.assert(isDeclarationOfForStatement); + return textSpan(ts.findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent), variableDeclaration); + } + } + else { + return textSpan(variableDeclaration); + } + } + else if (declarations && declarations[0] !== variableDeclaration) { + var indexOfCurrentDeclaration = ts.indexOf(declarations, variableDeclaration); + return spanInVariableDeclaration(declarations[indexOfCurrentDeclaration - 1]); + } + } + function canHaveSpanInParameterDeclaration(parameter) { + return !!parameter.initializer || parameter.dotDotDotToken !== undefined || + !!(parameter.flags & 16) || !!(parameter.flags & 32); + } + function spanInParameterDeclaration(parameter) { + if (canHaveSpanInParameterDeclaration(parameter)) { + return textSpan(parameter); + } + else { + var functionDeclaration = parameter.parent; + var indexOfParameter = ts.indexOf(functionDeclaration.parameters, parameter); + if (indexOfParameter) { + return spanInParameterDeclaration(functionDeclaration.parameters[indexOfParameter - 1]); + } + else { + return spanInNode(functionDeclaration.body); + } + } + } + function canFunctionHaveSpanInWholeDeclaration(functionDeclaration) { + return !!(functionDeclaration.flags & 1) || + (functionDeclaration.parent.kind === 201 && functionDeclaration.kind !== 135); + } + function spanInFunctionDeclaration(functionDeclaration) { + if (!functionDeclaration.body) { + return undefined; + } + if (canFunctionHaveSpanInWholeDeclaration(functionDeclaration)) { + return textSpan(functionDeclaration); + } + return spanInNode(functionDeclaration.body); + } + function spanInFunctionBlock(block) { + var nodeForSpanInBlock = block.statements.length ? block.statements[0] : block.getLastToken(); + if (canFunctionHaveSpanInWholeDeclaration(block.parent)) { + return spanInNodeIfStartsOnSameLine(block.parent, nodeForSpanInBlock); + } + return spanInNode(nodeForSpanInBlock); + } + function spanInBlock(block) { + switch (block.parent.kind) { + case 205: + if (ts.getModuleInstanceState(block.parent) !== 1) { + return undefined; + } + case 185: + case 183: + case 187: + case 188: + return spanInNodeIfStartsOnSameLine(block.parent, block.statements[0]); + case 186: + return spanInNodeIfStartsOnSameLine(ts.findPrecedingToken(block.pos, sourceFile, block.parent), block.statements[0]); + } + return spanInNode(block.statements[0]); + } + function spanInForStatement(forStatement) { + if (forStatement.initializer) { + if (forStatement.initializer.kind === 199) { + var variableDeclarationList = forStatement.initializer; + if (variableDeclarationList.declarations.length > 0) { + return spanInNode(variableDeclarationList.declarations[0]); + } + } + else { + return spanInNode(forStatement.initializer); + } + } + if (forStatement.condition) { + return textSpan(forStatement.condition); + } + if (forStatement.incrementor) { + return textSpan(forStatement.incrementor); + } + } + function spanInOpenBraceToken(node) { + switch (node.parent.kind) { + case 204: + var enumDeclaration = node.parent; + return spanInNodeIfStartsOnSameLine(ts.findPrecedingToken(node.pos, sourceFile, node.parent), enumDeclaration.members.length ? enumDeclaration.members[0] : enumDeclaration.getLastToken(sourceFile)); + case 201: + var classDeclaration = node.parent; + return spanInNodeIfStartsOnSameLine(ts.findPrecedingToken(node.pos, sourceFile, node.parent), classDeclaration.members.length ? classDeclaration.members[0] : classDeclaration.getLastToken(sourceFile)); + case 207: + return spanInNodeIfStartsOnSameLine(node.parent.parent, node.parent.clauses[0]); + } + return spanInNode(node.parent); + } + function spanInCloseBraceToken(node) { + switch (node.parent.kind) { + case 206: + if (ts.getModuleInstanceState(node.parent.parent) !== 1) { + return undefined; + } + case 204: + case 201: + return textSpan(node); + case 179: + if (ts.isFunctionBlock(node.parent)) { + return textSpan(node); + } + case 223: + return spanInNode(node.parent.statements[node.parent.statements.length - 1]); + ; + case 207: + var caseBlock = node.parent; + var lastClause = caseBlock.clauses[caseBlock.clauses.length - 1]; + if (lastClause) { + return spanInNode(lastClause.statements[lastClause.statements.length - 1]); + } + return undefined; + default: + return spanInNode(node.parent); + } + } + function spanInOpenParenToken(node) { + if (node.parent.kind === 184) { + return spanInPreviousNode(node); + } + return spanInNode(node.parent); + } + function spanInCloseParenToken(node) { + switch (node.parent.kind) { + case 162: + case 200: + case 163: + case 134: + case 133: + case 136: + case 137: + case 135: + case 185: + case 184: + case 186: + return spanInPreviousNode(node); + default: + return spanInNode(node.parent); + } + return spanInNode(node.parent); + } + function spanInColonToken(node) { + if (ts.isFunctionLike(node.parent) || node.parent.kind === 224) { + return spanInPreviousNode(node); + } + return spanInNode(node.parent); + } + function spanInGreaterThanOrLessThanToken(node) { + if (node.parent.kind === 160) { + return spanInNode(node.parent.expression); + } + return spanInNode(node.parent); + } + function spanInWhileKeyword(node) { + if (node.parent.kind === 184) { + return textSpan(node, ts.findNextToken(node.parent.expression, node.parent)); + } + return spanInNode(node.parent); + } + } + } + BreakpointResolver.spanInSourceFileAtLocation = spanInSourceFileAtLocation; + })(BreakpointResolver = ts.BreakpointResolver || (ts.BreakpointResolver = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/formatting.js b/dist/typescript/services/formatting/formatting.js new file mode 100644 index 000000000..bb8fb661c --- /dev/null +++ b/dist/typescript/services/formatting/formatting.js @@ -0,0 +1,747 @@ +/// +/// +/// +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var Constants; + (function (Constants) { + Constants[Constants["Unknown"] = -1] = "Unknown"; + })(Constants || (Constants = {})); + function formatOnEnter(position, sourceFile, rulesProvider, options) { + var line = sourceFile.getLineAndCharacterOfPosition(position).line; + if (line === 0) { + return []; + } + var span = { + pos: ts.getStartPositionOfLine(line - 1, sourceFile), + end: ts.getEndLinePosition(line, sourceFile) + 1 + }; + return formatSpan(span, sourceFile, options, rulesProvider, 2); + } + formatting.formatOnEnter = formatOnEnter; + function formatOnSemicolon(position, sourceFile, rulesProvider, options) { + return formatOutermostParent(position, 22, sourceFile, options, rulesProvider, 3); + } + formatting.formatOnSemicolon = formatOnSemicolon; + function formatOnClosingCurly(position, sourceFile, rulesProvider, options) { + return formatOutermostParent(position, 15, sourceFile, options, rulesProvider, 4); + } + formatting.formatOnClosingCurly = formatOnClosingCurly; + function formatDocument(sourceFile, rulesProvider, options) { + var span = { + pos: 0, + end: sourceFile.text.length + }; + return formatSpan(span, sourceFile, options, rulesProvider, 0); + } + formatting.formatDocument = formatDocument; + function formatSelection(start, end, sourceFile, rulesProvider, options) { + var span = { + pos: ts.getLineStartPositionForPosition(start, sourceFile), + end: end + }; + return formatSpan(span, sourceFile, options, rulesProvider, 1); + } + formatting.formatSelection = formatSelection; + function formatOutermostParent(position, expectedLastToken, sourceFile, options, rulesProvider, requestKind) { + var parent = findOutermostParent(position, expectedLastToken, sourceFile); + if (!parent) { + return []; + } + var span = { + pos: ts.getLineStartPositionForPosition(parent.getStart(sourceFile), sourceFile), + end: parent.end + }; + return formatSpan(span, sourceFile, options, rulesProvider, requestKind); + } + function findOutermostParent(position, expectedTokenKind, sourceFile) { + var precedingToken = ts.findPrecedingToken(position, sourceFile); + if (!precedingToken || + precedingToken.kind !== expectedTokenKind || + position !== precedingToken.getEnd()) { + return undefined; + } + var current = precedingToken; + while (current && + current.parent && + current.parent.end === precedingToken.end && + !isListElement(current.parent, current)) { + current = current.parent; + } + return current; + } + function isListElement(parent, node) { + switch (parent.kind) { + case 201: + case 202: + return ts.rangeContainsRange(parent.members, node); + case 205: + var body = parent.body; + return body && body.kind === 179 && ts.rangeContainsRange(body.statements, node); + case 227: + case 179: + case 206: + return ts.rangeContainsRange(parent.statements, node); + case 223: + return ts.rangeContainsRange(parent.block.statements, node); + } + return false; + } + function findEnclosingNode(range, sourceFile) { + return find(sourceFile); + function find(n) { + var candidate = ts.forEachChild(n, function (c) { return ts.startEndContainsRange(c.getStart(sourceFile), c.end, range) && c; }); + if (candidate) { + var result = find(candidate); + if (result) { + return result; + } + } + return n; + } + } + function prepareRangeContainsErrorFunction(errors, originalRange) { + if (!errors.length) { + return rangeHasNoErrors; + } + var sorted = errors + .filter(function (d) { return ts.rangeOverlapsWithStartEnd(originalRange, d.start, d.start + d.length); }) + .sort(function (e1, e2) { return e1.start - e2.start; }); + if (!sorted.length) { + return rangeHasNoErrors; + } + var index = 0; + return function (r) { + while (true) { + if (index >= sorted.length) { + return false; + } + var error = sorted[index]; + if (r.end <= error.start) { + return false; + } + if (ts.startEndOverlapsWithStartEnd(r.pos, r.end, error.start, error.start + error.length)) { + return true; + } + index++; + } + }; + function rangeHasNoErrors(r) { + return false; + } + } + function getScanStartPosition(enclosingNode, originalRange, sourceFile) { + var start = enclosingNode.getStart(sourceFile); + if (start === originalRange.pos && enclosingNode.end === originalRange.end) { + return start; + } + var precedingToken = ts.findPrecedingToken(originalRange.pos, sourceFile); + if (!precedingToken) { + return enclosingNode.pos; + } + if (precedingToken.end >= originalRange.pos) { + return enclosingNode.pos; + } + return precedingToken.end; + } + function getOwnOrInheritedDelta(n, options, sourceFile) { + var previousLine = -1; + var childKind = 0; + while (n) { + var line = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)).line; + if (previousLine !== -1 && line !== previousLine) { + break; + } + if (formatting.SmartIndenter.shouldIndentChildNode(n.kind, childKind)) { + return options.IndentSize; + } + previousLine = line; + childKind = n.kind; + n = n.parent; + } + return 0; + } + function formatSpan(originalRange, sourceFile, options, rulesProvider, requestKind) { + var rangeContainsError = prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange); + var formattingContext = new formatting.FormattingContext(sourceFile, requestKind); + var enclosingNode = findEnclosingNode(originalRange, sourceFile); + var formattingScanner = formatting.getFormattingScanner(sourceFile, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end); + var initialIndentation = formatting.SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options); + var previousRangeHasError; + var previousRange; + var previousParent; + var previousRangeStartLine; + var edits = []; + formattingScanner.advance(); + if (formattingScanner.isOnToken()) { + var startLine = sourceFile.getLineAndCharacterOfPosition(enclosingNode.getStart(sourceFile)).line; + var undecoratedStartLine = startLine; + if (enclosingNode.decorators) { + undecoratedStartLine = sourceFile.getLineAndCharacterOfPosition(ts.getNonDecoratorTokenPosOfNode(enclosingNode, sourceFile)).line; + } + var delta = getOwnOrInheritedDelta(enclosingNode, options, sourceFile); + processNode(enclosingNode, enclosingNode, startLine, undecoratedStartLine, initialIndentation, delta); + } + formattingScanner.close(); + return edits; + function tryComputeIndentationForListItem(startPos, endPos, parentStartLine, range, inheritedIndentation) { + if (ts.rangeOverlapsWithStartEnd(range, startPos, endPos)) { + if (inheritedIndentation !== -1) { + return inheritedIndentation; + } + } + else { + var startLine = sourceFile.getLineAndCharacterOfPosition(startPos).line; + var startLinePosition = ts.getLineStartPositionForPosition(startPos, sourceFile); + var column = formatting.SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, startPos, sourceFile, options); + if (startLine !== parentStartLine || startPos === column) { + return column; + } + } + return -1; + } + function computeIndentation(node, startLine, inheritedIndentation, parent, parentDynamicIndentation, effectiveParentStartLine) { + var indentation = inheritedIndentation; + if (indentation === -1) { + if (isSomeBlock(node.kind)) { + if (isSomeBlock(parent.kind) || + parent.kind === 227 || + parent.kind === 220 || + parent.kind === 221) { + indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta(); + } + else { + indentation = parentDynamicIndentation.getIndentation(); + } + } + else { + if (formatting.SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile)) { + indentation = parentDynamicIndentation.getIndentation(); + } + else { + indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta(); + } + } + } + var delta = formatting.SmartIndenter.shouldIndentChildNode(node.kind, 0) ? options.IndentSize : 0; + if (effectiveParentStartLine === startLine) { + indentation = parentDynamicIndentation.getIndentation(); + delta = Math.min(options.IndentSize, parentDynamicIndentation.getDelta() + delta); + } + return { + indentation: indentation, + delta: delta + }; + } + function getFirstNonDecoratorTokenOfNode(node) { + if (node.modifiers && node.modifiers.length) { + return node.modifiers[0].kind; + } + switch (node.kind) { + case 201: return 69; + case 202: return 103; + case 200: return 83; + case 204: return 204; + case 136: return 116; + case 137: return 120; + case 134: + if (node.asteriskToken) { + return 35; + } + case 132: + case 129: + return node.name.kind; + } + } + function getDynamicIndentation(node, nodeStartLine, indentation, delta) { + return { + getIndentationForComment: function (kind) { + switch (kind) { + case 15: + case 19: + return indentation + delta; + } + return indentation; + }, + getIndentationForToken: function (line, kind) { + if (nodeStartLine !== line && node.decorators) { + if (kind === getFirstNonDecoratorTokenOfNode(node)) { + return indentation; + } + } + switch (kind) { + case 14: + case 15: + case 18: + case 19: + case 76: + case 100: + case 52: + return indentation; + default: + return nodeStartLine !== line ? indentation + delta : indentation; + } + }, + getIndentation: function () { return indentation; }, + getDelta: function () { return delta; }, + recomputeIndentation: function (lineAdded) { + if (node.parent && formatting.SmartIndenter.shouldIndentChildNode(node.parent.kind, node.kind)) { + if (lineAdded) { + indentation += options.IndentSize; + } + else { + indentation -= options.IndentSize; + } + if (formatting.SmartIndenter.shouldIndentChildNode(node.kind, 0)) { + delta = options.IndentSize; + } + else { + delta = 0; + } + } + }, + }; + } + function processNode(node, contextNode, nodeStartLine, undecoratedNodeStartLine, indentation, delta) { + if (!ts.rangeOverlapsWithStartEnd(originalRange, node.getStart(sourceFile), node.getEnd())) { + return; + } + var nodeDynamicIndentation = getDynamicIndentation(node, nodeStartLine, indentation, delta); + var childContextNode = contextNode; + ts.forEachChild(node, function (child) { + processChildNode(child, -1, node, nodeDynamicIndentation, nodeStartLine, undecoratedNodeStartLine, false); + }, function (nodes) { + processChildNodes(nodes, node, nodeStartLine, nodeDynamicIndentation); + }); + while (formattingScanner.isOnToken()) { + var tokenInfo = formattingScanner.readTokenInfo(node); + if (tokenInfo.token.end > node.end) { + break; + } + consumeTokenAndAdvanceScanner(tokenInfo, node, nodeDynamicIndentation); + } + function processChildNode(child, inheritedIndentation, parent, parentDynamicIndentation, parentStartLine, undecoratedParentStartLine, isListItem) { + var childStartPos = child.getStart(sourceFile); + var childStartLine = sourceFile.getLineAndCharacterOfPosition(childStartPos).line; + var undecoratedChildStartLine = childStartLine; + if (child.decorators) { + undecoratedChildStartLine = sourceFile.getLineAndCharacterOfPosition(ts.getNonDecoratorTokenPosOfNode(child, sourceFile)).line; + } + var childIndentationAmount = -1; + if (isListItem) { + childIndentationAmount = tryComputeIndentationForListItem(childStartPos, child.end, parentStartLine, originalRange, inheritedIndentation); + if (childIndentationAmount !== -1) { + inheritedIndentation = childIndentationAmount; + } + } + if (!ts.rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) { + return inheritedIndentation; + } + if (child.getFullWidth() === 0) { + return inheritedIndentation; + } + while (formattingScanner.isOnToken()) { + var tokenInfo = formattingScanner.readTokenInfo(node); + if (tokenInfo.token.end > childStartPos) { + break; + } + consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation); + } + if (!formattingScanner.isOnToken()) { + return inheritedIndentation; + } + if (ts.isToken(child)) { + var tokenInfo = formattingScanner.readTokenInfo(child); + ts.Debug.assert(tokenInfo.token.end === child.end); + consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation); + return inheritedIndentation; + } + var effectiveParentStartLine = child.kind === 130 ? childStartLine : undecoratedParentStartLine; + var childIndentation = computeIndentation(child, childStartLine, childIndentationAmount, node, parentDynamicIndentation, effectiveParentStartLine); + processNode(child, childContextNode, childStartLine, undecoratedChildStartLine, childIndentation.indentation, childIndentation.delta); + childContextNode = node; + return inheritedIndentation; + } + function processChildNodes(nodes, parent, parentStartLine, parentDynamicIndentation) { + var listStartToken = getOpenTokenForList(parent, nodes); + var listEndToken = getCloseTokenForOpenToken(listStartToken); + var listDynamicIndentation = parentDynamicIndentation; + var startLine = parentStartLine; + if (listStartToken !== 0) { + while (formattingScanner.isOnToken()) { + var tokenInfo = formattingScanner.readTokenInfo(parent); + if (tokenInfo.token.end > nodes.pos) { + break; + } + else if (tokenInfo.token.kind === listStartToken) { + startLine = sourceFile.getLineAndCharacterOfPosition(tokenInfo.token.pos).line; + var indentation_1 = computeIndentation(tokenInfo.token, startLine, -1, parent, parentDynamicIndentation, startLine); + listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation_1.indentation, indentation_1.delta); + consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation); + } + else { + consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation); + } + } + } + var inheritedIndentation = -1; + for (var _i = 0; _i < nodes.length; _i++) { + var child = nodes[_i]; + inheritedIndentation = processChildNode(child, inheritedIndentation, node, listDynamicIndentation, startLine, startLine, true); + } + if (listEndToken !== 0) { + if (formattingScanner.isOnToken()) { + var tokenInfo = formattingScanner.readTokenInfo(parent); + if (tokenInfo.token.kind === listEndToken && ts.rangeContainsRange(parent, tokenInfo.token)) { + consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation); + } + } + } + } + function consumeTokenAndAdvanceScanner(currentTokenInfo, parent, dynamicIndentation) { + ts.Debug.assert(ts.rangeContainsRange(parent, currentTokenInfo.token)); + var lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine(); + var indentToken = false; + if (currentTokenInfo.leadingTrivia) { + processTrivia(currentTokenInfo.leadingTrivia, parent, childContextNode, dynamicIndentation); + } + var lineAdded; + var isTokenInRange = ts.rangeContainsRange(originalRange, currentTokenInfo.token); + var tokenStart = sourceFile.getLineAndCharacterOfPosition(currentTokenInfo.token.pos); + if (isTokenInRange) { + var rangeHasError = rangeContainsError(currentTokenInfo.token); + var prevStartLine = previousRangeStartLine; + lineAdded = processRange(currentTokenInfo.token, tokenStart, parent, childContextNode, dynamicIndentation); + if (rangeHasError) { + indentToken = false; + } + else { + if (lineAdded !== undefined) { + indentToken = lineAdded; + } + else { + indentToken = lastTriviaWasNewLine && tokenStart.line !== prevStartLine; + } + } + } + if (currentTokenInfo.trailingTrivia) { + processTrivia(currentTokenInfo.trailingTrivia, parent, childContextNode, dynamicIndentation); + } + if (indentToken) { + var indentNextTokenOrTrivia = true; + if (currentTokenInfo.leadingTrivia) { + for (var _i = 0, _a = currentTokenInfo.leadingTrivia; _i < _a.length; _i++) { + var triviaItem = _a[_i]; + if (!ts.rangeContainsRange(originalRange, triviaItem)) { + continue; + } + var triviaStartLine = sourceFile.getLineAndCharacterOfPosition(triviaItem.pos).line; + switch (triviaItem.kind) { + case 3: + var commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind); + indentMultilineComment(triviaItem, commentIndentation, !indentNextTokenOrTrivia); + indentNextTokenOrTrivia = false; + break; + case 2: + if (indentNextTokenOrTrivia) { + var commentIndentation_1 = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind); + insertIndentation(triviaItem.pos, commentIndentation_1, false); + indentNextTokenOrTrivia = false; + } + break; + case 4: + indentNextTokenOrTrivia = true; + break; + } + } + } + if (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) { + var tokenIndentation = dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind); + insertIndentation(currentTokenInfo.token.pos, tokenIndentation, lineAdded); + } + } + formattingScanner.advance(); + childContextNode = parent; + } + } + function processTrivia(trivia, parent, contextNode, dynamicIndentation) { + for (var _i = 0; _i < trivia.length; _i++) { + var triviaItem = trivia[_i]; + if (ts.isComment(triviaItem.kind) && ts.rangeContainsRange(originalRange, triviaItem)) { + var triviaItemStart = sourceFile.getLineAndCharacterOfPosition(triviaItem.pos); + processRange(triviaItem, triviaItemStart, parent, contextNode, dynamicIndentation); + } + } + } + function processRange(range, rangeStart, parent, contextNode, dynamicIndentation) { + var rangeHasError = rangeContainsError(range); + var lineAdded; + if (!rangeHasError && !previousRangeHasError) { + if (!previousRange) { + var originalStart = sourceFile.getLineAndCharacterOfPosition(originalRange.pos); + trimTrailingWhitespacesForLines(originalStart.line, rangeStart.line); + } + else { + lineAdded = + processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, dynamicIndentation); + } + } + previousRange = range; + previousParent = parent; + previousRangeStartLine = rangeStart.line; + previousRangeHasError = rangeHasError; + return lineAdded; + } + function processPair(currentItem, currentStartLine, currentParent, previousItem, previousStartLine, previousParent, contextNode, dynamicIndentation) { + formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode); + var rule = rulesProvider.getRulesMap().GetRule(formattingContext); + var trimTrailingWhitespaces; + var lineAdded; + if (rule) { + applyRuleEdits(rule, previousItem, previousStartLine, currentItem, currentStartLine); + if (rule.Operation.Action & (2 | 8) && currentStartLine !== previousStartLine) { + lineAdded = false; + if (currentParent.getStart(sourceFile) === currentItem.pos) { + dynamicIndentation.recomputeIndentation(false); + } + } + else if (rule.Operation.Action & 4 && currentStartLine === previousStartLine) { + lineAdded = true; + if (currentParent.getStart(sourceFile) === currentItem.pos) { + dynamicIndentation.recomputeIndentation(true); + } + } + trimTrailingWhitespaces = + (rule.Operation.Action & (4 | 2)) && + rule.Flag !== 1; + } + else { + trimTrailingWhitespaces = true; + } + if (currentStartLine !== previousStartLine && trimTrailingWhitespaces) { + trimTrailingWhitespacesForLines(previousStartLine, currentStartLine, previousItem); + } + return lineAdded; + } + function insertIndentation(pos, indentation, lineAdded) { + var indentationString = getIndentationString(indentation, options); + if (lineAdded) { + recordReplace(pos, 0, indentationString); + } + else { + var tokenStart = sourceFile.getLineAndCharacterOfPosition(pos); + if (indentation !== tokenStart.character) { + var startLinePosition = ts.getStartPositionOfLine(tokenStart.line, sourceFile); + recordReplace(startLinePosition, tokenStart.character, indentationString); + } + } + } + function indentMultilineComment(commentRange, indentation, firstLineIsIndented) { + var startLine = sourceFile.getLineAndCharacterOfPosition(commentRange.pos).line; + var endLine = sourceFile.getLineAndCharacterOfPosition(commentRange.end).line; + var parts; + if (startLine === endLine) { + if (!firstLineIsIndented) { + insertIndentation(commentRange.pos, indentation, false); + } + return; + } + else { + parts = []; + var startPos = commentRange.pos; + for (var line = startLine; line < endLine; ++line) { + var endOfLine = ts.getEndLinePosition(line, sourceFile); + parts.push({ pos: startPos, end: endOfLine }); + startPos = ts.getStartPositionOfLine(line + 1, sourceFile); + } + parts.push({ pos: startPos, end: commentRange.end }); + } + var startLinePos = ts.getStartPositionOfLine(startLine, sourceFile); + var nonWhitespaceColumnInFirstPart = formatting.SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(startLinePos, parts[0].pos, sourceFile, options); + if (indentation === nonWhitespaceColumnInFirstPart.column) { + return; + } + var startIndex = 0; + if (firstLineIsIndented) { + startIndex = 1; + startLine++; + } + var delta = indentation - nonWhitespaceColumnInFirstPart.column; + for (var i = startIndex, len = parts.length; i < len; ++i, ++startLine) { + var startLinePos_1 = ts.getStartPositionOfLine(startLine, sourceFile); + var nonWhitespaceCharacterAndColumn = i === 0 + ? nonWhitespaceColumnInFirstPart + : formatting.SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(parts[i].pos, parts[i].end, sourceFile, options); + var newIndentation = nonWhitespaceCharacterAndColumn.column + delta; + if (newIndentation > 0) { + var indentationString = getIndentationString(newIndentation, options); + recordReplace(startLinePos_1, nonWhitespaceCharacterAndColumn.character, indentationString); + } + else { + recordDelete(startLinePos_1, nonWhitespaceCharacterAndColumn.character); + } + } + } + function trimTrailingWhitespacesForLines(line1, line2, range) { + for (var line = line1; line < line2; ++line) { + var lineStartPosition = ts.getStartPositionOfLine(line, sourceFile); + var lineEndPosition = ts.getEndLinePosition(line, sourceFile); + if (range && ts.isComment(range.kind) && range.pos <= lineEndPosition && range.end > lineEndPosition) { + continue; + } + var pos = lineEndPosition; + while (pos >= lineStartPosition && ts.isWhiteSpace(sourceFile.text.charCodeAt(pos))) { + pos--; + } + if (pos !== lineEndPosition) { + ts.Debug.assert(pos === lineStartPosition || !ts.isWhiteSpace(sourceFile.text.charCodeAt(pos))); + recordDelete(pos + 1, lineEndPosition - pos); + } + } + } + function newTextChange(start, len, newText) { + return { span: ts.createTextSpan(start, len), newText: newText }; + } + function recordDelete(start, len) { + if (len) { + edits.push(newTextChange(start, len, "")); + } + } + function recordReplace(start, len, newText) { + if (len || newText) { + edits.push(newTextChange(start, len, newText)); + } + } + function applyRuleEdits(rule, previousRange, previousStartLine, currentRange, currentStartLine) { + var between; + switch (rule.Operation.Action) { + case 1: + return; + case 8: + if (previousRange.end !== currentRange.pos) { + recordDelete(previousRange.end, currentRange.pos - previousRange.end); + } + break; + case 4: + if (rule.Flag !== 1 && previousStartLine !== currentStartLine) { + return; + } + var lineDelta = currentStartLine - previousStartLine; + if (lineDelta !== 1) { + recordReplace(previousRange.end, currentRange.pos - previousRange.end, options.NewLineCharacter); + } + break; + case 2: + if (rule.Flag !== 1 && previousStartLine !== currentStartLine) { + return; + } + var posDelta = currentRange.pos - previousRange.end; + if (posDelta !== 1 || sourceFile.text.charCodeAt(previousRange.end) !== 32) { + recordReplace(previousRange.end, currentRange.pos - previousRange.end, " "); + } + break; + } + } + } + function isSomeBlock(kind) { + switch (kind) { + case 179: + case 206: + return true; + } + return false; + } + function getOpenTokenForList(node, list) { + switch (node.kind) { + case 135: + case 200: + case 162: + case 134: + case 133: + case 163: + if (node.typeParameters === list) { + return 24; + } + else if (node.parameters === list) { + return 16; + } + break; + case 157: + case 158: + if (node.typeArguments === list) { + return 24; + } + else if (node.arguments === list) { + return 16; + } + break; + case 141: + if (node.typeArguments === list) { + return 24; + } + } + return 0; + } + function getCloseTokenForOpenToken(kind) { + switch (kind) { + case 16: + return 17; + case 24: + return 25; + } + return 0; + } + var internedSizes; + var internedTabsIndentation; + var internedSpacesIndentation; + function getIndentationString(indentation, options) { + var resetInternedStrings = !internedSizes || (internedSizes.tabSize !== options.TabSize || internedSizes.indentSize !== options.IndentSize); + if (resetInternedStrings) { + internedSizes = { tabSize: options.TabSize, indentSize: options.IndentSize }; + internedTabsIndentation = internedSpacesIndentation = undefined; + } + if (!options.ConvertTabsToSpaces) { + var tabs = Math.floor(indentation / options.TabSize); + var spaces = indentation - tabs * options.TabSize; + var tabString; + if (!internedTabsIndentation) { + internedTabsIndentation = []; + } + if (internedTabsIndentation[tabs] === undefined) { + internedTabsIndentation[tabs] = tabString = repeat('\t', tabs); + } + else { + tabString = internedTabsIndentation[tabs]; + } + return spaces ? tabString + repeat(" ", spaces) : tabString; + } + else { + var spacesString; + var quotient = Math.floor(indentation / options.IndentSize); + var remainder = indentation % options.IndentSize; + if (!internedSpacesIndentation) { + internedSpacesIndentation = []; + } + if (internedSpacesIndentation[quotient] === undefined) { + spacesString = repeat(" ", options.IndentSize * quotient); + internedSpacesIndentation[quotient] = spacesString; + } + else { + spacesString = internedSpacesIndentation[quotient]; + } + return remainder ? spacesString + repeat(" ", remainder) : spacesString; + } + function repeat(value, count) { + var s = ""; + for (var i = 0; i < count; ++i) { + s += value; + } + return s; + } + } + formatting.getIndentationString = getIndentationString; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/formattingContext.js b/dist/typescript/services/formatting/formattingContext.js new file mode 100644 index 000000000..bd40c24fa --- /dev/null +++ b/dist/typescript/services/formatting/formattingContext.js @@ -0,0 +1,79 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var FormattingContext = (function () { + function FormattingContext(sourceFile, formattingRequestKind) { + this.sourceFile = sourceFile; + this.formattingRequestKind = formattingRequestKind; + } + FormattingContext.prototype.updateContext = function (currentRange, currentTokenParent, nextRange, nextTokenParent, commonParent) { + ts.Debug.assert(currentRange !== undefined, "currentTokenSpan is null"); + ts.Debug.assert(currentTokenParent !== undefined, "currentTokenParent is null"); + ts.Debug.assert(nextRange !== undefined, "nextTokenSpan is null"); + ts.Debug.assert(nextTokenParent !== undefined, "nextTokenParent is null"); + ts.Debug.assert(commonParent !== undefined, "commonParent is null"); + this.currentTokenSpan = currentRange; + this.currentTokenParent = currentTokenParent; + this.nextTokenSpan = nextRange; + this.nextTokenParent = nextTokenParent; + this.contextNode = commonParent; + this.contextNodeAllOnSameLine = undefined; + this.nextNodeAllOnSameLine = undefined; + this.tokensAreOnSameLine = undefined; + this.contextNodeBlockIsOnOneLine = undefined; + this.nextNodeBlockIsOnOneLine = undefined; + }; + FormattingContext.prototype.ContextNodeAllOnSameLine = function () { + if (this.contextNodeAllOnSameLine === undefined) { + this.contextNodeAllOnSameLine = this.NodeIsOnOneLine(this.contextNode); + } + return this.contextNodeAllOnSameLine; + }; + FormattingContext.prototype.NextNodeAllOnSameLine = function () { + if (this.nextNodeAllOnSameLine === undefined) { + this.nextNodeAllOnSameLine = this.NodeIsOnOneLine(this.nextTokenParent); + } + return this.nextNodeAllOnSameLine; + }; + FormattingContext.prototype.TokensAreOnSameLine = function () { + if (this.tokensAreOnSameLine === undefined) { + var startLine = this.sourceFile.getLineAndCharacterOfPosition(this.currentTokenSpan.pos).line; + var endLine = this.sourceFile.getLineAndCharacterOfPosition(this.nextTokenSpan.pos).line; + this.tokensAreOnSameLine = (startLine == endLine); + } + return this.tokensAreOnSameLine; + }; + FormattingContext.prototype.ContextNodeBlockIsOnOneLine = function () { + if (this.contextNodeBlockIsOnOneLine === undefined) { + this.contextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.contextNode); + } + return this.contextNodeBlockIsOnOneLine; + }; + FormattingContext.prototype.NextNodeBlockIsOnOneLine = function () { + if (this.nextNodeBlockIsOnOneLine === undefined) { + this.nextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.nextTokenParent); + } + return this.nextNodeBlockIsOnOneLine; + }; + FormattingContext.prototype.NodeIsOnOneLine = function (node) { + var startLine = this.sourceFile.getLineAndCharacterOfPosition(node.getStart(this.sourceFile)).line; + var endLine = this.sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line; + return startLine == endLine; + }; + FormattingContext.prototype.BlockIsOnOneLine = function (node) { + var openBrace = ts.findChildOfKind(node, 14, this.sourceFile); + var closeBrace = ts.findChildOfKind(node, 15, this.sourceFile); + if (openBrace && closeBrace) { + var startLine = this.sourceFile.getLineAndCharacterOfPosition(openBrace.getEnd()).line; + var endLine = this.sourceFile.getLineAndCharacterOfPosition(closeBrace.getStart(this.sourceFile)).line; + return startLine === endLine; + } + return false; + }; + return FormattingContext; + })(); + formatting.FormattingContext = FormattingContext; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/formattingRequestKind.js b/dist/typescript/services/formatting/formattingRequestKind.js new file mode 100644 index 000000000..1b32c464d --- /dev/null +++ b/dist/typescript/services/formatting/formattingRequestKind.js @@ -0,0 +1,15 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + (function (FormattingRequestKind) { + FormattingRequestKind[FormattingRequestKind["FormatDocument"] = 0] = "FormatDocument"; + FormattingRequestKind[FormattingRequestKind["FormatSelection"] = 1] = "FormatSelection"; + FormattingRequestKind[FormattingRequestKind["FormatOnEnter"] = 2] = "FormatOnEnter"; + FormattingRequestKind[FormattingRequestKind["FormatOnSemicolon"] = 3] = "FormatOnSemicolon"; + FormattingRequestKind[FormattingRequestKind["FormatOnClosingCurlyBrace"] = 4] = "FormatOnClosingCurlyBrace"; + })(formatting.FormattingRequestKind || (formatting.FormattingRequestKind = {})); + var FormattingRequestKind = formatting.FormattingRequestKind; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/formattingScanner.js b/dist/typescript/services/formatting/formattingScanner.js new file mode 100644 index 000000000..0e3022521 --- /dev/null +++ b/dist/typescript/services/formatting/formattingScanner.js @@ -0,0 +1,184 @@ +/// +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var scanner = ts.createScanner(2, false); + var ScanAction; + (function (ScanAction) { + ScanAction[ScanAction["Scan"] = 0] = "Scan"; + ScanAction[ScanAction["RescanGreaterThanToken"] = 1] = "RescanGreaterThanToken"; + ScanAction[ScanAction["RescanSlashToken"] = 2] = "RescanSlashToken"; + ScanAction[ScanAction["RescanTemplateToken"] = 3] = "RescanTemplateToken"; + })(ScanAction || (ScanAction = {})); + function getFormattingScanner(sourceFile, startPos, endPos) { + scanner.setText(sourceFile.text); + scanner.setTextPos(startPos); + var wasNewLine = true; + var leadingTrivia; + var trailingTrivia; + var savedPos; + var lastScanAction; + var lastTokenInfo; + return { + advance: advance, + readTokenInfo: readTokenInfo, + isOnToken: isOnToken, + lastTrailingTriviaWasNewLine: function () { return wasNewLine; }, + close: function () { + lastTokenInfo = undefined; + scanner.setText(undefined); + } + }; + function advance() { + lastTokenInfo = undefined; + var isStarted = scanner.getStartPos() !== startPos; + if (isStarted) { + if (trailingTrivia) { + ts.Debug.assert(trailingTrivia.length !== 0); + wasNewLine = trailingTrivia[trailingTrivia.length - 1].kind === 4; + } + else { + wasNewLine = false; + } + } + leadingTrivia = undefined; + trailingTrivia = undefined; + if (!isStarted) { + scanner.scan(); + } + var t; + var pos = scanner.getStartPos(); + while (pos < endPos) { + var t_1 = scanner.getToken(); + if (!ts.isTrivia(t_1)) { + break; + } + scanner.scan(); + var item_1 = { + pos: pos, + end: scanner.getStartPos(), + kind: t_1 + }; + pos = scanner.getStartPos(); + if (!leadingTrivia) { + leadingTrivia = []; + } + leadingTrivia.push(item_1); + } + savedPos = scanner.getStartPos(); + } + function shouldRescanGreaterThanToken(node) { + if (node) { + switch (node.kind) { + case 27: + case 60: + case 61: + case 42: + case 41: + return true; + } + } + return false; + } + function shouldRescanSlashToken(container) { + return container.kind === 9; + } + function shouldRescanTemplateToken(container) { + return container.kind === 12 || + container.kind === 13; + } + function startsWithSlashToken(t) { + return t === 36 || t === 57; + } + function readTokenInfo(n) { + if (!isOnToken()) { + return { + leadingTrivia: leadingTrivia, + trailingTrivia: undefined, + token: undefined + }; + } + var expectedScanAction = shouldRescanGreaterThanToken(n) + ? 1 + : shouldRescanSlashToken(n) + ? 2 + : shouldRescanTemplateToken(n) + ? 3 + : 0; + if (lastTokenInfo && expectedScanAction === lastScanAction) { + return fixTokenKind(lastTokenInfo, n); + } + if (scanner.getStartPos() !== savedPos) { + ts.Debug.assert(lastTokenInfo !== undefined); + scanner.setTextPos(savedPos); + scanner.scan(); + } + var currentToken = scanner.getToken(); + if (expectedScanAction === 1 && currentToken === 25) { + currentToken = scanner.reScanGreaterToken(); + ts.Debug.assert(n.kind === currentToken); + lastScanAction = 1; + } + else if (expectedScanAction === 2 && startsWithSlashToken(currentToken)) { + currentToken = scanner.reScanSlashToken(); + ts.Debug.assert(n.kind === currentToken); + lastScanAction = 2; + } + else if (expectedScanAction === 3 && currentToken === 15) { + currentToken = scanner.reScanTemplateToken(); + lastScanAction = 3; + } + else { + lastScanAction = 0; + } + var token = { + pos: scanner.getStartPos(), + end: scanner.getTextPos(), + kind: currentToken + }; + if (trailingTrivia) { + trailingTrivia = undefined; + } + while (scanner.getStartPos() < endPos) { + currentToken = scanner.scan(); + if (!ts.isTrivia(currentToken)) { + break; + } + var trivia = { + pos: scanner.getStartPos(), + end: scanner.getTextPos(), + kind: currentToken + }; + if (!trailingTrivia) { + trailingTrivia = []; + } + trailingTrivia.push(trivia); + if (currentToken === 4) { + scanner.scan(); + break; + } + } + lastTokenInfo = { + leadingTrivia: leadingTrivia, + trailingTrivia: trailingTrivia, + token: token + }; + return fixTokenKind(lastTokenInfo, n); + } + function isOnToken() { + var current = (lastTokenInfo && lastTokenInfo.token.kind) || scanner.getToken(); + var startPos = (lastTokenInfo && lastTokenInfo.token.pos) || scanner.getStartPos(); + return startPos < endPos && current !== 1 && !ts.isTrivia(current); + } + function fixTokenKind(tokenInfo, container) { + if (ts.isToken(container) && tokenInfo.token.kind !== container.kind) { + tokenInfo.token.kind = container.kind; + } + return tokenInfo; + } + } + formatting.getFormattingScanner = getFormattingScanner; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/references.js b/dist/typescript/services/formatting/references.js new file mode 100644 index 000000000..5a854c4e8 --- /dev/null +++ b/dist/typescript/services/formatting/references.js @@ -0,0 +1,12 @@ +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// diff --git a/dist/typescript/services/formatting/rule.js b/dist/typescript/services/formatting/rule.js new file mode 100644 index 000000000..d96fb232e --- /dev/null +++ b/dist/typescript/services/formatting/rule.js @@ -0,0 +1,22 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var Rule = (function () { + function Rule(Descriptor, Operation, Flag) { + if (Flag === void 0) { Flag = 0; } + this.Descriptor = Descriptor; + this.Operation = Operation; + this.Flag = Flag; + } + Rule.prototype.toString = function () { + return "[desc=" + this.Descriptor + "," + + "operation=" + this.Operation + "," + + "flag=" + this.Flag + "]"; + }; + return Rule; + })(); + formatting.Rule = Rule; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/ruleAction.js b/dist/typescript/services/formatting/ruleAction.js new file mode 100644 index 000000000..201e3c669 --- /dev/null +++ b/dist/typescript/services/formatting/ruleAction.js @@ -0,0 +1,14 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + (function (RuleAction) { + RuleAction[RuleAction["Ignore"] = 1] = "Ignore"; + RuleAction[RuleAction["Space"] = 2] = "Space"; + RuleAction[RuleAction["NewLine"] = 4] = "NewLine"; + RuleAction[RuleAction["Delete"] = 8] = "Delete"; + })(formatting.RuleAction || (formatting.RuleAction = {})); + var RuleAction = formatting.RuleAction; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/ruleDescriptor.js b/dist/typescript/services/formatting/ruleDescriptor.js new file mode 100644 index 000000000..38e69aabe --- /dev/null +++ b/dist/typescript/services/formatting/ruleDescriptor.js @@ -0,0 +1,31 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var RuleDescriptor = (function () { + function RuleDescriptor(LeftTokenRange, RightTokenRange) { + this.LeftTokenRange = LeftTokenRange; + this.RightTokenRange = RightTokenRange; + } + RuleDescriptor.prototype.toString = function () { + return "[leftRange=" + this.LeftTokenRange + "," + + "rightRange=" + this.RightTokenRange + "]"; + }; + RuleDescriptor.create1 = function (left, right) { + return RuleDescriptor.create4(formatting.Shared.TokenRange.FromToken(left), formatting.Shared.TokenRange.FromToken(right)); + }; + RuleDescriptor.create2 = function (left, right) { + return RuleDescriptor.create4(left, formatting.Shared.TokenRange.FromToken(right)); + }; + RuleDescriptor.create3 = function (left, right) { + return RuleDescriptor.create4(formatting.Shared.TokenRange.FromToken(left), right); + }; + RuleDescriptor.create4 = function (left, right) { + return new RuleDescriptor(left, right); + }; + return RuleDescriptor; + })(); + formatting.RuleDescriptor = RuleDescriptor; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/ruleFlag.js b/dist/typescript/services/formatting/ruleFlag.js new file mode 100644 index 000000000..298f9a28d --- /dev/null +++ b/dist/typescript/services/formatting/ruleFlag.js @@ -0,0 +1,12 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + (function (RuleFlags) { + RuleFlags[RuleFlags["None"] = 0] = "None"; + RuleFlags[RuleFlags["CanDeleteNewLines"] = 1] = "CanDeleteNewLines"; + })(formatting.RuleFlags || (formatting.RuleFlags = {})); + var RuleFlags = formatting.RuleFlags; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/ruleOperation.js b/dist/typescript/services/formatting/ruleOperation.js new file mode 100644 index 000000000..52558928e --- /dev/null +++ b/dist/typescript/services/formatting/ruleOperation.js @@ -0,0 +1,28 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var RuleOperation = (function () { + function RuleOperation() { + this.Context = null; + this.Action = null; + } + RuleOperation.prototype.toString = function () { + return "[context=" + this.Context + "," + + "action=" + this.Action + "]"; + }; + RuleOperation.create1 = function (action) { + return RuleOperation.create2(formatting.RuleOperationContext.Any, action); + }; + RuleOperation.create2 = function (context, action) { + var result = new RuleOperation(); + result.Context = context; + result.Action = action; + return result; + }; + return RuleOperation; + })(); + formatting.RuleOperation = RuleOperation; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/ruleOperationContext.js b/dist/typescript/services/formatting/ruleOperationContext.js new file mode 100644 index 000000000..0fc174a3b --- /dev/null +++ b/dist/typescript/services/formatting/ruleOperationContext.js @@ -0,0 +1,34 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var RuleOperationContext = (function () { + function RuleOperationContext() { + var funcs = []; + for (var _i = 0; _i < arguments.length; _i++) { + funcs[_i - 0] = arguments[_i]; + } + this.customContextChecks = funcs; + } + RuleOperationContext.prototype.IsAny = function () { + return this == RuleOperationContext.Any; + }; + RuleOperationContext.prototype.InContext = function (context) { + if (this.IsAny()) { + return true; + } + for (var _i = 0, _a = this.customContextChecks; _i < _a.length; _i++) { + var check = _a[_i]; + if (!check(context)) { + return false; + } + } + return true; + }; + RuleOperationContext.Any = new RuleOperationContext(); + return RuleOperationContext; + })(); + formatting.RuleOperationContext = RuleOperationContext; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/rules.js b/dist/typescript/services/formatting/rules.js new file mode 100644 index 000000000..ecb95c7b1 --- /dev/null +++ b/dist/typescript/services/formatting/rules.js @@ -0,0 +1,378 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var Rules = (function () { + function Rules() { + /// + /// Common Rules + /// + this.IgnoreBeforeComment = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.Any, formatting.Shared.TokenRange.Comments), formatting.RuleOperation.create1(1)); + this.IgnoreAfterLineComment = new formatting.Rule(formatting.RuleDescriptor.create3(2, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create1(1)); + this.NoSpaceBeforeSemicolon = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 22), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceBeforeColon = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 51), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), 8)); + this.NoSpaceBeforeQuestionMark = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 50), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), 8)); + this.SpaceAfterColon = new formatting.Rule(formatting.RuleDescriptor.create3(51, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), 2)); + this.SpaceAfterQuestionMarkInConditionalOperator = new formatting.Rule(formatting.RuleDescriptor.create3(50, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsConditionalOperatorContext), 2)); + this.NoSpaceAfterQuestionMark = new formatting.Rule(formatting.RuleDescriptor.create3(50, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.SpaceAfterSemicolon = new formatting.Rule(formatting.RuleDescriptor.create3(22, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.SpaceAfterCloseBrace = new formatting.Rule(formatting.RuleDescriptor.create3(15, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsAfterCodeBlockContext), 2)); + this.SpaceBetweenCloseBraceAndElse = new formatting.Rule(formatting.RuleDescriptor.create1(15, 76), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.SpaceBetweenCloseBraceAndWhile = new formatting.Rule(formatting.RuleDescriptor.create1(15, 100), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.NoSpaceAfterCloseBrace = new formatting.Rule(formatting.RuleDescriptor.create3(15, formatting.Shared.TokenRange.FromTokens([17, 19, 23, 22])), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceBeforeDot = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 20), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceAfterDot = new formatting.Rule(formatting.RuleDescriptor.create3(20, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceBeforeOpenBracket = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 18), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceAfterOpenBracket = new formatting.Rule(formatting.RuleDescriptor.create3(18, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceBeforeCloseBracket = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 19), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceAfterCloseBracket = new formatting.Rule(formatting.RuleDescriptor.create3(19, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.FunctionOpenBraceLeftTokenRange = formatting.Shared.TokenRange.AnyIncludingMultilineComments; + this.SpaceBeforeOpenBraceInFunction = new formatting.Rule(formatting.RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, 14), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsBeforeBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), 2), 1); + this.TypeScriptOpenBraceLeftTokenRange = formatting.Shared.TokenRange.FromTokens([65, 3]); + this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new formatting.Rule(formatting.RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, 14), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), 2), 1); + this.ControlOpenBraceLeftTokenRange = formatting.Shared.TokenRange.FromTokens([17, 3, 75, 96, 81, 76]); + this.SpaceBeforeOpenBraceInControl = new formatting.Rule(formatting.RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, 14), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsControlDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), 2), 1); + this.SpaceAfterOpenBrace = new formatting.Rule(formatting.RuleDescriptor.create3(14, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSingleLineBlockContext), 2)); + this.SpaceBeforeCloseBrace = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 15), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSingleLineBlockContext), 2)); + this.NoSpaceBetweenEmptyBraceBrackets = new formatting.Rule(formatting.RuleDescriptor.create1(14, 15), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsObjectContext), 8)); + this.NewLineAfterOpenBraceInBlockContext = new formatting.Rule(formatting.RuleDescriptor.create3(14, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsMultilineBlockContext), 4)); + this.NewLineBeforeCloseBraceInBlockContext = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.AnyIncludingMultilineComments, 15), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsMultilineBlockContext), 4)); + this.NoSpaceAfterUnaryPrefixOperator = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.UnaryPrefixOperators, formatting.Shared.TokenRange.UnaryPrefixExpressions), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), 8)); + this.NoSpaceAfterUnaryPreincrementOperator = new formatting.Rule(formatting.RuleDescriptor.create3(38, formatting.Shared.TokenRange.UnaryPreincrementExpressions), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceAfterUnaryPredecrementOperator = new formatting.Rule(formatting.RuleDescriptor.create3(39, formatting.Shared.TokenRange.UnaryPredecrementExpressions), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceBeforeUnaryPostincrementOperator = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.UnaryPostincrementExpressions, 38), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceBeforeUnaryPostdecrementOperator = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.UnaryPostdecrementExpressions, 39), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.SpaceAfterPostincrementWhenFollowedByAdd = new formatting.Rule(formatting.RuleDescriptor.create1(38, 33), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 2)); + this.SpaceAfterAddWhenFollowedByUnaryPlus = new formatting.Rule(formatting.RuleDescriptor.create1(33, 33), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 2)); + this.SpaceAfterAddWhenFollowedByPreincrement = new formatting.Rule(formatting.RuleDescriptor.create1(33, 38), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 2)); + this.SpaceAfterPostdecrementWhenFollowedBySubtract = new formatting.Rule(formatting.RuleDescriptor.create1(39, 34), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 2)); + this.SpaceAfterSubtractWhenFollowedByUnaryMinus = new formatting.Rule(formatting.RuleDescriptor.create1(34, 34), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 2)); + this.SpaceAfterSubtractWhenFollowedByPredecrement = new formatting.Rule(formatting.RuleDescriptor.create1(34, 39), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 2)); + this.NoSpaceBeforeComma = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 23), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.SpaceAfterCertainKeywords = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.FromTokens([98, 94, 88, 74, 90, 97]), formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.SpaceAfterLetConstInVariableDeclaration = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.FromTokens([104, 70]), formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsStartOfVariableDeclarationList), 2)); + this.NoSpaceBeforeOpenParenInFuncCall = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 16), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsFunctionCallOrNewContext, Rules.IsPreviousTokenNotComma), 8)); + this.SpaceAfterFunctionInFuncDecl = new formatting.Rule(formatting.RuleDescriptor.create3(83, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsFunctionDeclContext), 2)); + this.NoSpaceBeforeOpenParenInFuncDecl = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 16), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsFunctionDeclContext), 8)); + this.SpaceAfterVoidOperator = new formatting.Rule(formatting.RuleDescriptor.create3(99, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsVoidOpContext), 2)); + this.NoSpaceBetweenReturnAndSemicolon = new formatting.Rule(formatting.RuleDescriptor.create1(90, 22), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.SpaceBetweenStatements = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.FromTokens([17, 75, 76, 67]), formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotForContext), 2)); + this.SpaceAfterTryFinally = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.FromTokens([96, 81]), 14), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.SpaceAfterGetSetInMember = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.FromTokens([116, 120]), 65), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsFunctionDeclContext), 2)); + this.SpaceBeforeBinaryKeywordOperator = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.Any, formatting.Shared.TokenRange.BinaryKeywordOperators), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 2)); + this.SpaceAfterBinaryKeywordOperator = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.BinaryKeywordOperators, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 2)); + this.NoSpaceAfterConstructor = new formatting.Rule(formatting.RuleDescriptor.create1(114, 16), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceAfterModuleImport = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.FromTokens([117, 118]), 16), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.SpaceAfterCertainTypeScriptKeywords = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.FromTokens([69, 115, 77, 78, 79, 116, 102, 85, 103, 117, 106, 108, 120, 109]), formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.SpaceBeforeCertainTypeScriptKeywords = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.Any, formatting.Shared.TokenRange.FromTokens([79, 102])), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.SpaceAfterModuleName = new formatting.Rule(formatting.RuleDescriptor.create1(8, 14), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsModuleDeclContext), 2)); + this.SpaceAfterArrow = new formatting.Rule(formatting.RuleDescriptor.create3(32, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.NoSpaceAfterEllipsis = new formatting.Rule(formatting.RuleDescriptor.create1(21, 65), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceAfterOptionalParameters = new formatting.Rule(formatting.RuleDescriptor.create3(50, formatting.Shared.TokenRange.FromTokens([17, 23])), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), 8)); + this.NoSpaceBeforeOpenAngularBracket = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.TypeNames, 24), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), 8)); + this.NoSpaceBetweenCloseParenAndAngularBracket = new formatting.Rule(formatting.RuleDescriptor.create1(17, 24), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), 8)); + this.NoSpaceAfterOpenAngularBracket = new formatting.Rule(formatting.RuleDescriptor.create3(24, formatting.Shared.TokenRange.TypeNames), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), 8)); + this.NoSpaceBeforeCloseAngularBracket = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 25), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), 8)); + this.NoSpaceAfterCloseAngularBracket = new formatting.Rule(formatting.RuleDescriptor.create3(25, formatting.Shared.TokenRange.FromTokens([16, 18, 25, 23])), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), 8)); + this.NoSpaceBetweenEmptyInterfaceBraceBrackets = new formatting.Rule(formatting.RuleDescriptor.create1(14, 15), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsObjectTypeContext), 8)); + this.SpaceBeforeAt = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 52), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.NoSpaceAfterAt = new formatting.Rule(formatting.RuleDescriptor.create3(52, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.SpaceAfterDecorator = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.Any, formatting.Shared.TokenRange.FromTokens([65, 78, 73, 69, 109, 108, 106, 107, 116, 120, 18, 35])), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsEndOfDecoratorContextOnSameLine), 2)); + this.HighPriorityCommonRules = + [ + this.IgnoreBeforeComment, this.IgnoreAfterLineComment, + this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQuestionMark, this.SpaceAfterQuestionMarkInConditionalOperator, + this.NoSpaceAfterQuestionMark, + this.NoSpaceBeforeDot, this.NoSpaceAfterDot, + this.NoSpaceAfterUnaryPrefixOperator, + this.NoSpaceAfterUnaryPreincrementOperator, this.NoSpaceAfterUnaryPredecrementOperator, + this.NoSpaceBeforeUnaryPostincrementOperator, this.NoSpaceBeforeUnaryPostdecrementOperator, + this.SpaceAfterPostincrementWhenFollowedByAdd, + this.SpaceAfterAddWhenFollowedByUnaryPlus, this.SpaceAfterAddWhenFollowedByPreincrement, + this.SpaceAfterPostdecrementWhenFollowedBySubtract, + this.SpaceAfterSubtractWhenFollowedByUnaryMinus, this.SpaceAfterSubtractWhenFollowedByPredecrement, + this.NoSpaceAfterCloseBrace, + this.SpaceAfterOpenBrace, this.SpaceBeforeCloseBrace, this.NewLineBeforeCloseBraceInBlockContext, + this.SpaceAfterCloseBrace, this.SpaceBetweenCloseBraceAndElse, this.SpaceBetweenCloseBraceAndWhile, this.NoSpaceBetweenEmptyBraceBrackets, + this.SpaceAfterFunctionInFuncDecl, this.NewLineAfterOpenBraceInBlockContext, this.SpaceAfterGetSetInMember, + this.NoSpaceBetweenReturnAndSemicolon, + this.SpaceAfterCertainKeywords, + this.SpaceAfterLetConstInVariableDeclaration, + this.NoSpaceBeforeOpenParenInFuncCall, + this.SpaceBeforeBinaryKeywordOperator, this.SpaceAfterBinaryKeywordOperator, + this.SpaceAfterVoidOperator, + this.NoSpaceAfterConstructor, this.NoSpaceAfterModuleImport, + this.SpaceAfterCertainTypeScriptKeywords, this.SpaceBeforeCertainTypeScriptKeywords, + this.SpaceAfterModuleName, + this.SpaceAfterArrow, + this.NoSpaceAfterEllipsis, + this.NoSpaceAfterOptionalParameters, + this.NoSpaceBetweenEmptyInterfaceBraceBrackets, + this.NoSpaceBeforeOpenAngularBracket, + this.NoSpaceBetweenCloseParenAndAngularBracket, + this.NoSpaceAfterOpenAngularBracket, + this.NoSpaceBeforeCloseAngularBracket, + this.NoSpaceAfterCloseAngularBracket, + this.SpaceBeforeAt, + this.NoSpaceAfterAt, + this.SpaceAfterDecorator, + ]; + this.LowPriorityCommonRules = + [ + this.NoSpaceBeforeSemicolon, + this.SpaceBeforeOpenBraceInControl, this.SpaceBeforeOpenBraceInFunction, this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock, + this.NoSpaceBeforeComma, + this.NoSpaceBeforeOpenBracket, this.NoSpaceAfterOpenBracket, + this.NoSpaceBeforeCloseBracket, this.NoSpaceAfterCloseBracket, + this.SpaceAfterSemicolon, + this.NoSpaceBeforeOpenParenInFuncDecl, + this.SpaceBetweenStatements, this.SpaceAfterTryFinally + ]; + this.SpaceAfterComma = new formatting.Rule(formatting.RuleDescriptor.create3(23, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.NoSpaceAfterComma = new formatting.Rule(formatting.RuleDescriptor.create3(23, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.SpaceBeforeBinaryOperator = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.Any, formatting.Shared.TokenRange.BinaryOperators), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 2)); + this.SpaceAfterBinaryOperator = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.BinaryOperators, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 2)); + this.NoSpaceBeforeBinaryOperator = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.Any, formatting.Shared.TokenRange.BinaryOperators), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 8)); + this.NoSpaceAfterBinaryOperator = new formatting.Rule(formatting.RuleDescriptor.create4(formatting.Shared.TokenRange.BinaryOperators, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), 8)); + this.SpaceAfterKeywordInControl = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Keywords, 16), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsControlDeclContext), 2)); + this.NoSpaceAfterKeywordInControl = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Keywords, 16), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsControlDeclContext), 8)); + this.NewLineBeforeOpenBraceInFunction = new formatting.Rule(formatting.RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, 14), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsBeforeMultilineBlockContext), 4), 1); + this.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock = new formatting.Rule(formatting.RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, 14), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsBeforeMultilineBlockContext), 4), 1); + this.NewLineBeforeOpenBraceInControl = new formatting.Rule(formatting.RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, 14), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsControlDeclContext, Rules.IsBeforeMultilineBlockContext), 4), 1); + this.SpaceAfterSemicolonInFor = new formatting.Rule(formatting.RuleDescriptor.create3(22, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsForContext), 2)); + this.NoSpaceAfterSemicolonInFor = new formatting.Rule(formatting.RuleDescriptor.create3(22, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsForContext), 8)); + this.SpaceAfterOpenParen = new formatting.Rule(formatting.RuleDescriptor.create3(16, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.SpaceBeforeCloseParen = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 17), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 2)); + this.NoSpaceBetweenParens = new formatting.Rule(formatting.RuleDescriptor.create1(16, 17), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceAfterOpenParen = new formatting.Rule(formatting.RuleDescriptor.create3(16, formatting.Shared.TokenRange.Any), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.NoSpaceBeforeCloseParen = new formatting.Rule(formatting.RuleDescriptor.create2(formatting.Shared.TokenRange.Any, 17), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsSameLineTokenContext), 8)); + this.SpaceAfterAnonymousFunctionKeyword = new formatting.Rule(formatting.RuleDescriptor.create1(83, 16), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsFunctionDeclContext), 2)); + this.NoSpaceAfterAnonymousFunctionKeyword = new formatting.Rule(formatting.RuleDescriptor.create1(83, 16), formatting.RuleOperation.create2(new formatting.RuleOperationContext(Rules.IsFunctionDeclContext), 8)); + } + Rules.prototype.getRuleName = function (rule) { + var o = this; + for (var name_1 in o) { + if (o[name_1] === rule) { + return name_1; + } + } + throw new Error("Unknown rule"); + }; + Rules.IsForContext = function (context) { + return context.contextNode.kind === 186; + }; + Rules.IsNotForContext = function (context) { + return !Rules.IsForContext(context); + }; + Rules.IsBinaryOpContext = function (context) { + switch (context.contextNode.kind) { + case 169: + case 170: + return true; + case 152: + case 203: + case 208: + case 198: + case 129: + case 226: + case 132: + case 131: + return context.currentTokenSpan.kind === 53 || context.nextTokenSpan.kind === 53; + case 187: + return context.currentTokenSpan.kind === 86 || context.nextTokenSpan.kind === 86; + case 188: + return context.currentTokenSpan.kind === 125 || context.nextTokenSpan.kind === 125; + } + return false; + }; + Rules.IsNotBinaryOpContext = function (context) { + return !Rules.IsBinaryOpContext(context); + }; + Rules.IsConditionalOperatorContext = function (context) { + return context.contextNode.kind === 170; + }; + Rules.IsSameLineTokenOrBeforeMultilineBlockContext = function (context) { + //// This check is mainly used inside SpaceBeforeOpenBraceInControl and SpaceBeforeOpenBraceInFunction. + //// + //// Ex: + //// if (1) { .... + //// * ) and { are on the same line so apply the rule. Here we don't care whether it's same or multi block context + //// + //// Ex: + //// if (1) + //// { ... } + //// * ) and { are on differnet lines. We only need to format if the block is multiline context. So in this case we don't format. + //// + //// Ex: + //// if (1) + //// { ... + //// } + //// * ) and { are on differnet lines. We only need to format if the block is multiline context. So in this case we format. + return context.TokensAreOnSameLine() || Rules.IsBeforeMultilineBlockContext(context); + }; + Rules.IsBeforeMultilineBlockContext = function (context) { + return Rules.IsBeforeBlockContext(context) && !(context.NextNodeAllOnSameLine() || context.NextNodeBlockIsOnOneLine()); + }; + Rules.IsMultilineBlockContext = function (context) { + return Rules.IsBlockContext(context) && !(context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); + }; + Rules.IsSingleLineBlockContext = function (context) { + return Rules.IsBlockContext(context) && (context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); + }; + Rules.IsBlockContext = function (context) { + return Rules.NodeIsBlockContext(context.contextNode); + }; + Rules.IsBeforeBlockContext = function (context) { + return Rules.NodeIsBlockContext(context.nextTokenParent); + }; + Rules.NodeIsBlockContext = function (node) { + if (Rules.NodeIsTypeScriptDeclWithBlockContext(node)) { + return true; + } + switch (node.kind) { + case 179: + case 207: + case 154: + case 206: + return true; + } + return false; + }; + Rules.IsFunctionDeclContext = function (context) { + switch (context.contextNode.kind) { + case 200: + case 134: + case 133: + case 136: + case 137: + case 138: + case 162: + case 135: + case 163: + case 202: + return true; + } + return false; + }; + Rules.IsTypeScriptDeclWithBlockContext = function (context) { + return Rules.NodeIsTypeScriptDeclWithBlockContext(context.contextNode); + }; + Rules.NodeIsTypeScriptDeclWithBlockContext = function (node) { + switch (node.kind) { + case 201: + case 202: + case 204: + case 145: + case 205: + return true; + } + return false; + }; + Rules.IsAfterCodeBlockContext = function (context) { + switch (context.currentTokenParent.kind) { + case 201: + case 205: + case 204: + case 179: + case 223: + case 206: + case 193: + return true; + } + return false; + }; + Rules.IsControlDeclContext = function (context) { + switch (context.contextNode.kind) { + case 183: + case 193: + case 186: + case 187: + case 188: + case 185: + case 196: + case 184: + case 192: + case 223: + return true; + default: + return false; + } + }; + Rules.IsObjectContext = function (context) { + return context.contextNode.kind === 154; + }; + Rules.IsFunctionCallContext = function (context) { + return context.contextNode.kind === 157; + }; + Rules.IsNewContext = function (context) { + return context.contextNode.kind === 158; + }; + Rules.IsFunctionCallOrNewContext = function (context) { + return Rules.IsFunctionCallContext(context) || Rules.IsNewContext(context); + }; + Rules.IsPreviousTokenNotComma = function (context) { + return context.currentTokenSpan.kind !== 23; + }; + Rules.IsSameLineTokenContext = function (context) { + return context.TokensAreOnSameLine(); + }; + Rules.IsEndOfDecoratorContextOnSameLine = function (context) { + return context.TokensAreOnSameLine() && + context.contextNode.decorators && + Rules.NodeIsInDecoratorContext(context.currentTokenParent) && + !Rules.NodeIsInDecoratorContext(context.nextTokenParent); + }; + Rules.NodeIsInDecoratorContext = function (node) { + while (ts.isExpression(node)) { + node = node.parent; + } + return node.kind === 130; + }; + Rules.IsStartOfVariableDeclarationList = function (context) { + return context.currentTokenParent.kind === 199 && + context.currentTokenParent.getStart(context.sourceFile) === context.currentTokenSpan.pos; + }; + Rules.IsNotFormatOnEnter = function (context) { + return context.formattingRequestKind != 2; + }; + Rules.IsModuleDeclContext = function (context) { + return context.contextNode.kind === 205; + }; + Rules.IsObjectTypeContext = function (context) { + return context.contextNode.kind === 145; + }; + Rules.IsTypeArgumentOrParameter = function (token, parent) { + if (token.kind !== 24 && token.kind !== 25) { + return false; + } + switch (parent.kind) { + case 141: + case 201: + case 202: + case 200: + case 162: + case 163: + case 134: + case 133: + case 138: + case 139: + case 157: + case 158: + return true; + default: + return false; + } + }; + Rules.IsTypeArgumentOrParameterContext = function (context) { + return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan, context.currentTokenParent) || + Rules.IsTypeArgumentOrParameter(context.nextTokenSpan, context.nextTokenParent); + }; + Rules.IsVoidOpContext = function (context) { + return context.currentTokenSpan.kind === 99 && context.currentTokenParent.kind === 166; + }; + return Rules; + })(); + formatting.Rules = Rules; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/rulesMap.js b/dist/typescript/services/formatting/rulesMap.js new file mode 100644 index 000000000..ad474abf7 --- /dev/null +++ b/dist/typescript/services/formatting/rulesMap.js @@ -0,0 +1,137 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var RulesMap = (function () { + function RulesMap() { + this.map = []; + this.mapRowLength = 0; + } + RulesMap.create = function (rules) { + var result = new RulesMap(); + result.Initialize(rules); + return result; + }; + RulesMap.prototype.Initialize = function (rules) { + this.mapRowLength = 125 + 1; + this.map = new Array(this.mapRowLength * this.mapRowLength); + var rulesBucketConstructionStateList = new Array(this.map.length); + this.FillRules(rules, rulesBucketConstructionStateList); + return this.map; + }; + RulesMap.prototype.FillRules = function (rules, rulesBucketConstructionStateList) { + var _this = this; + rules.forEach(function (rule) { + _this.FillRule(rule, rulesBucketConstructionStateList); + }); + }; + RulesMap.prototype.GetRuleBucketIndex = function (row, column) { + var rulesBucketIndex = (row * this.mapRowLength) + column; + return rulesBucketIndex; + }; + RulesMap.prototype.FillRule = function (rule, rulesBucketConstructionStateList) { + var _this = this; + var specificRule = rule.Descriptor.LeftTokenRange != formatting.Shared.TokenRange.Any && + rule.Descriptor.RightTokenRange != formatting.Shared.TokenRange.Any; + rule.Descriptor.LeftTokenRange.GetTokens().forEach(function (left) { + rule.Descriptor.RightTokenRange.GetTokens().forEach(function (right) { + var rulesBucketIndex = _this.GetRuleBucketIndex(left, right); + var rulesBucket = _this.map[rulesBucketIndex]; + if (rulesBucket == undefined) { + rulesBucket = _this.map[rulesBucketIndex] = new RulesBucket(); + } + rulesBucket.AddRule(rule, specificRule, rulesBucketConstructionStateList, rulesBucketIndex); + }); + }); + }; + RulesMap.prototype.GetRule = function (context) { + var bucketIndex = this.GetRuleBucketIndex(context.currentTokenSpan.kind, context.nextTokenSpan.kind); + var bucket = this.map[bucketIndex]; + if (bucket != null) { + for (var _i = 0, _a = bucket.Rules(); _i < _a.length; _i++) { + var rule = _a[_i]; + if (rule.Operation.Context.InContext(context)) { + return rule; + } + } + } + return null; + }; + return RulesMap; + })(); + formatting.RulesMap = RulesMap; + var MaskBitSize = 5; + var Mask = 0x1f; + (function (RulesPosition) { + RulesPosition[RulesPosition["IgnoreRulesSpecific"] = 0] = "IgnoreRulesSpecific"; + RulesPosition[RulesPosition["IgnoreRulesAny"] = MaskBitSize * 1] = "IgnoreRulesAny"; + RulesPosition[RulesPosition["ContextRulesSpecific"] = MaskBitSize * 2] = "ContextRulesSpecific"; + RulesPosition[RulesPosition["ContextRulesAny"] = MaskBitSize * 3] = "ContextRulesAny"; + RulesPosition[RulesPosition["NoContextRulesSpecific"] = MaskBitSize * 4] = "NoContextRulesSpecific"; + RulesPosition[RulesPosition["NoContextRulesAny"] = MaskBitSize * 5] = "NoContextRulesAny"; + })(formatting.RulesPosition || (formatting.RulesPosition = {})); + var RulesPosition = formatting.RulesPosition; + var RulesBucketConstructionState = (function () { + function RulesBucketConstructionState() { + this.rulesInsertionIndexBitmap = 0; + } + RulesBucketConstructionState.prototype.GetInsertionIndex = function (maskPosition) { + var index = 0; + var pos = 0; + var indexBitmap = this.rulesInsertionIndexBitmap; + while (pos <= maskPosition) { + index += (indexBitmap & Mask); + indexBitmap >>= MaskBitSize; + pos += MaskBitSize; + } + return index; + }; + RulesBucketConstructionState.prototype.IncreaseInsertionIndex = function (maskPosition) { + var value = (this.rulesInsertionIndexBitmap >> maskPosition) & Mask; + value++; + ts.Debug.assert((value & Mask) == value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules."); + var temp = this.rulesInsertionIndexBitmap & ~(Mask << maskPosition); + temp |= value << maskPosition; + this.rulesInsertionIndexBitmap = temp; + }; + return RulesBucketConstructionState; + })(); + formatting.RulesBucketConstructionState = RulesBucketConstructionState; + var RulesBucket = (function () { + function RulesBucket() { + this.rules = []; + } + RulesBucket.prototype.Rules = function () { + return this.rules; + }; + RulesBucket.prototype.AddRule = function (rule, specificTokens, constructionState, rulesBucketIndex) { + var position; + if (rule.Operation.Action == 1) { + position = specificTokens ? + RulesPosition.IgnoreRulesSpecific : + RulesPosition.IgnoreRulesAny; + } + else if (!rule.Operation.Context.IsAny()) { + position = specificTokens ? + RulesPosition.ContextRulesSpecific : + RulesPosition.ContextRulesAny; + } + else { + position = specificTokens ? + RulesPosition.NoContextRulesSpecific : + RulesPosition.NoContextRulesAny; + } + var state = constructionState[rulesBucketIndex]; + if (state === undefined) { + state = constructionState[rulesBucketIndex] = new RulesBucketConstructionState(); + } + var index = state.GetInsertionIndex(position); + this.rules.splice(index, 0, rule); + state.IncreaseInsertionIndex(position); + }; + return RulesBucket; + })(); + formatting.RulesBucket = RulesBucket; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/rulesProvider.js b/dist/typescript/services/formatting/rulesProvider.js new file mode 100644 index 000000000..5b9ad5b9b --- /dev/null +++ b/dist/typescript/services/formatting/rulesProvider.js @@ -0,0 +1,86 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var RulesProvider = (function () { + function RulesProvider() { + this.globalRules = new formatting.Rules(); + } + RulesProvider.prototype.getRuleName = function (rule) { + return this.globalRules.getRuleName(rule); + }; + RulesProvider.prototype.getRuleByName = function (name) { + return this.globalRules[name]; + }; + RulesProvider.prototype.getRulesMap = function () { + return this.rulesMap; + }; + RulesProvider.prototype.ensureUpToDate = function (options) { + if (this.options == null || !ts.compareDataObjects(this.options, options)) { + var activeRules = this.createActiveRules(options); + var rulesMap = formatting.RulesMap.create(activeRules); + this.activeRules = activeRules; + this.rulesMap = rulesMap; + this.options = ts.clone(options); + } + }; + RulesProvider.prototype.createActiveRules = function (options) { + var rules = this.globalRules.HighPriorityCommonRules.slice(0); + if (options.InsertSpaceAfterCommaDelimiter) { + rules.push(this.globalRules.SpaceAfterComma); + } + else { + rules.push(this.globalRules.NoSpaceAfterComma); + } + if (options.InsertSpaceAfterFunctionKeywordForAnonymousFunctions) { + rules.push(this.globalRules.SpaceAfterAnonymousFunctionKeyword); + } + else { + rules.push(this.globalRules.NoSpaceAfterAnonymousFunctionKeyword); + } + if (options.InsertSpaceAfterKeywordsInControlFlowStatements) { + rules.push(this.globalRules.SpaceAfterKeywordInControl); + } + else { + rules.push(this.globalRules.NoSpaceAfterKeywordInControl); + } + if (options.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis) { + rules.push(this.globalRules.SpaceAfterOpenParen); + rules.push(this.globalRules.SpaceBeforeCloseParen); + rules.push(this.globalRules.NoSpaceBetweenParens); + } + else { + rules.push(this.globalRules.NoSpaceAfterOpenParen); + rules.push(this.globalRules.NoSpaceBeforeCloseParen); + rules.push(this.globalRules.NoSpaceBetweenParens); + } + if (options.InsertSpaceAfterSemicolonInForStatements) { + rules.push(this.globalRules.SpaceAfterSemicolonInFor); + } + else { + rules.push(this.globalRules.NoSpaceAfterSemicolonInFor); + } + if (options.InsertSpaceBeforeAndAfterBinaryOperators) { + rules.push(this.globalRules.SpaceBeforeBinaryOperator); + rules.push(this.globalRules.SpaceAfterBinaryOperator); + } + else { + rules.push(this.globalRules.NoSpaceBeforeBinaryOperator); + rules.push(this.globalRules.NoSpaceAfterBinaryOperator); + } + if (options.PlaceOpenBraceOnNewLineForControlBlocks) { + rules.push(this.globalRules.NewLineBeforeOpenBraceInControl); + } + if (options.PlaceOpenBraceOnNewLineForFunctions) { + rules.push(this.globalRules.NewLineBeforeOpenBraceInFunction); + rules.push(this.globalRules.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock); + } + rules = rules.concat(this.globalRules.LowPriorityCommonRules); + return rules; + }; + return RulesProvider; + })(); + formatting.RulesProvider = RulesProvider; + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/smartIndenter.js b/dist/typescript/services/formatting/smartIndenter.js new file mode 100644 index 000000000..efc161a3c --- /dev/null +++ b/dist/typescript/services/formatting/smartIndenter.js @@ -0,0 +1,307 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var SmartIndenter; + (function (SmartIndenter) { + var Value; + (function (Value) { + Value[Value["Unknown"] = -1] = "Unknown"; + })(Value || (Value = {})); + function getIndentation(position, sourceFile, options) { + if (position > sourceFile.text.length) { + return 0; + } + var precedingToken = ts.findPrecedingToken(position, sourceFile); + if (!precedingToken) { + return 0; + } + var precedingTokenIsLiteral = precedingToken.kind === 8 || + precedingToken.kind === 9 || + precedingToken.kind === 10 || + precedingToken.kind === 11 || + precedingToken.kind === 12 || + precedingToken.kind === 13; + if (precedingTokenIsLiteral && precedingToken.getStart(sourceFile) <= position && precedingToken.end > position) { + return 0; + } + var lineAtPosition = sourceFile.getLineAndCharacterOfPosition(position).line; + if (precedingToken.kind === 23 && precedingToken.parent.kind !== 169) { + var actualIndentation = getActualIndentationForListItemBeforeComma(precedingToken, sourceFile, options); + if (actualIndentation !== -1) { + return actualIndentation; + } + } + var previous; + var current = precedingToken; + var currentStart; + var indentationDelta; + while (current) { + if (ts.positionBelongsToNode(current, position, sourceFile) && shouldIndentChildNode(current.kind, previous ? previous.kind : 0)) { + currentStart = getStartLineAndCharacterForNode(current, sourceFile); + if (nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile)) { + indentationDelta = 0; + } + else { + indentationDelta = lineAtPosition !== currentStart.line ? options.IndentSize : 0; + } + break; + } + var actualIndentation = getActualIndentationForListItem(current, sourceFile, options); + if (actualIndentation !== -1) { + return actualIndentation; + } + previous = current; + current = current.parent; + } + if (!current) { + return 0; + } + return getIndentationForNodeWorker(current, currentStart, undefined, indentationDelta, sourceFile, options); + } + SmartIndenter.getIndentation = getIndentation; + function getIndentationForNode(n, ignoreActualIndentationRange, sourceFile, options) { + var start = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)); + return getIndentationForNodeWorker(n, start, ignoreActualIndentationRange, 0, sourceFile, options); + } + SmartIndenter.getIndentationForNode = getIndentationForNode; + function getIndentationForNodeWorker(current, currentStart, ignoreActualIndentationRange, indentationDelta, sourceFile, options) { + var parent = current.parent; + var parentStart; + while (parent) { + var useActualIndentation = true; + if (ignoreActualIndentationRange) { + var start = current.getStart(sourceFile); + useActualIndentation = start < ignoreActualIndentationRange.pos || start > ignoreActualIndentationRange.end; + } + if (useActualIndentation) { + var actualIndentation = getActualIndentationForListItem(current, sourceFile, options); + if (actualIndentation !== -1) { + return actualIndentation + indentationDelta; + } + } + parentStart = getParentStart(parent, current, sourceFile); + var parentAndChildShareLine = parentStart.line === currentStart.line || + childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile); + if (useActualIndentation) { + var actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options); + if (actualIndentation !== -1) { + return actualIndentation + indentationDelta; + } + } + if (shouldIndentChildNode(parent.kind, current.kind) && !parentAndChildShareLine) { + indentationDelta += options.IndentSize; + } + current = parent; + currentStart = parentStart; + parent = current.parent; + } + return indentationDelta; + } + function getParentStart(parent, child, sourceFile) { + var containingList = getContainingList(child, sourceFile); + if (containingList) { + return sourceFile.getLineAndCharacterOfPosition(containingList.pos); + } + return sourceFile.getLineAndCharacterOfPosition(parent.getStart(sourceFile)); + } + function getActualIndentationForListItemBeforeComma(commaToken, sourceFile, options) { + var commaItemInfo = ts.findListItemInfo(commaToken); + if (commaItemInfo && commaItemInfo.listItemIndex > 0) { + return deriveActualIndentationFromList(commaItemInfo.list.getChildren(), commaItemInfo.listItemIndex - 1, sourceFile, options); + } + else { + return -1; + } + } + function getActualIndentationForNode(current, parent, currentLineAndChar, parentAndChildShareLine, sourceFile, options) { + var useActualIndentation = (ts.isDeclaration(current) || ts.isStatement(current)) && + (parent.kind === 227 || !parentAndChildShareLine); + if (!useActualIndentation) { + return -1; + } + return findColumnForFirstNonWhitespaceCharacterInLine(currentLineAndChar, sourceFile, options); + } + function nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile) { + var nextToken = ts.findNextToken(precedingToken, current); + if (!nextToken) { + return false; + } + if (nextToken.kind === 14) { + return true; + } + else if (nextToken.kind === 15) { + var nextTokenStartLine = getStartLineAndCharacterForNode(nextToken, sourceFile).line; + return lineAtPosition === nextTokenStartLine; + } + return false; + } + function getStartLineAndCharacterForNode(n, sourceFile) { + return sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)); + } + function childStartsOnTheSameLineWithElseInIfStatement(parent, child, childStartLine, sourceFile) { + if (parent.kind === 183 && parent.elseStatement === child) { + var elseKeyword = ts.findChildOfKind(parent, 76, sourceFile); + ts.Debug.assert(elseKeyword !== undefined); + var elseKeywordStartLine = getStartLineAndCharacterForNode(elseKeyword, sourceFile).line; + return elseKeywordStartLine === childStartLine; + } + return false; + } + SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement = childStartsOnTheSameLineWithElseInIfStatement; + function getContainingList(node, sourceFile) { + if (node.parent) { + switch (node.parent.kind) { + case 141: + if (node.parent.typeArguments && + ts.rangeContainsStartEnd(node.parent.typeArguments, node.getStart(sourceFile), node.getEnd())) { + return node.parent.typeArguments; + } + break; + case 154: + return node.parent.properties; + case 153: + return node.parent.elements; + case 200: + case 162: + case 163: + case 134: + case 133: + case 138: + case 139: { + var start = node.getStart(sourceFile); + if (node.parent.typeParameters && + ts.rangeContainsStartEnd(node.parent.typeParameters, start, node.getEnd())) { + return node.parent.typeParameters; + } + if (ts.rangeContainsStartEnd(node.parent.parameters, start, node.getEnd())) { + return node.parent.parameters; + } + break; + } + case 158: + case 157: { + var start = node.getStart(sourceFile); + if (node.parent.typeArguments && + ts.rangeContainsStartEnd(node.parent.typeArguments, start, node.getEnd())) { + return node.parent.typeArguments; + } + if (node.parent.arguments && + ts.rangeContainsStartEnd(node.parent.arguments, start, node.getEnd())) { + return node.parent.arguments; + } + break; + } + } + } + return undefined; + } + function getActualIndentationForListItem(node, sourceFile, options) { + var containingList = getContainingList(node, sourceFile); + return containingList ? getActualIndentationFromList(containingList) : -1; + function getActualIndentationFromList(list) { + var index = ts.indexOf(list, node); + return index !== -1 ? deriveActualIndentationFromList(list, index, sourceFile, options) : -1; + } + } + function deriveActualIndentationFromList(list, index, sourceFile, options) { + ts.Debug.assert(index >= 0 && index < list.length); + var node = list[index]; + var lineAndCharacter = getStartLineAndCharacterForNode(node, sourceFile); + for (var i = index - 1; i >= 0; --i) { + if (list[i].kind === 23) { + continue; + } + var prevEndLine = sourceFile.getLineAndCharacterOfPosition(list[i].end).line; + if (prevEndLine !== lineAndCharacter.line) { + return findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter, sourceFile, options); + } + lineAndCharacter = getStartLineAndCharacterForNode(list[i], sourceFile); + } + return -1; + } + function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter, sourceFile, options) { + var lineStart = sourceFile.getPositionOfLineAndCharacter(lineAndCharacter.line, 0); + return findFirstNonWhitespaceColumn(lineStart, lineStart + lineAndCharacter.character, sourceFile, options); + } + function findFirstNonWhitespaceCharacterAndColumn(startPos, endPos, sourceFile, options) { + var character = 0; + var column = 0; + for (var pos = startPos; pos < endPos; ++pos) { + var ch = sourceFile.text.charCodeAt(pos); + if (!ts.isWhiteSpace(ch)) { + break; + } + if (ch === 9) { + column += options.TabSize + (column % options.TabSize); + } + else { + column++; + } + character++; + } + return { column: column, character: character }; + } + SmartIndenter.findFirstNonWhitespaceCharacterAndColumn = findFirstNonWhitespaceCharacterAndColumn; + function findFirstNonWhitespaceColumn(startPos, endPos, sourceFile, options) { + return findFirstNonWhitespaceCharacterAndColumn(startPos, endPos, sourceFile, options).column; + } + SmartIndenter.findFirstNonWhitespaceColumn = findFirstNonWhitespaceColumn; + function nodeContentIsAlwaysIndented(kind) { + switch (kind) { + case 201: + case 202: + case 204: + case 153: + case 179: + case 206: + case 154: + case 145: + case 147: + case 207: + case 221: + case 220: + case 161: + case 157: + case 158: + case 180: + case 198: + case 214: + case 191: + case 170: + case 151: + case 150: + return true; + } + return false; + } + function shouldIndentChildNode(parent, child) { + if (nodeContentIsAlwaysIndented(parent)) { + return true; + } + switch (parent) { + case 184: + case 185: + case 187: + case 188: + case 186: + case 183: + case 200: + case 162: + case 134: + case 133: + case 138: + case 163: + case 135: + case 136: + case 137: + return child !== 179; + default: + return false; + } + } + SmartIndenter.shouldIndentChildNode = shouldIndentChildNode; + })(SmartIndenter = formatting.SmartIndenter || (formatting.SmartIndenter = {})); + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/formatting/tokenRange.js b/dist/typescript/services/formatting/tokenRange.js new file mode 100644 index 000000000..7e7f9f4b0 --- /dev/null +++ b/dist/typescript/services/formatting/tokenRange.js @@ -0,0 +1,115 @@ +/// +var ts; +(function (ts) { + var formatting; + (function (formatting) { + var Shared; + (function (Shared) { + var TokenRangeAccess = (function () { + function TokenRangeAccess(from, to, except) { + this.tokens = []; + for (var token = from; token <= to; token++) { + if (except.indexOf(token) < 0) { + this.tokens.push(token); + } + } + } + TokenRangeAccess.prototype.GetTokens = function () { + return this.tokens; + }; + TokenRangeAccess.prototype.Contains = function (token) { + return this.tokens.indexOf(token) >= 0; + }; + return TokenRangeAccess; + })(); + Shared.TokenRangeAccess = TokenRangeAccess; + var TokenValuesAccess = (function () { + function TokenValuesAccess(tks) { + this.tokens = tks && tks.length ? tks : []; + } + TokenValuesAccess.prototype.GetTokens = function () { + return this.tokens; + }; + TokenValuesAccess.prototype.Contains = function (token) { + return this.tokens.indexOf(token) >= 0; + }; + return TokenValuesAccess; + })(); + Shared.TokenValuesAccess = TokenValuesAccess; + var TokenSingleValueAccess = (function () { + function TokenSingleValueAccess(token) { + this.token = token; + } + TokenSingleValueAccess.prototype.GetTokens = function () { + return [this.token]; + }; + TokenSingleValueAccess.prototype.Contains = function (tokenValue) { + return tokenValue == this.token; + }; + return TokenSingleValueAccess; + })(); + Shared.TokenSingleValueAccess = TokenSingleValueAccess; + var TokenAllAccess = (function () { + function TokenAllAccess() { + } + TokenAllAccess.prototype.GetTokens = function () { + var result = []; + for (var token = 0; token <= 125; token++) { + result.push(token); + } + return result; + }; + TokenAllAccess.prototype.Contains = function (tokenValue) { + return true; + }; + TokenAllAccess.prototype.toString = function () { + return "[allTokens]"; + }; + return TokenAllAccess; + })(); + Shared.TokenAllAccess = TokenAllAccess; + var TokenRange = (function () { + function TokenRange(tokenAccess) { + this.tokenAccess = tokenAccess; + } + TokenRange.FromToken = function (token) { + return new TokenRange(new TokenSingleValueAccess(token)); + }; + TokenRange.FromTokens = function (tokens) { + return new TokenRange(new TokenValuesAccess(tokens)); + }; + TokenRange.FromRange = function (f, to, except) { + if (except === void 0) { except = []; } + return new TokenRange(new TokenRangeAccess(f, to, except)); + }; + TokenRange.AllTokens = function () { + return new TokenRange(new TokenAllAccess()); + }; + TokenRange.prototype.GetTokens = function () { + return this.tokenAccess.GetTokens(); + }; + TokenRange.prototype.Contains = function (token) { + return this.tokenAccess.Contains(token); + }; + TokenRange.prototype.toString = function () { + return this.tokenAccess.toString(); + }; + TokenRange.Any = TokenRange.AllTokens(); + TokenRange.AnyIncludingMultilineComments = TokenRange.FromTokens(TokenRange.Any.GetTokens().concat([3])); + TokenRange.Keywords = TokenRange.FromRange(66, 125); + TokenRange.BinaryOperators = TokenRange.FromRange(24, 64); + TokenRange.BinaryKeywordOperators = TokenRange.FromTokens([86, 87, 125]); + TokenRange.UnaryPrefixOperators = TokenRange.FromTokens([38, 39, 47, 46]); + TokenRange.UnaryPrefixExpressions = TokenRange.FromTokens([7, 65, 16, 18, 14, 93, 88]); + TokenRange.UnaryPreincrementExpressions = TokenRange.FromTokens([65, 16, 93, 88]); + TokenRange.UnaryPostincrementExpressions = TokenRange.FromTokens([65, 17, 19, 88]); + TokenRange.UnaryPredecrementExpressions = TokenRange.FromTokens([65, 16, 93, 88]); + TokenRange.UnaryPostdecrementExpressions = TokenRange.FromTokens([65, 17, 19, 88]); + TokenRange.Comments = TokenRange.FromTokens([2, 3]); + TokenRange.TypeNames = TokenRange.FromTokens([65, 119, 121, 113, 122, 99, 112]); + return TokenRange; + })(); + Shared.TokenRange = TokenRange; + })(Shared = formatting.Shared || (formatting.Shared = {})); + })(formatting = ts.formatting || (ts.formatting = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/navigateTo.js b/dist/typescript/services/navigateTo.js new file mode 100644 index 000000000..7856a6c9c --- /dev/null +++ b/dist/typescript/services/navigateTo.js @@ -0,0 +1,147 @@ +var ts; +(function (ts) { + var NavigateTo; + (function (NavigateTo) { + function getNavigateToItems(program, cancellationToken, searchValue, maxResultCount) { + var patternMatcher = ts.createPatternMatcher(searchValue); + var rawItems = []; + ts.forEach(program.getSourceFiles(), function (sourceFile) { + cancellationToken.throwIfCancellationRequested(); + var nameToDeclarations = sourceFile.getNamedDeclarations(); + for (var name_1 in nameToDeclarations) { + var declarations = ts.getProperty(nameToDeclarations, name_1); + if (declarations) { + var matches = patternMatcher.getMatchesForLastSegmentOfPattern(name_1); + if (!matches) { + continue; + } + for (var _i = 0; _i < declarations.length; _i++) { + var declaration = declarations[_i]; + if (patternMatcher.patternContainsDots) { + var containers = getContainers(declaration); + if (!containers) { + return undefined; + } + matches = patternMatcher.getMatches(containers, name_1); + if (!matches) { + continue; + } + } + var fileName = sourceFile.fileName; + var matchKind = bestMatchKind(matches); + rawItems.push({ name: name_1, fileName: fileName, matchKind: matchKind, isCaseSensitive: allMatchesAreCaseSensitive(matches), declaration: declaration }); + } + } + } + }); + rawItems.sort(compareNavigateToItems); + if (maxResultCount !== undefined) { + rawItems = rawItems.slice(0, maxResultCount); + } + var items = ts.map(rawItems, createNavigateToItem); + return items; + function allMatchesAreCaseSensitive(matches) { + ts.Debug.assert(matches.length > 0); + for (var _i = 0; _i < matches.length; _i++) { + var match = matches[_i]; + if (!match.isCaseSensitive) { + return false; + } + } + return true; + } + function getTextOfIdentifierOrLiteral(node) { + if (node) { + if (node.kind === 65 || + node.kind === 8 || + node.kind === 7) { + return node.text; + } + } + return undefined; + } + function tryAddSingleDeclarationName(declaration, containers) { + if (declaration && declaration.name) { + var text = getTextOfIdentifierOrLiteral(declaration.name); + if (text !== undefined) { + containers.unshift(text); + } + else if (declaration.name.kind === 127) { + return tryAddComputedPropertyName(declaration.name.expression, containers, true); + } + else { + return false; + } + } + return true; + } + function tryAddComputedPropertyName(expression, containers, includeLastPortion) { + var text = getTextOfIdentifierOrLiteral(expression); + if (text !== undefined) { + if (includeLastPortion) { + containers.unshift(text); + } + return true; + } + if (expression.kind === 155) { + var propertyAccess = expression; + if (includeLastPortion) { + containers.unshift(propertyAccess.name.text); + } + return tryAddComputedPropertyName(propertyAccess.expression, containers, true); + } + return false; + } + function getContainers(declaration) { + var containers = []; + if (declaration.name.kind === 127) { + if (!tryAddComputedPropertyName(declaration.name.expression, containers, false)) { + return undefined; + } + } + declaration = ts.getContainerNode(declaration); + while (declaration) { + if (!tryAddSingleDeclarationName(declaration, containers)) { + return undefined; + } + declaration = ts.getContainerNode(declaration); + } + return containers; + } + function bestMatchKind(matches) { + ts.Debug.assert(matches.length > 0); + var bestMatchKind = ts.PatternMatchKind.camelCase; + for (var _i = 0; _i < matches.length; _i++) { + var match = matches[_i]; + var kind = match.kind; + if (kind < bestMatchKind) { + bestMatchKind = kind; + } + } + return bestMatchKind; + } + var baseSensitivity = { sensitivity: "base" }; + function compareNavigateToItems(i1, i2) { + return i1.matchKind - i2.matchKind || + i1.name.localeCompare(i2.name, undefined, baseSensitivity) || + i1.name.localeCompare(i2.name); + } + function createNavigateToItem(rawItem) { + var declaration = rawItem.declaration; + var container = ts.getContainerNode(declaration); + return { + name: rawItem.name, + kind: ts.getNodeKind(declaration), + kindModifiers: ts.getNodeModifiers(declaration), + matchKind: ts.PatternMatchKind[rawItem.matchKind], + isCaseSensitive: rawItem.isCaseSensitive, + fileName: rawItem.fileName, + textSpan: ts.createTextSpanFromBounds(declaration.getStart(), declaration.getEnd()), + containerName: container && container.name ? container.name.text : "", + containerKind: container && container.name ? ts.getNodeKind(container) : "" + }; + } + } + NavigateTo.getNavigateToItems = getNavigateToItems; + })(NavigateTo = ts.NavigateTo || (ts.NavigateTo = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/navigationBar.js b/dist/typescript/services/navigationBar.js new file mode 100644 index 000000000..6e53a1a9b --- /dev/null +++ b/dist/typescript/services/navigationBar.js @@ -0,0 +1,370 @@ +/// +var ts; +(function (ts) { + var NavigationBar; + (function (NavigationBar) { + function getNavigationBarItems(sourceFile) { + var hasGlobalNode = false; + return getItemsWorker(getTopLevelNodes(sourceFile), createTopLevelItem); + function getIndent(node) { + var indent = hasGlobalNode ? 1 : 0; + var current = node.parent; + while (current) { + switch (current.kind) { + case 205: + do { + current = current.parent; + } while (current.kind === 205); + case 201: + case 204: + case 202: + case 200: + indent++; + } + current = current.parent; + } + return indent; + } + function getChildNodes(nodes) { + var childNodes = []; + function visit(node) { + switch (node.kind) { + case 180: + ts.forEach(node.declarationList.declarations, visit); + break; + case 150: + case 151: + ts.forEach(node.elements, visit); + break; + case 215: + if (node.exportClause) { + ts.forEach(node.exportClause.elements, visit); + } + break; + case 209: + var importClause = node.importClause; + if (importClause) { + if (importClause.name) { + childNodes.push(importClause); + } + if (importClause.namedBindings) { + if (importClause.namedBindings.kind === 211) { + childNodes.push(importClause.namedBindings); + } + else { + ts.forEach(importClause.namedBindings.elements, visit); + } + } + } + break; + case 152: + case 198: + if (ts.isBindingPattern(node.name)) { + visit(node.name); + break; + } + case 201: + case 204: + case 202: + case 205: + case 200: + case 208: + case 213: + case 217: + childNodes.push(node); + break; + } + } + ts.forEach(nodes, visit); + return sortNodes(childNodes); + } + function getTopLevelNodes(node) { + var topLevelNodes = []; + topLevelNodes.push(node); + addTopLevelNodes(node.statements, topLevelNodes); + return topLevelNodes; + } + function sortNodes(nodes) { + return nodes.slice(0).sort(function (n1, n2) { + if (n1.name && n2.name) { + return ts.getPropertyNameForPropertyNameNode(n1.name).localeCompare(ts.getPropertyNameForPropertyNameNode(n2.name)); + } + else if (n1.name) { + return 1; + } + else if (n2.name) { + return -1; + } + else { + return n1.kind - n2.kind; + } + }); + } + function addTopLevelNodes(nodes, topLevelNodes) { + nodes = sortNodes(nodes); + for (var _i = 0; _i < nodes.length; _i++) { + var node = nodes[_i]; + switch (node.kind) { + case 201: + case 204: + case 202: + topLevelNodes.push(node); + break; + case 205: + var moduleDeclaration = node; + topLevelNodes.push(node); + addTopLevelNodes(getInnermostModule(moduleDeclaration).body.statements, topLevelNodes); + break; + case 200: + var functionDeclaration = node; + if (isTopLevelFunctionDeclaration(functionDeclaration)) { + topLevelNodes.push(node); + addTopLevelNodes(functionDeclaration.body.statements, topLevelNodes); + } + break; + } + } + } + function isTopLevelFunctionDeclaration(functionDeclaration) { + if (functionDeclaration.kind === 200) { + if (functionDeclaration.body && functionDeclaration.body.kind === 179) { + if (ts.forEach(functionDeclaration.body.statements, function (s) { return s.kind === 200 && !isEmpty(s.name.text); })) { + return true; + } + if (!ts.isFunctionBlock(functionDeclaration.parent)) { + return true; + } + } + } + return false; + } + function getItemsWorker(nodes, createItem) { + var items = []; + var keyToItem = {}; + for (var _i = 0; _i < nodes.length; _i++) { + var child = nodes[_i]; + var item_1 = createItem(child); + if (item_1 !== undefined) { + if (item_1.text.length > 0) { + var key = item_1.text + "-" + item_1.kind + "-" + item_1.indent; + var itemWithSameName = keyToItem[key]; + if (itemWithSameName) { + merge(itemWithSameName, item_1); + } + else { + keyToItem[key] = item_1; + items.push(item_1); + } + } + } + } + return items; + } + function merge(target, source) { + target.spans.push.apply(target.spans, source.spans); + if (source.childItems) { + if (!target.childItems) { + target.childItems = []; + } + outer: for (var _i = 0, _a = source.childItems; _i < _a.length; _i++) { + var sourceChild = _a[_i]; + for (var _b = 0, _c = target.childItems; _b < _c.length; _b++) { + var targetChild = _c[_b]; + if (targetChild.text === sourceChild.text && targetChild.kind === sourceChild.kind) { + merge(targetChild, sourceChild); + continue outer; + } + } + target.childItems.push(sourceChild); + } + } + } + function createChildItem(node) { + switch (node.kind) { + case 129: + if (ts.isBindingPattern(node.name)) { + break; + } + if ((node.flags & 499) === 0) { + return undefined; + } + return createItem(node, getTextOfNode(node.name), ts.ScriptElementKind.memberVariableElement); + case 134: + case 133: + return createItem(node, getTextOfNode(node.name), ts.ScriptElementKind.memberFunctionElement); + case 136: + return createItem(node, getTextOfNode(node.name), ts.ScriptElementKind.memberGetAccessorElement); + case 137: + return createItem(node, getTextOfNode(node.name), ts.ScriptElementKind.memberSetAccessorElement); + case 140: + return createItem(node, "[]", ts.ScriptElementKind.indexSignatureElement); + case 226: + return createItem(node, getTextOfNode(node.name), ts.ScriptElementKind.memberVariableElement); + case 138: + return createItem(node, "()", ts.ScriptElementKind.callSignatureElement); + case 139: + return createItem(node, "new()", ts.ScriptElementKind.constructSignatureElement); + case 132: + case 131: + return createItem(node, getTextOfNode(node.name), ts.ScriptElementKind.memberVariableElement); + case 200: + return createItem(node, getTextOfNode(node.name), ts.ScriptElementKind.functionElement); + case 198: + case 152: + var variableDeclarationNode; + var name_1; + if (node.kind === 152) { + name_1 = node.name; + variableDeclarationNode = node; + while (variableDeclarationNode && variableDeclarationNode.kind !== 198) { + variableDeclarationNode = variableDeclarationNode.parent; + } + ts.Debug.assert(variableDeclarationNode !== undefined); + } + else { + ts.Debug.assert(!ts.isBindingPattern(node.name)); + variableDeclarationNode = node; + name_1 = node.name; + } + if (ts.isConst(variableDeclarationNode)) { + return createItem(node, getTextOfNode(name_1), ts.ScriptElementKind.constElement); + } + else if (ts.isLet(variableDeclarationNode)) { + return createItem(node, getTextOfNode(name_1), ts.ScriptElementKind.letElement); + } + else { + return createItem(node, getTextOfNode(name_1), ts.ScriptElementKind.variableElement); + } + case 135: + return createItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement); + case 217: + case 213: + case 208: + case 210: + case 211: + return createItem(node, getTextOfNode(node.name), ts.ScriptElementKind.alias); + } + return undefined; + function createItem(node, name, scriptElementKind) { + return getNavigationBarItem(name, scriptElementKind, ts.getNodeModifiers(node), [getNodeSpan(node)]); + } + } + function isEmpty(text) { + return !text || text.trim() === ""; + } + function getNavigationBarItem(text, kind, kindModifiers, spans, childItems, indent) { + if (childItems === void 0) { childItems = []; } + if (indent === void 0) { indent = 0; } + if (isEmpty(text)) { + return undefined; + } + return { + text: text, + kind: kind, + kindModifiers: kindModifiers, + spans: spans, + childItems: childItems, + indent: indent, + bolded: false, + grayed: false + }; + } + function createTopLevelItem(node) { + switch (node.kind) { + case 227: + return createSourceFileItem(node); + case 201: + return createClassItem(node); + case 204: + return createEnumItem(node); + case 202: + return createIterfaceItem(node); + case 205: + return createModuleItem(node); + case 200: + return createFunctionItem(node); + } + return undefined; + function getModuleName(moduleDeclaration) { + if (moduleDeclaration.name.kind === 8) { + return getTextOfNode(moduleDeclaration.name); + } + var result = []; + result.push(moduleDeclaration.name.text); + while (moduleDeclaration.body && moduleDeclaration.body.kind === 205) { + moduleDeclaration = moduleDeclaration.body; + result.push(moduleDeclaration.name.text); + } + return result.join("."); + } + function createModuleItem(node) { + var moduleName = getModuleName(node); + var childItems = getItemsWorker(getChildNodes(getInnermostModule(node).body.statements), createChildItem); + return getNavigationBarItem(moduleName, ts.ScriptElementKind.moduleElement, ts.getNodeModifiers(node), [getNodeSpan(node)], childItems, getIndent(node)); + } + function createFunctionItem(node) { + if (node.body && node.body.kind === 179) { + var childItems = getItemsWorker(sortNodes(node.body.statements), createChildItem); + return getNavigationBarItem(!node.name ? "default" : node.name.text, ts.ScriptElementKind.functionElement, ts.getNodeModifiers(node), [getNodeSpan(node)], childItems, getIndent(node)); + } + return undefined; + } + function createSourceFileItem(node) { + var childItems = getItemsWorker(getChildNodes(node.statements), createChildItem); + if (childItems === undefined || childItems.length === 0) { + return undefined; + } + hasGlobalNode = true; + var rootName = ts.isExternalModule(node) + ? "\"" + ts.escapeString(ts.getBaseFileName(ts.removeFileExtension(ts.normalizePath(node.fileName)))) + "\"" + : ""; + return getNavigationBarItem(rootName, ts.ScriptElementKind.moduleElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)], childItems); + } + function createClassItem(node) { + var childItems; + if (node.members) { + var constructor = ts.forEach(node.members, function (member) { + return member.kind === 135 && member; + }); + var nodes = removeDynamicallyNamedProperties(node); + if (constructor) { + nodes.push.apply(nodes, ts.filter(constructor.parameters, function (p) { return !ts.isBindingPattern(p.name); })); + } + childItems = getItemsWorker(sortNodes(nodes), createChildItem); + } + var nodeName = !node.name ? "default" : node.name.text; + return getNavigationBarItem(nodeName, ts.ScriptElementKind.classElement, ts.getNodeModifiers(node), [getNodeSpan(node)], childItems, getIndent(node)); + } + function createEnumItem(node) { + var childItems = getItemsWorker(sortNodes(removeComputedProperties(node)), createChildItem); + return getNavigationBarItem(node.name.text, ts.ScriptElementKind.enumElement, ts.getNodeModifiers(node), [getNodeSpan(node)], childItems, getIndent(node)); + } + function createIterfaceItem(node) { + var childItems = getItemsWorker(sortNodes(removeDynamicallyNamedProperties(node)), createChildItem); + return getNavigationBarItem(node.name.text, ts.ScriptElementKind.interfaceElement, ts.getNodeModifiers(node), [getNodeSpan(node)], childItems, getIndent(node)); + } + } + function removeComputedProperties(node) { + return ts.filter(node.members, function (member) { return member.name === undefined || member.name.kind !== 127; }); + } + function removeDynamicallyNamedProperties(node) { + return ts.filter(node.members, function (member) { return !ts.hasDynamicName(member); }); + } + function getInnermostModule(node) { + while (node.body.kind === 205) { + node = node.body; + } + return node; + } + function getNodeSpan(node) { + return node.kind === 227 + ? ts.createTextSpanFromBounds(node.getFullStart(), node.getEnd()) + : ts.createTextSpanFromBounds(node.getStart(), node.getEnd()); + } + function getTextOfNode(node) { + return ts.getTextOfNodeFromSourceText(sourceFile.text, node); + } + } + NavigationBar.getNavigationBarItems = getNavigationBarItems; + })(NavigationBar = ts.NavigationBar || (ts.NavigationBar = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/outliningElementsCollector.js b/dist/typescript/services/outliningElementsCollector.js new file mode 100644 index 000000000..ad0937543 --- /dev/null +++ b/dist/typescript/services/outliningElementsCollector.js @@ -0,0 +1,151 @@ +var ts; +(function (ts) { + var OutliningElementsCollector; + (function (OutliningElementsCollector) { + function collectElements(sourceFile) { + var elements = []; + var collapseText = "..."; + function addOutliningSpan(hintSpanNode, startElement, endElement, autoCollapse) { + if (hintSpanNode && startElement && endElement) { + var span = { + textSpan: ts.createTextSpanFromBounds(startElement.pos, endElement.end), + hintSpan: ts.createTextSpanFromBounds(hintSpanNode.getStart(), hintSpanNode.end), + bannerText: collapseText, + autoCollapse: autoCollapse + }; + elements.push(span); + } + } + function addOutliningSpanComments(commentSpan, autoCollapse) { + if (commentSpan) { + var span = { + textSpan: ts.createTextSpanFromBounds(commentSpan.pos, commentSpan.end), + hintSpan: ts.createTextSpanFromBounds(commentSpan.pos, commentSpan.end), + bannerText: collapseText, + autoCollapse: autoCollapse + }; + elements.push(span); + } + } + function addOutliningForLeadingCommentsForNode(n) { + var comments = ts.getLeadingCommentRangesOfNode(n, sourceFile); + if (comments) { + var firstSingleLineCommentStart = -1; + var lastSingleLineCommentEnd = -1; + var isFirstSingleLineComment = true; + var singleLineCommentCount = 0; + for (var _i = 0; _i < comments.length; _i++) { + var currentComment = comments[_i]; + if (currentComment.kind === 2) { + if (isFirstSingleLineComment) { + firstSingleLineCommentStart = currentComment.pos; + } + isFirstSingleLineComment = false; + lastSingleLineCommentEnd = currentComment.end; + singleLineCommentCount++; + } + else if (currentComment.kind === 3) { + combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); + addOutliningSpanComments(currentComment, false); + singleLineCommentCount = 0; + lastSingleLineCommentEnd = -1; + isFirstSingleLineComment = true; + } + } + combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); + } + } + function combineAndAddMultipleSingleLineComments(count, start, end) { + if (count > 1) { + var multipleSingleLineComments = { + pos: start, + end: end, + kind: 2 + }; + addOutliningSpanComments(multipleSingleLineComments, false); + } + } + function autoCollapse(node) { + return ts.isFunctionBlock(node) && node.parent.kind !== 163; + } + var depth = 0; + var maxDepth = 20; + function walk(n) { + if (depth > maxDepth) { + return; + } + if (ts.isDeclaration(n)) { + addOutliningForLeadingCommentsForNode(n); + } + switch (n.kind) { + case 179: + if (!ts.isFunctionBlock(n)) { + var parent_1 = n.parent; + var openBrace = ts.findChildOfKind(n, 14, sourceFile); + var closeBrace = ts.findChildOfKind(n, 15, sourceFile); + if (parent_1.kind === 184 || + parent_1.kind === 187 || + parent_1.kind === 188 || + parent_1.kind === 186 || + parent_1.kind === 183 || + parent_1.kind === 185 || + parent_1.kind === 192 || + parent_1.kind === 223) { + addOutliningSpan(parent_1, openBrace, closeBrace, autoCollapse(n)); + break; + } + if (parent_1.kind === 196) { + var tryStatement = parent_1; + if (tryStatement.tryBlock === n) { + addOutliningSpan(parent_1, openBrace, closeBrace, autoCollapse(n)); + break; + } + else if (tryStatement.finallyBlock === n) { + var finallyKeyword = ts.findChildOfKind(tryStatement, 81, sourceFile); + if (finallyKeyword) { + addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n)); + break; + } + } + } + var span = ts.createTextSpanFromBounds(n.getStart(), n.end); + elements.push({ + textSpan: span, + hintSpan: span, + bannerText: collapseText, + autoCollapse: autoCollapse(n) + }); + break; + } + case 206: { + var openBrace = ts.findChildOfKind(n, 14, sourceFile); + var closeBrace = ts.findChildOfKind(n, 15, sourceFile); + addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n)); + break; + } + case 201: + case 202: + case 204: + case 154: + case 207: { + var openBrace = ts.findChildOfKind(n, 14, sourceFile); + var closeBrace = ts.findChildOfKind(n, 15, sourceFile); + addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n)); + break; + } + case 153: + var openBracket = ts.findChildOfKind(n, 18, sourceFile); + var closeBracket = ts.findChildOfKind(n, 19, sourceFile); + addOutliningSpan(n, openBracket, closeBracket, autoCollapse(n)); + break; + } + depth++; + ts.forEachChild(n, walk); + depth--; + } + walk(sourceFile); + return elements; + } + OutliningElementsCollector.collectElements = collectElements; + })(OutliningElementsCollector = ts.OutliningElementsCollector || (ts.OutliningElementsCollector = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/patternMatcher.js b/dist/typescript/services/patternMatcher.js new file mode 100644 index 000000000..90774f4ff --- /dev/null +++ b/dist/typescript/services/patternMatcher.js @@ -0,0 +1,451 @@ +var ts; +(function (ts) { + (function (PatternMatchKind) { + PatternMatchKind[PatternMatchKind["exact"] = 0] = "exact"; + PatternMatchKind[PatternMatchKind["prefix"] = 1] = "prefix"; + PatternMatchKind[PatternMatchKind["substring"] = 2] = "substring"; + PatternMatchKind[PatternMatchKind["camelCase"] = 3] = "camelCase"; + })(ts.PatternMatchKind || (ts.PatternMatchKind = {})); + var PatternMatchKind = ts.PatternMatchKind; + function createPatternMatch(kind, punctuationStripped, isCaseSensitive, camelCaseWeight) { + return { + kind: kind, + punctuationStripped: punctuationStripped, + isCaseSensitive: isCaseSensitive, + camelCaseWeight: camelCaseWeight + }; + } + function createPatternMatcher(pattern) { + var stringToWordSpans = {}; + pattern = pattern.trim(); + var fullPatternSegment = createSegment(pattern); + var dotSeparatedSegments = pattern.split(".").map(function (p) { return createSegment(p.trim()); }); + var invalidPattern = dotSeparatedSegments.length === 0 || ts.forEach(dotSeparatedSegments, segmentIsInvalid); + return { + getMatches: getMatches, + getMatchesForLastSegmentOfPattern: getMatchesForLastSegmentOfPattern, + patternContainsDots: dotSeparatedSegments.length > 1 + }; + function skipMatch(candidate) { + return invalidPattern || !candidate; + } + function getMatchesForLastSegmentOfPattern(candidate) { + if (skipMatch(candidate)) { + return undefined; + } + return matchSegment(candidate, ts.lastOrUndefined(dotSeparatedSegments)); + } + function getMatches(candidateContainers, candidate) { + if (skipMatch(candidate)) { + return undefined; + } + var candidateMatch = matchSegment(candidate, ts.lastOrUndefined(dotSeparatedSegments)); + if (!candidateMatch) { + return undefined; + } + candidateContainers = candidateContainers || []; + if (dotSeparatedSegments.length - 1 > candidateContainers.length) { + return undefined; + } + var totalMatch = candidateMatch; + for (var i = dotSeparatedSegments.length - 2, j = candidateContainers.length - 1; i >= 0; i--, j--) { + var segment = dotSeparatedSegments[i]; + var containerName = candidateContainers[j]; + var containerMatch = matchSegment(containerName, segment); + if (!containerMatch) { + return undefined; + } + ts.addRange(totalMatch, containerMatch); + } + return totalMatch; + } + function getWordSpans(word) { + if (!ts.hasProperty(stringToWordSpans, word)) { + stringToWordSpans[word] = breakIntoWordSpans(word); + } + return stringToWordSpans[word]; + } + function matchTextChunk(candidate, chunk, punctuationStripped) { + var index = indexOfIgnoringCase(candidate, chunk.textLowerCase); + if (index === 0) { + if (chunk.text.length === candidate.length) { + return createPatternMatch(PatternMatchKind.exact, punctuationStripped, candidate === chunk.text); + } + else { + return createPatternMatch(PatternMatchKind.prefix, punctuationStripped, startsWith(candidate, chunk.text)); + } + } + var isLowercase = chunk.isLowerCase; + if (isLowercase) { + if (index > 0) { + var wordSpans = getWordSpans(candidate); + for (var _i = 0; _i < wordSpans.length; _i++) { + var span = wordSpans[_i]; + if (partStartsWith(candidate, span, chunk.text, true)) { + return createPatternMatch(PatternMatchKind.substring, punctuationStripped, partStartsWith(candidate, span, chunk.text, false)); + } + } + } + } + else { + if (candidate.indexOf(chunk.text) > 0) { + return createPatternMatch(PatternMatchKind.substring, punctuationStripped, true); + } + } + if (!isLowercase) { + if (chunk.characterSpans.length > 0) { + var candidateParts = getWordSpans(candidate); + var camelCaseWeight = tryCamelCaseMatch(candidate, candidateParts, chunk, false); + if (camelCaseWeight !== undefined) { + return createPatternMatch(PatternMatchKind.camelCase, punctuationStripped, true, camelCaseWeight); + } + camelCaseWeight = tryCamelCaseMatch(candidate, candidateParts, chunk, true); + if (camelCaseWeight !== undefined) { + return createPatternMatch(PatternMatchKind.camelCase, punctuationStripped, false, camelCaseWeight); + } + } + } + if (isLowercase) { + if (chunk.text.length < candidate.length) { + if (index > 0 && isUpperCaseLetter(candidate.charCodeAt(index))) { + return createPatternMatch(PatternMatchKind.substring, punctuationStripped, false); + } + } + } + return undefined; + } + function containsSpaceOrAsterisk(text) { + for (var i = 0; i < text.length; i++) { + var ch = text.charCodeAt(i); + if (ch === 32 || ch === 42) { + return true; + } + } + return false; + } + function matchSegment(candidate, segment) { + if (!containsSpaceOrAsterisk(segment.totalTextChunk.text)) { + var match = matchTextChunk(candidate, segment.totalTextChunk, false); + if (match) { + return [match]; + } + } + var subWordTextChunks = segment.subWordTextChunks; + var matches = undefined; + for (var _i = 0; _i < subWordTextChunks.length; _i++) { + var subWordTextChunk = subWordTextChunks[_i]; + var result = matchTextChunk(candidate, subWordTextChunk, true); + if (!result) { + return undefined; + } + matches = matches || []; + matches.push(result); + } + return matches; + } + function partStartsWith(candidate, candidateSpan, pattern, ignoreCase, patternSpan) { + var patternPartStart = patternSpan ? patternSpan.start : 0; + var patternPartLength = patternSpan ? patternSpan.length : pattern.length; + if (patternPartLength > candidateSpan.length) { + return false; + } + if (ignoreCase) { + for (var i = 0; i < patternPartLength; i++) { + var ch1 = pattern.charCodeAt(patternPartStart + i); + var ch2 = candidate.charCodeAt(candidateSpan.start + i); + if (toLowerCase(ch1) !== toLowerCase(ch2)) { + return false; + } + } + } + else { + for (var i = 0; i < patternPartLength; i++) { + var ch1 = pattern.charCodeAt(patternPartStart + i); + var ch2 = candidate.charCodeAt(candidateSpan.start + i); + if (ch1 !== ch2) { + return false; + } + } + } + return true; + } + function tryCamelCaseMatch(candidate, candidateParts, chunk, ignoreCase) { + var chunkCharacterSpans = chunk.characterSpans; + var currentCandidate = 0; + var currentChunkSpan = 0; + var firstMatch = undefined; + var contiguous = undefined; + while (true) { + if (currentChunkSpan === chunkCharacterSpans.length) { + var weight = 0; + if (contiguous) { + weight += 1; + } + if (firstMatch === 0) { + weight += 2; + } + return weight; + } + else if (currentCandidate === candidateParts.length) { + return undefined; + } + var candidatePart = candidateParts[currentCandidate]; + var gotOneMatchThisCandidate = false; + for (; currentChunkSpan < chunkCharacterSpans.length; currentChunkSpan++) { + var chunkCharacterSpan = chunkCharacterSpans[currentChunkSpan]; + if (gotOneMatchThisCandidate) { + if (!isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan - 1].start)) || + !isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan].start))) { + break; + } + } + if (!partStartsWith(candidate, candidatePart, chunk.text, ignoreCase, chunkCharacterSpan)) { + break; + } + gotOneMatchThisCandidate = true; + firstMatch = firstMatch === undefined ? currentCandidate : firstMatch; + contiguous = contiguous === undefined ? true : contiguous; + candidatePart = ts.createTextSpan(candidatePart.start + chunkCharacterSpan.length, candidatePart.length - chunkCharacterSpan.length); + } + if (!gotOneMatchThisCandidate && contiguous !== undefined) { + contiguous = false; + } + currentCandidate++; + } + } + } + ts.createPatternMatcher = createPatternMatcher; + function patternMatchCompareTo(match1, match2) { + return compareType(match1, match2) || + compareCamelCase(match1, match2) || + compareCase(match1, match2) || + comparePunctuation(match1, match2); + } + function comparePunctuation(result1, result2) { + if (result1.punctuationStripped !== result2.punctuationStripped) { + return result1.punctuationStripped ? 1 : -1; + } + return 0; + } + function compareCase(result1, result2) { + if (result1.isCaseSensitive !== result2.isCaseSensitive) { + return result1.isCaseSensitive ? -1 : 1; + } + return 0; + } + function compareType(result1, result2) { + return result1.kind - result2.kind; + } + function compareCamelCase(result1, result2) { + if (result1.kind === PatternMatchKind.camelCase && result2.kind === PatternMatchKind.camelCase) { + return result2.camelCaseWeight - result1.camelCaseWeight; + } + return 0; + } + function createSegment(text) { + return { + totalTextChunk: createTextChunk(text), + subWordTextChunks: breakPatternIntoTextChunks(text) + }; + } + function segmentIsInvalid(segment) { + return segment.subWordTextChunks.length === 0; + } + function isUpperCaseLetter(ch) { + if (ch >= 65 && ch <= 90) { + return true; + } + if (ch < 127 || !ts.isUnicodeIdentifierStart(ch, 2)) { + return false; + } + var str = String.fromCharCode(ch); + return str === str.toUpperCase(); + } + function isLowerCaseLetter(ch) { + if (ch >= 97 && ch <= 122) { + return true; + } + if (ch < 127 || !ts.isUnicodeIdentifierStart(ch, 2)) { + return false; + } + var str = String.fromCharCode(ch); + return str === str.toLowerCase(); + } + function containsUpperCaseLetter(string) { + for (var i = 0, n = string.length; i < n; i++) { + if (isUpperCaseLetter(string.charCodeAt(i))) { + return true; + } + } + return false; + } + function startsWith(string, search) { + for (var i = 0, n = search.length; i < n; i++) { + if (string.charCodeAt(i) !== search.charCodeAt(i)) { + return false; + } + } + return true; + } + function indexOfIgnoringCase(string, value) { + for (var i = 0, n = string.length - value.length; i <= n; i++) { + if (startsWithIgnoringCase(string, value, i)) { + return i; + } + } + return -1; + } + function startsWithIgnoringCase(string, value, start) { + for (var i = 0, n = value.length; i < n; i++) { + var ch1 = toLowerCase(string.charCodeAt(i + start)); + var ch2 = value.charCodeAt(i); + if (ch1 !== ch2) { + return false; + } + } + return true; + } + function toLowerCase(ch) { + if (ch >= 65 && ch <= 90) { + return 97 + (ch - 65); + } + if (ch < 127) { + return ch; + } + return String.fromCharCode(ch).toLowerCase().charCodeAt(0); + } + function isDigit(ch) { + return ch >= 48 && ch <= 57; + } + function isWordChar(ch) { + return isUpperCaseLetter(ch) || isLowerCaseLetter(ch) || isDigit(ch) || ch === 95 || ch === 36; + } + function breakPatternIntoTextChunks(pattern) { + var result = []; + var wordStart = 0; + var wordLength = 0; + for (var i = 0; i < pattern.length; i++) { + var ch = pattern.charCodeAt(i); + if (isWordChar(ch)) { + if (wordLength++ === 0) { + wordStart = i; + } + } + else { + if (wordLength > 0) { + result.push(createTextChunk(pattern.substr(wordStart, wordLength))); + wordLength = 0; + } + } + } + if (wordLength > 0) { + result.push(createTextChunk(pattern.substr(wordStart, wordLength))); + } + return result; + } + function createTextChunk(text) { + var textLowerCase = text.toLowerCase(); + return { + text: text, + textLowerCase: textLowerCase, + isLowerCase: text === textLowerCase, + characterSpans: breakIntoCharacterSpans(text) + }; + } + function breakIntoCharacterSpans(identifier) { + return breakIntoSpans(identifier, false); + } + ts.breakIntoCharacterSpans = breakIntoCharacterSpans; + function breakIntoWordSpans(identifier) { + return breakIntoSpans(identifier, true); + } + ts.breakIntoWordSpans = breakIntoWordSpans; + function breakIntoSpans(identifier, word) { + var result = []; + var wordStart = 0; + for (var i = 1, n = identifier.length; i < n; i++) { + var lastIsDigit = isDigit(identifier.charCodeAt(i - 1)); + var currentIsDigit = isDigit(identifier.charCodeAt(i)); + var hasTransitionFromLowerToUpper = transitionFromLowerToUpper(identifier, word, i); + var hasTransitionFromUpperToLower = transitionFromUpperToLower(identifier, word, i, wordStart); + if (charIsPunctuation(identifier.charCodeAt(i - 1)) || + charIsPunctuation(identifier.charCodeAt(i)) || + lastIsDigit != currentIsDigit || + hasTransitionFromLowerToUpper || + hasTransitionFromUpperToLower) { + if (!isAllPunctuation(identifier, wordStart, i)) { + result.push(ts.createTextSpan(wordStart, i - wordStart)); + } + wordStart = i; + } + } + if (!isAllPunctuation(identifier, wordStart, identifier.length)) { + result.push(ts.createTextSpan(wordStart, identifier.length - wordStart)); + } + return result; + } + function charIsPunctuation(ch) { + switch (ch) { + case 33: + case 34: + case 35: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 44: + case 45: + case 46: + case 47: + case 58: + case 59: + case 63: + case 64: + case 91: + case 92: + case 93: + case 95: + case 123: + case 125: + return true; + } + return false; + } + function isAllPunctuation(identifier, start, end) { + for (var i = start; i < end; i++) { + var ch = identifier.charCodeAt(i); + if (!charIsPunctuation(ch) || ch === 95 || ch === 36) { + return false; + } + } + return true; + } + function transitionFromUpperToLower(identifier, word, index, wordStart) { + if (word) { + if (index != wordStart && + index + 1 < identifier.length) { + var currentIsUpper = isUpperCaseLetter(identifier.charCodeAt(index)); + var nextIsLower = isLowerCaseLetter(identifier.charCodeAt(index + 1)); + if (currentIsUpper && nextIsLower) { + for (var i = wordStart; i < index; i++) { + if (!isUpperCaseLetter(identifier.charCodeAt(i))) { + return false; + } + } + return true; + } + } + } + return false; + } + function transitionFromLowerToUpper(identifier, word, index) { + var lastIsUpper = isUpperCaseLetter(identifier.charCodeAt(index - 1)); + var currentIsUpper = isUpperCaseLetter(identifier.charCodeAt(index)); + var transition = word + ? (currentIsUpper && !lastIsUpper) + : currentIsUpper; + return transition; + } +})(ts || (ts = {})); diff --git a/dist/typescript/services/services.js b/dist/typescript/services/services.js new file mode 100644 index 000000000..df6112b53 --- /dev/null +++ b/dist/typescript/services/services.js @@ -0,0 +1,4804 @@ +/// +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +/// +/// +/// +/// +/// +/// +/// +/// +/// +var ts; +(function (ts) { + ts.servicesVersion = "0.4"; + var ScriptSnapshot; + (function (ScriptSnapshot) { + var StringScriptSnapshot = (function () { + function StringScriptSnapshot(text) { + this.text = text; + this._lineStartPositions = undefined; + } + StringScriptSnapshot.prototype.getText = function (start, end) { + return this.text.substring(start, end); + }; + StringScriptSnapshot.prototype.getLength = function () { + return this.text.length; + }; + StringScriptSnapshot.prototype.getChangeRange = function (oldSnapshot) { + return undefined; + }; + return StringScriptSnapshot; + })(); + function fromString(text) { + return new StringScriptSnapshot(text); + } + ScriptSnapshot.fromString = fromString; + })(ScriptSnapshot = ts.ScriptSnapshot || (ts.ScriptSnapshot = {})); + var scanner = ts.createScanner(2, true); + var emptyArray = []; + function createNode(kind, pos, end, flags, parent) { + var node = new (ts.getNodeConstructor(kind))(); + node.pos = pos; + node.end = end; + node.flags = flags; + node.parent = parent; + return node; + } + var NodeObject = (function () { + function NodeObject() { + } + NodeObject.prototype.getSourceFile = function () { + return ts.getSourceFileOfNode(this); + }; + NodeObject.prototype.getStart = function (sourceFile) { + return ts.getTokenPosOfNode(this, sourceFile); + }; + NodeObject.prototype.getFullStart = function () { + return this.pos; + }; + NodeObject.prototype.getEnd = function () { + return this.end; + }; + NodeObject.prototype.getWidth = function (sourceFile) { + return this.getEnd() - this.getStart(sourceFile); + }; + NodeObject.prototype.getFullWidth = function () { + return this.end - this.getFullStart(); + }; + NodeObject.prototype.getLeadingTriviaWidth = function (sourceFile) { + return this.getStart(sourceFile) - this.pos; + }; + NodeObject.prototype.getFullText = function (sourceFile) { + return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end); + }; + NodeObject.prototype.getText = function (sourceFile) { + return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd()); + }; + NodeObject.prototype.addSyntheticNodes = function (nodes, pos, end) { + scanner.setTextPos(pos); + while (pos < end) { + var token = scanner.scan(); + var textPos = scanner.getTextPos(); + nodes.push(createNode(token, pos, textPos, 1024, this)); + pos = textPos; + } + return pos; + }; + NodeObject.prototype.createSyntaxList = function (nodes) { + var list = createNode(228, nodes.pos, nodes.end, 1024, this); + list._children = []; + var pos = nodes.pos; + for (var _i = 0; _i < nodes.length; _i++) { + var node = nodes[_i]; + if (pos < node.pos) { + pos = this.addSyntheticNodes(list._children, pos, node.pos); + } + list._children.push(node); + pos = node.end; + } + if (pos < nodes.end) { + this.addSyntheticNodes(list._children, pos, nodes.end); + } + return list; + }; + NodeObject.prototype.createChildren = function (sourceFile) { + var _this = this; + var children; + if (this.kind >= 126) { + scanner.setText((sourceFile || this.getSourceFile()).text); + children = []; + var pos = this.pos; + var processNode = function (node) { + if (pos < node.pos) { + pos = _this.addSyntheticNodes(children, pos, node.pos); + } + children.push(node); + pos = node.end; + }; + var processNodes = function (nodes) { + if (pos < nodes.pos) { + pos = _this.addSyntheticNodes(children, pos, nodes.pos); + } + children.push(_this.createSyntaxList(nodes)); + pos = nodes.end; + }; + ts.forEachChild(this, processNode, processNodes); + if (pos < this.end) { + this.addSyntheticNodes(children, pos, this.end); + } + scanner.setText(undefined); + } + this._children = children || emptyArray; + }; + NodeObject.prototype.getChildCount = function (sourceFile) { + if (!this._children) + this.createChildren(sourceFile); + return this._children.length; + }; + NodeObject.prototype.getChildAt = function (index, sourceFile) { + if (!this._children) + this.createChildren(sourceFile); + return this._children[index]; + }; + NodeObject.prototype.getChildren = function (sourceFile) { + if (!this._children) + this.createChildren(sourceFile); + return this._children; + }; + NodeObject.prototype.getFirstToken = function (sourceFile) { + var children = this.getChildren(); + for (var _i = 0; _i < children.length; _i++) { + var child = children[_i]; + if (child.kind < 126) { + return child; + } + return child.getFirstToken(sourceFile); + } + }; + NodeObject.prototype.getLastToken = function (sourceFile) { + var children = this.getChildren(sourceFile); + for (var i = children.length - 1; i >= 0; i--) { + var child = children[i]; + if (child.kind < 126) { + return child; + } + return child.getLastToken(sourceFile); + } + }; + return NodeObject; + })(); + var SymbolObject = (function () { + function SymbolObject(flags, name) { + this.flags = flags; + this.name = name; + } + SymbolObject.prototype.getFlags = function () { + return this.flags; + }; + SymbolObject.prototype.getName = function () { + return this.name; + }; + SymbolObject.prototype.getDeclarations = function () { + return this.declarations; + }; + SymbolObject.prototype.getDocumentationComment = function () { + if (this.documentationComment === undefined) { + this.documentationComment = getJsDocCommentsFromDeclarations(this.declarations, this.name, !(this.flags & 4)); + } + return this.documentationComment; + }; + return SymbolObject; + })(); + function getJsDocCommentsFromDeclarations(declarations, name, canUseParsedParamTagComments) { + var documentationComment = []; + var docComments = getJsDocCommentsSeparatedByNewLines(); + ts.forEach(docComments, function (docComment) { + if (documentationComment.length) { + documentationComment.push(ts.lineBreakPart()); + } + documentationComment.push(docComment); + }); + return documentationComment; + function getJsDocCommentsSeparatedByNewLines() { + var paramTag = "@param"; + var jsDocCommentParts = []; + ts.forEach(declarations, function (declaration, indexOfDeclaration) { + if (ts.indexOf(declarations, declaration) === indexOfDeclaration) { + var sourceFileOfDeclaration = ts.getSourceFileOfNode(declaration); + if (canUseParsedParamTagComments && declaration.kind === 129) { + ts.forEach(getJsDocCommentTextRange(declaration.parent, sourceFileOfDeclaration), function (jsDocCommentTextRange) { + var cleanedParamJsDocComment = getCleanedParamJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration); + if (cleanedParamJsDocComment) { + jsDocCommentParts.push.apply(jsDocCommentParts, cleanedParamJsDocComment); + } + }); + } + if (declaration.kind === 205 && declaration.body.kind === 205) { + return; + } + while (declaration.kind === 205 && declaration.parent.kind === 205) { + declaration = declaration.parent; + } + ts.forEach(getJsDocCommentTextRange(declaration.kind === 198 ? declaration.parent.parent : declaration, sourceFileOfDeclaration), function (jsDocCommentTextRange) { + var cleanedJsDocComment = getCleanedJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration); + if (cleanedJsDocComment) { + jsDocCommentParts.push.apply(jsDocCommentParts, cleanedJsDocComment); + } + }); + } + }); + return jsDocCommentParts; + function getJsDocCommentTextRange(node, sourceFile) { + return ts.map(ts.getJsDocComments(node, sourceFile), function (jsDocComment) { + return { + pos: jsDocComment.pos + "/*".length, + end: jsDocComment.end - "*/".length + }; + }); + } + function consumeWhiteSpacesOnTheLine(pos, end, sourceFile, maxSpacesToRemove) { + if (maxSpacesToRemove !== undefined) { + end = Math.min(end, pos + maxSpacesToRemove); + } + for (; pos < end; pos++) { + var ch = sourceFile.text.charCodeAt(pos); + if (!ts.isWhiteSpace(ch) || ts.isLineBreak(ch)) { + return pos; + } + } + return end; + } + function consumeLineBreaks(pos, end, sourceFile) { + while (pos < end && ts.isLineBreak(sourceFile.text.charCodeAt(pos))) { + pos++; + } + return pos; + } + function isName(pos, end, sourceFile, name) { + return pos + name.length < end && + sourceFile.text.substr(pos, name.length) === name && + (ts.isWhiteSpace(sourceFile.text.charCodeAt(pos + name.length)) || + ts.isLineBreak(sourceFile.text.charCodeAt(pos + name.length))); + } + function isParamTag(pos, end, sourceFile) { + return isName(pos, end, sourceFile, paramTag); + } + function pushDocCommentLineText(docComments, text, blankLineCount) { + while (blankLineCount--) { + docComments.push(ts.textPart("")); + } + docComments.push(ts.textPart(text)); + } + function getCleanedJsDocComment(pos, end, sourceFile) { + var spacesToRemoveAfterAsterisk; + var docComments = []; + var blankLineCount = 0; + var isInParamTag = false; + while (pos < end) { + var docCommentTextOfLine = ""; + pos = consumeWhiteSpacesOnTheLine(pos, end, sourceFile); + if (pos < end && sourceFile.text.charCodeAt(pos) === 42) { + var lineStartPos = pos + 1; + pos = consumeWhiteSpacesOnTheLine(pos + 1, end, sourceFile, spacesToRemoveAfterAsterisk); + if (spacesToRemoveAfterAsterisk === undefined && pos < end && !ts.isLineBreak(sourceFile.text.charCodeAt(pos))) { + spacesToRemoveAfterAsterisk = pos - lineStartPos; + } + } + else if (spacesToRemoveAfterAsterisk === undefined) { + spacesToRemoveAfterAsterisk = 0; + } + while (pos < end && !ts.isLineBreak(sourceFile.text.charCodeAt(pos))) { + var ch = sourceFile.text.charAt(pos); + if (ch === "@") { + if (isParamTag(pos, end, sourceFile)) { + isInParamTag = true; + pos += paramTag.length; + continue; + } + else { + isInParamTag = false; + } + } + if (!isInParamTag) { + docCommentTextOfLine += ch; + } + pos++; + } + pos = consumeLineBreaks(pos, end, sourceFile); + if (docCommentTextOfLine) { + pushDocCommentLineText(docComments, docCommentTextOfLine, blankLineCount); + blankLineCount = 0; + } + else if (!isInParamTag && docComments.length) { + blankLineCount++; + } + } + return docComments; + } + function getCleanedParamJsDocComment(pos, end, sourceFile) { + var paramHelpStringMargin; + var paramDocComments = []; + while (pos < end) { + if (isParamTag(pos, end, sourceFile)) { + var blankLineCount = 0; + var recordedParamTag = false; + pos = consumeWhiteSpaces(pos + paramTag.length); + if (pos >= end) { + break; + } + if (sourceFile.text.charCodeAt(pos) === 123) { + pos++; + for (var curlies = 1; pos < end; pos++) { + var charCode = sourceFile.text.charCodeAt(pos); + if (charCode === 123) { + curlies++; + continue; + } + if (charCode === 125) { + curlies--; + if (curlies === 0) { + pos++; + break; + } + else { + continue; + } + } + if (charCode === 64) { + break; + } + } + pos = consumeWhiteSpaces(pos); + if (pos >= end) { + break; + } + } + if (isName(pos, end, sourceFile, name)) { + pos = consumeWhiteSpaces(pos + name.length); + if (pos >= end) { + break; + } + var paramHelpString = ""; + var firstLineParamHelpStringPos = pos; + while (pos < end) { + var ch = sourceFile.text.charCodeAt(pos); + if (ts.isLineBreak(ch)) { + if (paramHelpString) { + pushDocCommentLineText(paramDocComments, paramHelpString, blankLineCount); + paramHelpString = ""; + blankLineCount = 0; + recordedParamTag = true; + } + else if (recordedParamTag) { + blankLineCount++; + } + setPosForParamHelpStringOnNextLine(firstLineParamHelpStringPos); + continue; + } + if (ch === 64) { + break; + } + paramHelpString += sourceFile.text.charAt(pos); + pos++; + } + if (paramHelpString) { + pushDocCommentLineText(paramDocComments, paramHelpString, blankLineCount); + } + paramHelpStringMargin = undefined; + } + if (sourceFile.text.charCodeAt(pos) === 64) { + continue; + } + } + pos++; + } + return paramDocComments; + function consumeWhiteSpaces(pos) { + while (pos < end && ts.isWhiteSpace(sourceFile.text.charCodeAt(pos))) { + pos++; + } + return pos; + } + function setPosForParamHelpStringOnNextLine(firstLineParamHelpStringPos) { + pos = consumeLineBreaks(pos, end, sourceFile); + if (pos >= end) { + return; + } + if (paramHelpStringMargin === undefined) { + paramHelpStringMargin = sourceFile.getLineAndCharacterOfPosition(firstLineParamHelpStringPos).character; + } + var startOfLinePos = pos; + pos = consumeWhiteSpacesOnTheLine(pos, end, sourceFile, paramHelpStringMargin); + if (pos >= end) { + return; + } + var consumedSpaces = pos - startOfLinePos; + if (consumedSpaces < paramHelpStringMargin) { + var ch = sourceFile.text.charCodeAt(pos); + if (ch === 42) { + pos = consumeWhiteSpacesOnTheLine(pos + 1, end, sourceFile, paramHelpStringMargin - consumedSpaces - 1); + } + } + } + } + } + } + var TypeObject = (function () { + function TypeObject(checker, flags) { + this.checker = checker; + this.flags = flags; + } + TypeObject.prototype.getFlags = function () { + return this.flags; + }; + TypeObject.prototype.getSymbol = function () { + return this.symbol; + }; + TypeObject.prototype.getProperties = function () { + return this.checker.getPropertiesOfType(this); + }; + TypeObject.prototype.getProperty = function (propertyName) { + return this.checker.getPropertyOfType(this, propertyName); + }; + TypeObject.prototype.getApparentProperties = function () { + return this.checker.getAugmentedPropertiesOfType(this); + }; + TypeObject.prototype.getCallSignatures = function () { + return this.checker.getSignaturesOfType(this, 0); + }; + TypeObject.prototype.getConstructSignatures = function () { + return this.checker.getSignaturesOfType(this, 1); + }; + TypeObject.prototype.getStringIndexType = function () { + return this.checker.getIndexTypeOfType(this, 0); + }; + TypeObject.prototype.getNumberIndexType = function () { + return this.checker.getIndexTypeOfType(this, 1); + }; + return TypeObject; + })(); + var SignatureObject = (function () { + function SignatureObject(checker) { + this.checker = checker; + } + SignatureObject.prototype.getDeclaration = function () { + return this.declaration; + }; + SignatureObject.prototype.getTypeParameters = function () { + return this.typeParameters; + }; + SignatureObject.prototype.getParameters = function () { + return this.parameters; + }; + SignatureObject.prototype.getReturnType = function () { + return this.checker.getReturnTypeOfSignature(this); + }; + SignatureObject.prototype.getDocumentationComment = function () { + if (this.documentationComment === undefined) { + this.documentationComment = this.declaration ? getJsDocCommentsFromDeclarations([this.declaration], undefined, false) : []; + } + return this.documentationComment; + }; + return SignatureObject; + })(); + var SourceFileObject = (function (_super) { + __extends(SourceFileObject, _super); + function SourceFileObject() { + _super.apply(this, arguments); + } + SourceFileObject.prototype.update = function (newText, textChangeRange) { + return ts.updateSourceFile(this, newText, textChangeRange); + }; + SourceFileObject.prototype.getLineAndCharacterOfPosition = function (position) { + return ts.getLineAndCharacterOfPosition(this, position); + }; + SourceFileObject.prototype.getLineStarts = function () { + return ts.getLineStarts(this); + }; + SourceFileObject.prototype.getPositionOfLineAndCharacter = function (line, character) { + return ts.getPositionOfLineAndCharacter(this, line, character); + }; + SourceFileObject.prototype.getNamedDeclarations = function () { + if (!this.namedDeclarations) { + this.namedDeclarations = this.computeNamedDeclarations(); + } + return this.namedDeclarations; + }; + SourceFileObject.prototype.computeNamedDeclarations = function () { + var result = {}; + ts.forEachChild(this, visit); + return result; + function addDeclaration(declaration) { + var name = getDeclarationName(declaration); + if (name) { + var declarations = getDeclarations(name); + declarations.push(declaration); + } + } + function getDeclarations(name) { + return ts.getProperty(result, name) || (result[name] = []); + } + function getDeclarationName(declaration) { + if (declaration.name) { + var result_1 = getTextOfIdentifierOrLiteral(declaration.name); + if (result_1 !== undefined) { + return result_1; + } + if (declaration.name.kind === 127) { + var expr = declaration.name.expression; + if (expr.kind === 155) { + return expr.name.text; + } + return getTextOfIdentifierOrLiteral(expr); + } + } + return undefined; + } + function getTextOfIdentifierOrLiteral(node) { + if (node) { + if (node.kind === 65 || + node.kind === 8 || + node.kind === 7) { + return node.text; + } + } + return undefined; + } + function visit(node) { + switch (node.kind) { + case 200: + case 134: + case 133: + var functionDeclaration = node; + var declarationName = getDeclarationName(functionDeclaration); + if (declarationName) { + var declarations = getDeclarations(declarationName); + var lastDeclaration = ts.lastOrUndefined(declarations); + if (lastDeclaration && functionDeclaration.parent === lastDeclaration.parent && functionDeclaration.symbol === lastDeclaration.symbol) { + if (functionDeclaration.body && !lastDeclaration.body) { + declarations[declarations.length - 1] = functionDeclaration; + } + } + else { + declarations.push(functionDeclaration); + } + ts.forEachChild(node, visit); + } + break; + case 201: + case 202: + case 203: + case 204: + case 205: + case 208: + case 217: + case 213: + case 208: + case 210: + case 211: + case 136: + case 137: + case 145: + addDeclaration(node); + case 135: + case 180: + case 199: + case 150: + case 151: + case 206: + ts.forEachChild(node, visit); + break; + case 179: + if (ts.isFunctionBlock(node)) { + ts.forEachChild(node, visit); + } + break; + case 129: + if (!(node.flags & 112)) { + break; + } + case 198: + case 152: + if (ts.isBindingPattern(node.name)) { + ts.forEachChild(node.name, visit); + break; + } + case 226: + case 132: + case 131: + addDeclaration(node); + break; + case 215: + if (node.exportClause) { + ts.forEach(node.exportClause.elements, visit); + } + break; + case 209: + var importClause = node.importClause; + if (importClause) { + if (importClause.name) { + addDeclaration(importClause); + } + if (importClause.namedBindings) { + if (importClause.namedBindings.kind === 211) { + addDeclaration(importClause.namedBindings); + } + else { + ts.forEach(importClause.namedBindings.elements, visit); + } + } + } + break; + } + } + }; + return SourceFileObject; + })(NodeObject); + var TextChange = (function () { + function TextChange() { + } + return TextChange; + })(); + ts.TextChange = TextChange; + var HighlightSpanKind; + (function (HighlightSpanKind) { + HighlightSpanKind.none = "none"; + HighlightSpanKind.definition = "definition"; + HighlightSpanKind.reference = "reference"; + HighlightSpanKind.writtenReference = "writtenReference"; + })(HighlightSpanKind = ts.HighlightSpanKind || (ts.HighlightSpanKind = {})); + (function (SymbolDisplayPartKind) { + SymbolDisplayPartKind[SymbolDisplayPartKind["aliasName"] = 0] = "aliasName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["className"] = 1] = "className"; + SymbolDisplayPartKind[SymbolDisplayPartKind["enumName"] = 2] = "enumName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["fieldName"] = 3] = "fieldName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["interfaceName"] = 4] = "interfaceName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["keyword"] = 5] = "keyword"; + SymbolDisplayPartKind[SymbolDisplayPartKind["lineBreak"] = 6] = "lineBreak"; + SymbolDisplayPartKind[SymbolDisplayPartKind["numericLiteral"] = 7] = "numericLiteral"; + SymbolDisplayPartKind[SymbolDisplayPartKind["stringLiteral"] = 8] = "stringLiteral"; + SymbolDisplayPartKind[SymbolDisplayPartKind["localName"] = 9] = "localName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["methodName"] = 10] = "methodName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["moduleName"] = 11] = "moduleName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["operator"] = 12] = "operator"; + SymbolDisplayPartKind[SymbolDisplayPartKind["parameterName"] = 13] = "parameterName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["propertyName"] = 14] = "propertyName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["punctuation"] = 15] = "punctuation"; + SymbolDisplayPartKind[SymbolDisplayPartKind["space"] = 16] = "space"; + SymbolDisplayPartKind[SymbolDisplayPartKind["text"] = 17] = "text"; + SymbolDisplayPartKind[SymbolDisplayPartKind["typeParameterName"] = 18] = "typeParameterName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["enumMemberName"] = 19] = "enumMemberName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["functionName"] = 20] = "functionName"; + SymbolDisplayPartKind[SymbolDisplayPartKind["regularExpressionLiteral"] = 21] = "regularExpressionLiteral"; + })(ts.SymbolDisplayPartKind || (ts.SymbolDisplayPartKind = {})); + var SymbolDisplayPartKind = ts.SymbolDisplayPartKind; + (function (OutputFileType) { + OutputFileType[OutputFileType["JavaScript"] = 0] = "JavaScript"; + OutputFileType[OutputFileType["SourceMap"] = 1] = "SourceMap"; + OutputFileType[OutputFileType["Declaration"] = 2] = "Declaration"; + })(ts.OutputFileType || (ts.OutputFileType = {})); + var OutputFileType = ts.OutputFileType; + (function (EndOfLineState) { + EndOfLineState[EndOfLineState["Start"] = 0] = "Start"; + EndOfLineState[EndOfLineState["InMultiLineCommentTrivia"] = 1] = "InMultiLineCommentTrivia"; + EndOfLineState[EndOfLineState["InSingleQuoteStringLiteral"] = 2] = "InSingleQuoteStringLiteral"; + EndOfLineState[EndOfLineState["InDoubleQuoteStringLiteral"] = 3] = "InDoubleQuoteStringLiteral"; + EndOfLineState[EndOfLineState["InTemplateHeadOrNoSubstitutionTemplate"] = 4] = "InTemplateHeadOrNoSubstitutionTemplate"; + EndOfLineState[EndOfLineState["InTemplateMiddleOrTail"] = 5] = "InTemplateMiddleOrTail"; + EndOfLineState[EndOfLineState["InTemplateSubstitutionPosition"] = 6] = "InTemplateSubstitutionPosition"; + })(ts.EndOfLineState || (ts.EndOfLineState = {})); + var EndOfLineState = ts.EndOfLineState; + (function (TokenClass) { + TokenClass[TokenClass["Punctuation"] = 0] = "Punctuation"; + TokenClass[TokenClass["Keyword"] = 1] = "Keyword"; + TokenClass[TokenClass["Operator"] = 2] = "Operator"; + TokenClass[TokenClass["Comment"] = 3] = "Comment"; + TokenClass[TokenClass["Whitespace"] = 4] = "Whitespace"; + TokenClass[TokenClass["Identifier"] = 5] = "Identifier"; + TokenClass[TokenClass["NumberLiteral"] = 6] = "NumberLiteral"; + TokenClass[TokenClass["StringLiteral"] = 7] = "StringLiteral"; + TokenClass[TokenClass["RegExpLiteral"] = 8] = "RegExpLiteral"; + })(ts.TokenClass || (ts.TokenClass = {})); + var TokenClass = ts.TokenClass; + var ScriptElementKind; + (function (ScriptElementKind) { + ScriptElementKind.unknown = ""; + ScriptElementKind.warning = "warning"; + ScriptElementKind.keyword = "keyword"; + ScriptElementKind.scriptElement = "script"; + ScriptElementKind.moduleElement = "module"; + ScriptElementKind.classElement = "class"; + ScriptElementKind.interfaceElement = "interface"; + ScriptElementKind.typeElement = "type"; + ScriptElementKind.enumElement = "enum"; + ScriptElementKind.variableElement = "var"; + ScriptElementKind.localVariableElement = "local var"; + ScriptElementKind.functionElement = "function"; + ScriptElementKind.localFunctionElement = "local function"; + ScriptElementKind.memberFunctionElement = "method"; + ScriptElementKind.memberGetAccessorElement = "getter"; + ScriptElementKind.memberSetAccessorElement = "setter"; + ScriptElementKind.memberVariableElement = "property"; + ScriptElementKind.constructorImplementationElement = "constructor"; + ScriptElementKind.callSignatureElement = "call"; + ScriptElementKind.indexSignatureElement = "index"; + ScriptElementKind.constructSignatureElement = "construct"; + ScriptElementKind.parameterElement = "parameter"; + ScriptElementKind.typeParameterElement = "type parameter"; + ScriptElementKind.primitiveType = "primitive type"; + ScriptElementKind.label = "label"; + ScriptElementKind.alias = "alias"; + ScriptElementKind.constElement = "const"; + ScriptElementKind.letElement = "let"; + })(ScriptElementKind = ts.ScriptElementKind || (ts.ScriptElementKind = {})); + var ScriptElementKindModifier; + (function (ScriptElementKindModifier) { + ScriptElementKindModifier.none = ""; + ScriptElementKindModifier.publicMemberModifier = "public"; + ScriptElementKindModifier.privateMemberModifier = "private"; + ScriptElementKindModifier.protectedMemberModifier = "protected"; + ScriptElementKindModifier.exportedModifier = "export"; + ScriptElementKindModifier.ambientModifier = "declare"; + ScriptElementKindModifier.staticModifier = "static"; + })(ScriptElementKindModifier = ts.ScriptElementKindModifier || (ts.ScriptElementKindModifier = {})); + var ClassificationTypeNames = (function () { + function ClassificationTypeNames() { + } + ClassificationTypeNames.comment = "comment"; + ClassificationTypeNames.identifier = "identifier"; + ClassificationTypeNames.keyword = "keyword"; + ClassificationTypeNames.numericLiteral = "number"; + ClassificationTypeNames.operator = "operator"; + ClassificationTypeNames.stringLiteral = "string"; + ClassificationTypeNames.whiteSpace = "whitespace"; + ClassificationTypeNames.text = "text"; + ClassificationTypeNames.punctuation = "punctuation"; + ClassificationTypeNames.className = "class name"; + ClassificationTypeNames.enumName = "enum name"; + ClassificationTypeNames.interfaceName = "interface name"; + ClassificationTypeNames.moduleName = "module name"; + ClassificationTypeNames.typeParameterName = "type parameter name"; + ClassificationTypeNames.typeAlias = "type alias name"; + return ClassificationTypeNames; + })(); + ts.ClassificationTypeNames = ClassificationTypeNames; + function displayPartsToString(displayParts) { + if (displayParts) { + return ts.map(displayParts, function (displayPart) { return displayPart.text; }).join(""); + } + return ""; + } + ts.displayPartsToString = displayPartsToString; + function isLocalVariableOrFunction(symbol) { + if (symbol.parent) { + return false; + } + return ts.forEach(symbol.declarations, function (declaration) { + if (declaration.kind === 162) { + return true; + } + if (declaration.kind !== 198 && declaration.kind !== 200) { + return false; + } + for (var parent_1 = declaration.parent; !ts.isFunctionBlock(parent_1); parent_1 = parent_1.parent) { + if (parent_1.kind === 227 || parent_1.kind === 206) { + return false; + } + } + return true; + }); + } + function getDefaultCompilerOptions() { + return { + target: 1, + module: 0, + }; + } + ts.getDefaultCompilerOptions = getDefaultCompilerOptions; + var OperationCanceledException = (function () { + function OperationCanceledException() { + } + return OperationCanceledException; + })(); + ts.OperationCanceledException = OperationCanceledException; + var CancellationTokenObject = (function () { + function CancellationTokenObject(cancellationToken) { + this.cancellationToken = cancellationToken; + } + CancellationTokenObject.prototype.isCancellationRequested = function () { + return this.cancellationToken && this.cancellationToken.isCancellationRequested(); + }; + CancellationTokenObject.prototype.throwIfCancellationRequested = function () { + if (this.isCancellationRequested()) { + throw new OperationCanceledException(); + } + }; + CancellationTokenObject.None = new CancellationTokenObject(null); + return CancellationTokenObject; + })(); + ts.CancellationTokenObject = CancellationTokenObject; + var HostCache = (function () { + function HostCache(host) { + this.host = host; + this.fileNameToEntry = {}; + var rootFileNames = host.getScriptFileNames(); + for (var _i = 0; _i < rootFileNames.length; _i++) { + var fileName = rootFileNames[_i]; + this.createEntry(fileName); + } + this._compilationSettings = host.getCompilationSettings() || getDefaultCompilerOptions(); + } + HostCache.prototype.compilationSettings = function () { + return this._compilationSettings; + }; + HostCache.prototype.createEntry = function (fileName) { + var entry; + var scriptSnapshot = this.host.getScriptSnapshot(fileName); + if (scriptSnapshot) { + entry = { + hostFileName: fileName, + version: this.host.getScriptVersion(fileName), + scriptSnapshot: scriptSnapshot + }; + } + return this.fileNameToEntry[ts.normalizeSlashes(fileName)] = entry; + }; + HostCache.prototype.getEntry = function (fileName) { + return ts.lookUp(this.fileNameToEntry, ts.normalizeSlashes(fileName)); + }; + HostCache.prototype.contains = function (fileName) { + return ts.hasProperty(this.fileNameToEntry, ts.normalizeSlashes(fileName)); + }; + HostCache.prototype.getOrCreateEntry = function (fileName) { + if (this.contains(fileName)) { + return this.getEntry(fileName); + } + return this.createEntry(fileName); + }; + HostCache.prototype.getRootFileNames = function () { + var _this = this; + var fileNames = []; + ts.forEachKey(this.fileNameToEntry, function (key) { + if (ts.hasProperty(_this.fileNameToEntry, key) && _this.fileNameToEntry[key]) + fileNames.push(key); + }); + return fileNames; + }; + HostCache.prototype.getVersion = function (fileName) { + var file = this.getEntry(fileName); + return file && file.version; + }; + HostCache.prototype.getScriptSnapshot = function (fileName) { + var file = this.getEntry(fileName); + return file && file.scriptSnapshot; + }; + return HostCache; + })(); + var SyntaxTreeCache = (function () { + function SyntaxTreeCache(host) { + this.host = host; + } + SyntaxTreeCache.prototype.getCurrentSourceFile = function (fileName) { + var scriptSnapshot = this.host.getScriptSnapshot(fileName); + if (!scriptSnapshot) { + throw new Error("Could not find file: '" + fileName + "'."); + } + var version = this.host.getScriptVersion(fileName); + var sourceFile; + if (this.currentFileName !== fileName) { + sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, 2, version, true); + } + else if (this.currentFileVersion !== version) { + var editRange = scriptSnapshot.getChangeRange(this.currentFileScriptSnapshot); + sourceFile = updateLanguageServiceSourceFile(this.currentSourceFile, scriptSnapshot, version, editRange); + } + if (sourceFile) { + this.currentFileVersion = version; + this.currentFileName = fileName; + this.currentFileScriptSnapshot = scriptSnapshot; + this.currentSourceFile = sourceFile; + } + return this.currentSourceFile; + }; + return SyntaxTreeCache; + })(); + function setSourceFileFields(sourceFile, scriptSnapshot, version) { + sourceFile.version = version; + sourceFile.scriptSnapshot = scriptSnapshot; + } + function transpile(input, compilerOptions, fileName, diagnostics) { + var options = compilerOptions ? ts.clone(compilerOptions) : getDefaultCompilerOptions(); + options.separateCompilation = true; + options.allowNonTsExtensions = true; + var inputFileName = fileName || "module.ts"; + var sourceFile = ts.createSourceFile(inputFileName, input, options.target); + if (diagnostics && sourceFile.parseDiagnostics) { + diagnostics.push.apply(diagnostics, sourceFile.parseDiagnostics); + } + var outputText; + var compilerHost = { + getSourceFile: function (fileName, target) { return fileName === inputFileName ? sourceFile : undefined; }, + writeFile: function (name, text, writeByteOrderMark) { + ts.Debug.assert(outputText === undefined, "Unexpected multiple outputs for the file: " + name); + outputText = text; + }, + getDefaultLibFileName: function () { return "lib.d.ts"; }, + useCaseSensitiveFileNames: function () { return false; }, + getCanonicalFileName: function (fileName) { return fileName; }, + getCurrentDirectory: function () { return ""; }, + getNewLine: function () { return (ts.sys && ts.sys.newLine) || "\r\n"; } + }; + var program = ts.createProgram([inputFileName], options, compilerHost); + if (diagnostics) { + diagnostics.push.apply(diagnostics, program.getGlobalDiagnostics()); + } + program.emit(); + ts.Debug.assert(outputText !== undefined, "Output generation failed"); + return outputText; + } + ts.transpile = transpile; + function createLanguageServiceSourceFile(fileName, scriptSnapshot, scriptTarget, version, setNodeParents) { + var sourceFile = ts.createSourceFile(fileName, scriptSnapshot.getText(0, scriptSnapshot.getLength()), scriptTarget, setNodeParents); + setSourceFileFields(sourceFile, scriptSnapshot, version); + sourceFile.nameTable = sourceFile.identifiers; + return sourceFile; + } + ts.createLanguageServiceSourceFile = createLanguageServiceSourceFile; + ts.disableIncrementalParsing = false; + function updateLanguageServiceSourceFile(sourceFile, scriptSnapshot, version, textChangeRange, aggressiveChecks) { + if (textChangeRange) { + if (version !== sourceFile.version) { + if (!ts.disableIncrementalParsing) { + var newSourceFile = ts.updateSourceFile(sourceFile, scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange, aggressiveChecks); + setSourceFileFields(newSourceFile, scriptSnapshot, version); + newSourceFile.nameTable = undefined; + return newSourceFile; + } + } + } + return createLanguageServiceSourceFile(sourceFile.fileName, scriptSnapshot, sourceFile.languageVersion, version, true); + } + ts.updateLanguageServiceSourceFile = updateLanguageServiceSourceFile; + function createDocumentRegistry() { + var buckets = {}; + function getKeyFromCompilationSettings(settings) { + return "_" + settings.target; + } + function getBucketForCompilationSettings(settings, createIfMissing) { + var key = getKeyFromCompilationSettings(settings); + var bucket = ts.lookUp(buckets, key); + if (!bucket && createIfMissing) { + buckets[key] = bucket = {}; + } + return bucket; + } + function reportStats() { + var bucketInfoArray = Object.keys(buckets).filter(function (name) { return name && name.charAt(0) === '_'; }).map(function (name) { + var entries = ts.lookUp(buckets, name); + var sourceFiles = []; + for (var i in entries) { + var entry = entries[i]; + sourceFiles.push({ + name: i, + refCount: entry.languageServiceRefCount, + references: entry.owners.slice(0) + }); + } + sourceFiles.sort(function (x, y) { return y.refCount - x.refCount; }); + return { + bucket: name, + sourceFiles: sourceFiles + }; + }); + return JSON.stringify(bucketInfoArray, null, 2); + } + function acquireDocument(fileName, compilationSettings, scriptSnapshot, version) { + return acquireOrUpdateDocument(fileName, compilationSettings, scriptSnapshot, version, true); + } + function updateDocument(fileName, compilationSettings, scriptSnapshot, version) { + return acquireOrUpdateDocument(fileName, compilationSettings, scriptSnapshot, version, false); + } + function acquireOrUpdateDocument(fileName, compilationSettings, scriptSnapshot, version, acquiring) { + var bucket = getBucketForCompilationSettings(compilationSettings, true); + var entry = ts.lookUp(bucket, fileName); + if (!entry) { + ts.Debug.assert(acquiring, "How could we be trying to update a document that the registry doesn't have?"); + var sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, compilationSettings.target, version, false); + bucket[fileName] = entry = { + sourceFile: sourceFile, + languageServiceRefCount: 0, + owners: [] + }; + } + else { + if (entry.sourceFile.version !== version) { + entry.sourceFile = updateLanguageServiceSourceFile(entry.sourceFile, scriptSnapshot, version, scriptSnapshot.getChangeRange(entry.sourceFile.scriptSnapshot)); + } + } + if (acquiring) { + entry.languageServiceRefCount++; + } + return entry.sourceFile; + } + function releaseDocument(fileName, compilationSettings) { + var bucket = getBucketForCompilationSettings(compilationSettings, false); + ts.Debug.assert(bucket !== undefined); + var entry = ts.lookUp(bucket, fileName); + entry.languageServiceRefCount--; + ts.Debug.assert(entry.languageServiceRefCount >= 0); + if (entry.languageServiceRefCount === 0) { + delete bucket[fileName]; + } + } + return { + acquireDocument: acquireDocument, + updateDocument: updateDocument, + releaseDocument: releaseDocument, + reportStats: reportStats + }; + } + ts.createDocumentRegistry = createDocumentRegistry; + function preProcessFile(sourceText, readImportFiles) { + if (readImportFiles === void 0) { readImportFiles = true; } + var referencedFiles = []; + var importedFiles = []; + var isNoDefaultLib = false; + function processTripleSlashDirectives() { + var commentRanges = ts.getLeadingCommentRanges(sourceText, 0); + ts.forEach(commentRanges, function (commentRange) { + var comment = sourceText.substring(commentRange.pos, commentRange.end); + var referencePathMatchResult = ts.getFileReferenceFromReferencePath(comment, commentRange); + if (referencePathMatchResult) { + isNoDefaultLib = referencePathMatchResult.isNoDefaultLib; + var fileReference = referencePathMatchResult.fileReference; + if (fileReference) { + referencedFiles.push(fileReference); + } + } + }); + } + function recordModuleName() { + var importPath = scanner.getTokenValue(); + var pos = scanner.getTokenPos(); + importedFiles.push({ + fileName: importPath, + pos: pos, + end: pos + importPath.length + }); + } + function processImport() { + scanner.setText(sourceText); + var token = scanner.scan(); + while (token !== 1) { + if (token === 85) { + token = scanner.scan(); + if (token === 8) { + recordModuleName(); + continue; + } + else { + if (token === 65) { + token = scanner.scan(); + if (token === 124) { + token = scanner.scan(); + if (token === 8) { + recordModuleName(); + continue; + } + } + else if (token === 53) { + token = scanner.scan(); + if (token === 118) { + token = scanner.scan(); + if (token === 16) { + token = scanner.scan(); + if (token === 8) { + recordModuleName(); + continue; + } + } + } + } + else if (token === 23) { + token = scanner.scan(); + } + else { + continue; + } + } + if (token === 14) { + token = scanner.scan(); + while (token !== 15) { + token = scanner.scan(); + } + if (token === 15) { + token = scanner.scan(); + if (token === 124) { + token = scanner.scan(); + if (token === 8) { + recordModuleName(); + } + } + } + } + else if (token === 35) { + token = scanner.scan(); + if (token === 111) { + token = scanner.scan(); + if (token === 65) { + token = scanner.scan(); + if (token === 124) { + token = scanner.scan(); + if (token === 8) { + recordModuleName(); + } + } + } + } + } + } + } + else if (token === 78) { + token = scanner.scan(); + if (token === 14) { + token = scanner.scan(); + while (token !== 15) { + token = scanner.scan(); + } + if (token === 15) { + token = scanner.scan(); + if (token === 124) { + token = scanner.scan(); + if (token === 8) { + recordModuleName(); + } + } + } + } + else if (token === 35) { + token = scanner.scan(); + if (token === 124) { + token = scanner.scan(); + if (token === 8) { + recordModuleName(); + } + } + } + } + token = scanner.scan(); + } + scanner.setText(undefined); + } + if (readImportFiles) { + processImport(); + } + processTripleSlashDirectives(); + return { referencedFiles: referencedFiles, importedFiles: importedFiles, isLibFile: isNoDefaultLib }; + } + ts.preProcessFile = preProcessFile; + function getTargetLabel(referenceNode, labelName) { + while (referenceNode) { + if (referenceNode.kind === 194 && referenceNode.label.text === labelName) { + return referenceNode.label; + } + referenceNode = referenceNode.parent; + } + return undefined; + } + function isJumpStatementTarget(node) { + return node.kind === 65 && + (node.parent.kind === 190 || node.parent.kind === 189) && + node.parent.label === node; + } + function isLabelOfLabeledStatement(node) { + return node.kind === 65 && + node.parent.kind === 194 && + node.parent.label === node; + } + function isLabeledBy(node, labelName) { + for (var owner = node.parent; owner.kind === 194; owner = owner.parent) { + if (owner.label.text === labelName) { + return true; + } + } + return false; + } + function isLabelName(node) { + return isLabelOfLabeledStatement(node) || isJumpStatementTarget(node); + } + function isRightSideOfQualifiedName(node) { + return node.parent.kind === 126 && node.parent.right === node; + } + function isRightSideOfPropertyAccess(node) { + return node && node.parent && node.parent.kind === 155 && node.parent.name === node; + } + function isCallExpressionTarget(node) { + if (isRightSideOfPropertyAccess(node)) { + node = node.parent; + } + return node && node.parent && node.parent.kind === 157 && node.parent.expression === node; + } + function isNewExpressionTarget(node) { + if (isRightSideOfPropertyAccess(node)) { + node = node.parent; + } + return node && node.parent && node.parent.kind === 158 && node.parent.expression === node; + } + function isNameOfModuleDeclaration(node) { + return node.parent.kind === 205 && node.parent.name === node; + } + function isNameOfFunctionDeclaration(node) { + return node.kind === 65 && + ts.isFunctionLike(node.parent) && node.parent.name === node; + } + function isNameOfPropertyAssignment(node) { + return (node.kind === 65 || node.kind === 8 || node.kind === 7) && + (node.parent.kind === 224 || node.parent.kind === 225) && node.parent.name === node; + } + function isLiteralNameOfPropertyDeclarationOrIndexAccess(node) { + if (node.kind === 8 || node.kind === 7) { + switch (node.parent.kind) { + case 132: + case 131: + case 224: + case 226: + case 134: + case 133: + case 136: + case 137: + case 205: + return node.parent.name === node; + case 156: + return node.parent.argumentExpression === node; + } + } + return false; + } + function isNameOfExternalModuleImportOrDeclaration(node) { + if (node.kind === 8) { + return isNameOfModuleDeclaration(node) || + (ts.isExternalModuleImportEqualsDeclaration(node.parent.parent) && ts.getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node); + } + return false; + } + function isInsideComment(sourceFile, token, position) { + return position <= token.getStart(sourceFile) && + (isInsideCommentRange(ts.getTrailingCommentRanges(sourceFile.text, token.getFullStart())) || + isInsideCommentRange(ts.getLeadingCommentRanges(sourceFile.text, token.getFullStart()))); + function isInsideCommentRange(comments) { + return ts.forEach(comments, function (comment) { + if (comment.pos < position && position < comment.end) { + return true; + } + else if (position === comment.end) { + var text = sourceFile.text; + var width = comment.end - comment.pos; + if (width <= 2 || text.charCodeAt(comment.pos + 1) === 47) { + return true; + } + else { + return !(text.charCodeAt(comment.end - 1) === 47 && + text.charCodeAt(comment.end - 2) === 42); + } + } + return false; + }); + } + } + var SemanticMeaning; + (function (SemanticMeaning) { + SemanticMeaning[SemanticMeaning["None"] = 0] = "None"; + SemanticMeaning[SemanticMeaning["Value"] = 1] = "Value"; + SemanticMeaning[SemanticMeaning["Type"] = 2] = "Type"; + SemanticMeaning[SemanticMeaning["Namespace"] = 4] = "Namespace"; + SemanticMeaning[SemanticMeaning["All"] = 7] = "All"; + })(SemanticMeaning || (SemanticMeaning = {})); + var BreakContinueSearchType; + (function (BreakContinueSearchType) { + BreakContinueSearchType[BreakContinueSearchType["None"] = 0] = "None"; + BreakContinueSearchType[BreakContinueSearchType["Unlabeled"] = 1] = "Unlabeled"; + BreakContinueSearchType[BreakContinueSearchType["Labeled"] = 2] = "Labeled"; + BreakContinueSearchType[BreakContinueSearchType["All"] = 3] = "All"; + })(BreakContinueSearchType || (BreakContinueSearchType = {})); + var keywordCompletions = []; + for (var i = 66; i <= 125; i++) { + keywordCompletions.push({ + name: ts.tokenToString(i), + kind: ScriptElementKind.keyword, + kindModifiers: ScriptElementKindModifier.none, + sortText: "0" + }); + } + function getContainerNode(node) { + while (true) { + node = node.parent; + if (!node) { + return undefined; + } + switch (node.kind) { + case 227: + case 134: + case 133: + case 200: + case 162: + case 136: + case 137: + case 201: + case 202: + case 204: + case 205: + return node; + } + } + } + ts.getContainerNode = getContainerNode; + function getNodeKind(node) { + switch (node.kind) { + case 205: return ScriptElementKind.moduleElement; + case 201: return ScriptElementKind.classElement; + case 202: return ScriptElementKind.interfaceElement; + case 203: return ScriptElementKind.typeElement; + case 204: return ScriptElementKind.enumElement; + case 198: + return ts.isConst(node) + ? ScriptElementKind.constElement + : ts.isLet(node) + ? ScriptElementKind.letElement + : ScriptElementKind.variableElement; + case 200: return ScriptElementKind.functionElement; + case 136: return ScriptElementKind.memberGetAccessorElement; + case 137: return ScriptElementKind.memberSetAccessorElement; + case 134: + case 133: + return ScriptElementKind.memberFunctionElement; + case 132: + case 131: + return ScriptElementKind.memberVariableElement; + case 140: return ScriptElementKind.indexSignatureElement; + case 139: return ScriptElementKind.constructSignatureElement; + case 138: return ScriptElementKind.callSignatureElement; + case 135: return ScriptElementKind.constructorImplementationElement; + case 128: return ScriptElementKind.typeParameterElement; + case 226: return ScriptElementKind.variableElement; + case 129: return (node.flags & 112) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement; + case 208: + case 213: + case 210: + case 217: + case 211: + return ScriptElementKind.alias; + } + return ScriptElementKind.unknown; + } + ts.getNodeKind = getNodeKind; + function createLanguageService(host, documentRegistry) { + if (documentRegistry === void 0) { documentRegistry = createDocumentRegistry(); } + var syntaxTreeCache = new SyntaxTreeCache(host); + var ruleProvider; + var program; + var useCaseSensitivefileNames = false; + var cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken()); + if (!ts.localizedDiagnosticMessages && host.getLocalizedDiagnosticMessages) { + ts.localizedDiagnosticMessages = host.getLocalizedDiagnosticMessages(); + } + function log(message) { + if (host.log) { + host.log(message); + } + } + function getCanonicalFileName(fileName) { + return useCaseSensitivefileNames ? fileName : fileName.toLowerCase(); + } + function getValidSourceFile(fileName) { + fileName = ts.normalizeSlashes(fileName); + var sourceFile = program.getSourceFile(getCanonicalFileName(fileName)); + if (!sourceFile) { + throw new Error("Could not find file: '" + fileName + "'."); + } + return sourceFile; + } + function getRuleProvider(options) { + if (!ruleProvider) { + ruleProvider = new ts.formatting.RulesProvider(); + } + ruleProvider.ensureUpToDate(options); + return ruleProvider; + } + function synchronizeHostData() { + var hostCache = new HostCache(host); + if (programUpToDate()) { + return; + } + var oldSettings = program && program.getCompilerOptions(); + var newSettings = hostCache.compilationSettings(); + var changesInCompilationSettingsAffectSyntax = oldSettings && oldSettings.target !== newSettings.target; + var newProgram = ts.createProgram(hostCache.getRootFileNames(), newSettings, { + getSourceFile: getOrCreateSourceFile, + getCancellationToken: function () { return cancellationToken; }, + getCanonicalFileName: function (fileName) { return useCaseSensitivefileNames ? fileName : fileName.toLowerCase(); }, + useCaseSensitiveFileNames: function () { return useCaseSensitivefileNames; }, + getNewLine: function () { return host.getNewLine ? host.getNewLine() : "\r\n"; }, + getDefaultLibFileName: function (options) { return host.getDefaultLibFileName(options); }, + writeFile: function (fileName, data, writeByteOrderMark) { }, + getCurrentDirectory: function () { return host.getCurrentDirectory(); } + }); + if (program) { + var oldSourceFiles = program.getSourceFiles(); + for (var _i = 0; _i < oldSourceFiles.length; _i++) { + var oldSourceFile = oldSourceFiles[_i]; + var fileName = oldSourceFile.fileName; + if (!newProgram.getSourceFile(fileName) || changesInCompilationSettingsAffectSyntax) { + documentRegistry.releaseDocument(fileName, oldSettings); + } + } + } + program = newProgram; + program.getTypeChecker(); + return; + function getOrCreateSourceFile(fileName) { + var hostFileInformation = hostCache.getOrCreateEntry(fileName); + if (!hostFileInformation) { + return undefined; + } + if (!changesInCompilationSettingsAffectSyntax) { + var oldSourceFile = program && program.getSourceFile(fileName); + if (oldSourceFile) { + return documentRegistry.updateDocument(fileName, newSettings, hostFileInformation.scriptSnapshot, hostFileInformation.version); + } + } + return documentRegistry.acquireDocument(fileName, newSettings, hostFileInformation.scriptSnapshot, hostFileInformation.version); + } + function sourceFileUpToDate(sourceFile) { + return sourceFile && sourceFile.version === hostCache.getVersion(sourceFile.fileName); + } + function programUpToDate() { + if (!program) { + return false; + } + var rootFileNames = hostCache.getRootFileNames(); + if (program.getSourceFiles().length !== rootFileNames.length) { + return false; + } + for (var _i = 0; _i < rootFileNames.length; _i++) { + var fileName = rootFileNames[_i]; + if (!sourceFileUpToDate(program.getSourceFile(fileName))) { + return false; + } + } + return ts.compareDataObjects(program.getCompilerOptions(), hostCache.compilationSettings()); + } + } + function getProgram() { + synchronizeHostData(); + return program; + } + function cleanupSemanticCache() { + } + function dispose() { + if (program) { + ts.forEach(program.getSourceFiles(), function (f) { + return documentRegistry.releaseDocument(f.fileName, program.getCompilerOptions()); + }); + } + } + function getSyntacticDiagnostics(fileName) { + synchronizeHostData(); + return program.getSyntacticDiagnostics(getValidSourceFile(fileName)); + } + function getSemanticDiagnostics(fileName) { + synchronizeHostData(); + var targetSourceFile = getValidSourceFile(fileName); + if (ts.isJavaScript(fileName)) { + return getJavaScriptSemanticDiagnostics(targetSourceFile); + } + var semanticDiagnostics = program.getSemanticDiagnostics(targetSourceFile); + if (!program.getCompilerOptions().declaration) { + return semanticDiagnostics; + } + var declarationDiagnostics = program.getDeclarationDiagnostics(targetSourceFile); + return ts.concatenate(semanticDiagnostics, declarationDiagnostics); + } + function getJavaScriptSemanticDiagnostics(sourceFile) { + var diagnostics = []; + walk(sourceFile); + return diagnostics; + function walk(node) { + if (!node) { + return false; + } + switch (node.kind) { + case 208: + diagnostics.push(ts.createDiagnosticForNode(node, ts.Diagnostics.import_can_only_be_used_in_a_ts_file)); + return true; + case 214: + diagnostics.push(ts.createDiagnosticForNode(node, ts.Diagnostics.export_can_only_be_used_in_a_ts_file)); + return true; + case 201: + var classDeclaration = node; + if (checkModifiers(classDeclaration.modifiers) || + checkTypeParameters(classDeclaration.typeParameters)) { + return true; + } + break; + case 222: + var heritageClause = node; + if (heritageClause.token === 102) { + diagnostics.push(ts.createDiagnosticForNode(node, ts.Diagnostics.implements_clauses_can_only_be_used_in_a_ts_file)); + return true; + } + break; + case 202: + diagnostics.push(ts.createDiagnosticForNode(node, ts.Diagnostics.interface_declarations_can_only_be_used_in_a_ts_file)); + return true; + case 205: + diagnostics.push(ts.createDiagnosticForNode(node, ts.Diagnostics.module_declarations_can_only_be_used_in_a_ts_file)); + return true; + case 203: + diagnostics.push(ts.createDiagnosticForNode(node, ts.Diagnostics.type_aliases_can_only_be_used_in_a_ts_file)); + return true; + case 134: + case 133: + case 135: + case 136: + case 137: + case 162: + case 200: + case 163: + case 200: + var functionDeclaration = node; + if (checkModifiers(functionDeclaration.modifiers) || + checkTypeParameters(functionDeclaration.typeParameters) || + checkTypeAnnotation(functionDeclaration.type)) { + return true; + } + break; + case 180: + var variableStatement = node; + if (checkModifiers(variableStatement.modifiers)) { + return true; + } + break; + case 198: + var variableDeclaration = node; + if (checkTypeAnnotation(variableDeclaration.type)) { + return true; + } + break; + case 157: + case 158: + var expression = node; + if (expression.typeArguments && expression.typeArguments.length > 0) { + var start = expression.typeArguments.pos; + diagnostics.push(ts.createFileDiagnostic(sourceFile, start, expression.typeArguments.end - start, ts.Diagnostics.type_arguments_can_only_be_used_in_a_ts_file)); + return true; + } + break; + case 129: + var parameter = node; + if (parameter.modifiers) { + var start = parameter.modifiers.pos; + diagnostics.push(ts.createFileDiagnostic(sourceFile, start, parameter.modifiers.end - start, ts.Diagnostics.parameter_modifiers_can_only_be_used_in_a_ts_file)); + return true; + } + if (parameter.questionToken) { + diagnostics.push(ts.createDiagnosticForNode(parameter.questionToken, ts.Diagnostics.can_only_be_used_in_a_ts_file)); + return true; + } + if (parameter.type) { + diagnostics.push(ts.createDiagnosticForNode(parameter.type, ts.Diagnostics.types_can_only_be_used_in_a_ts_file)); + return true; + } + break; + case 132: + diagnostics.push(ts.createDiagnosticForNode(node, ts.Diagnostics.property_declarations_can_only_be_used_in_a_ts_file)); + return true; + case 204: + diagnostics.push(ts.createDiagnosticForNode(node, ts.Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file)); + return true; + case 160: + var typeAssertionExpression = node; + diagnostics.push(ts.createDiagnosticForNode(typeAssertionExpression.type, ts.Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file)); + return true; + case 130: + diagnostics.push(ts.createDiagnosticForNode(node, ts.Diagnostics.decorators_can_only_be_used_in_a_ts_file)); + return true; + } + return ts.forEachChild(node, walk); + } + function checkTypeParameters(typeParameters) { + if (typeParameters) { + var start = typeParameters.pos; + diagnostics.push(ts.createFileDiagnostic(sourceFile, start, typeParameters.end - start, ts.Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file)); + return true; + } + return false; + } + function checkTypeAnnotation(type) { + if (type) { + diagnostics.push(ts.createDiagnosticForNode(type, ts.Diagnostics.types_can_only_be_used_in_a_ts_file)); + return true; + } + return false; + } + function checkModifiers(modifiers) { + if (modifiers) { + for (var _i = 0; _i < modifiers.length; _i++) { + var modifier = modifiers[_i]; + switch (modifier.kind) { + case 108: + case 106: + case 107: + case 115: + diagnostics.push(ts.createDiagnosticForNode(modifier, ts.Diagnostics._0_can_only_be_used_in_a_ts_file, ts.tokenToString(modifier.kind))); + return true; + case 109: + case 78: + case 70: + case 73: + } + } + } + return false; + } + } + function getCompilerOptionsDiagnostics() { + synchronizeHostData(); + return program.getGlobalDiagnostics(); + } + function getCompletionEntryDisplayNameForSymbol(symbol, target, performCharacterChecks) { + var displayName = symbol.getName(); + if (displayName) { + if (displayName === "default") { + var localSymbol = ts.getLocalSymbolForExportDefault(symbol); + if (localSymbol && localSymbol.name) { + displayName = symbol.valueDeclaration.localSymbol.name; + } + } + var firstCharCode = displayName.charCodeAt(0); + if ((symbol.flags & 1536) && (firstCharCode === 39 || firstCharCode === 34)) { + return undefined; + } + } + return getCompletionEntryDisplayName(displayName, target, performCharacterChecks); + } + function getCompletionEntryDisplayName(displayName, target, performCharacterChecks) { + if (!displayName) { + return undefined; + } + var firstCharCode = displayName.charCodeAt(0); + if (displayName.length >= 2 && + firstCharCode === displayName.charCodeAt(displayName.length - 1) && + (firstCharCode === 39 || firstCharCode === 34)) { + displayName = displayName.substring(1, displayName.length - 1); + } + if (!displayName) { + return undefined; + } + if (performCharacterChecks) { + if (!ts.isIdentifierStart(displayName.charCodeAt(0), target)) { + return undefined; + } + for (var i = 1, n = displayName.length; i < n; i++) { + if (!ts.isIdentifierPart(displayName.charCodeAt(i), target)) { + return undefined; + } + } + } + return ts.unescapeIdentifier(displayName); + } + function getCompletionData(fileName, position) { + var typeChecker = program.getTypeChecker(); + var syntacticStart = new Date().getTime(); + var sourceFile = getValidSourceFile(fileName); + var start = new Date().getTime(); + var currentToken = ts.getTokenAtPosition(sourceFile, position); + log("getCompletionData: Get current token: " + (new Date().getTime() - start)); + start = new Date().getTime(); + var insideComment = isInsideComment(sourceFile, currentToken, position); + log("getCompletionData: Is inside comment: " + (new Date().getTime() - start)); + if (insideComment) { + log("Returning an empty list because completion was inside a comment."); + return undefined; + } + start = new Date().getTime(); + var previousToken = ts.findPrecedingToken(position, sourceFile); + log("getCompletionData: Get previous token 1: " + (new Date().getTime() - start)); + var contextToken = previousToken; + if (contextToken && position <= contextToken.end && ts.isWord(contextToken.kind)) { + var start_1 = new Date().getTime(); + contextToken = ts.findPrecedingToken(contextToken.getFullStart(), sourceFile); + log("getCompletionData: Get previous token 2: " + (new Date().getTime() - start_1)); + } + if (contextToken && isCompletionListBlocker(contextToken)) { + log("Returning an empty list because completion was requested in an invalid position."); + return undefined; + } + var node = currentToken; + var isRightOfDot = false; + if (contextToken && contextToken.kind === 20 && contextToken.parent.kind === 155) { + node = contextToken.parent.expression; + isRightOfDot = true; + } + else if (contextToken && contextToken.kind === 20 && contextToken.parent.kind === 126) { + node = contextToken.parent.left; + isRightOfDot = true; + } + var location = ts.getTouchingPropertyName(sourceFile, position); + var target = program.getCompilerOptions().target; + var semanticStart = new Date().getTime(); + var isMemberCompletion; + var isNewIdentifierLocation; + var symbols = []; + if (isRightOfDot) { + getTypeScriptMemberSymbols(); + } + else { + if (!tryGetGlobalSymbols()) { + return undefined; + } + } + log("getCompletionData: Semantic work: " + (new Date().getTime() - semanticStart)); + return { symbols: symbols, isMemberCompletion: isMemberCompletion, isNewIdentifierLocation: isNewIdentifierLocation, location: location, isRightOfDot: isRightOfDot }; + function getTypeScriptMemberSymbols() { + isMemberCompletion = true; + isNewIdentifierLocation = false; + if (node.kind === 65 || node.kind === 126 || node.kind === 155) { + var symbol = typeChecker.getSymbolAtLocation(node); + if (symbol && symbol.flags & 8388608) { + symbol = typeChecker.getAliasedSymbol(symbol); + } + if (symbol && symbol.flags & 1952) { + var exportedSymbols = typeChecker.getExportsOfModule(symbol); + ts.forEach(exportedSymbols, function (symbol) { + if (typeChecker.isValidPropertyAccess((node.parent), symbol.name)) { + symbols.push(symbol); + } + }); + } + } + var type = typeChecker.getTypeAtLocation(node); + if (type) { + ts.forEach(type.getApparentProperties(), function (symbol) { + if (typeChecker.isValidPropertyAccess((node.parent), symbol.name)) { + symbols.push(symbol); + } + }); + } + } + function tryGetGlobalSymbols() { + var containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(contextToken); + if (containingObjectLiteral) { + isMemberCompletion = true; + isNewIdentifierLocation = true; + var contextualType = typeChecker.getContextualType(containingObjectLiteral); + if (!contextualType) { + return false; + } + var contextualTypeMembers = typeChecker.getPropertiesOfType(contextualType); + if (contextualTypeMembers && contextualTypeMembers.length > 0) { + symbols = filterContextualMembersList(contextualTypeMembers, containingObjectLiteral.properties); + } + } + else if (ts.getAncestor(contextToken, 210)) { + isMemberCompletion = true; + isNewIdentifierLocation = true; + if (showCompletionsInImportsClause(contextToken)) { + var importDeclaration = ts.getAncestor(contextToken, 209); + ts.Debug.assert(importDeclaration !== undefined); + var exports_1; + if (importDeclaration.moduleSpecifier) { + var moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importDeclaration.moduleSpecifier); + if (moduleSpecifierSymbol) { + exports_1 = typeChecker.getExportsOfModule(moduleSpecifierSymbol); + } + } + symbols = exports_1 ? filterModuleExports(exports_1, importDeclaration) : emptyArray; + } + } + else { + isMemberCompletion = false; + isNewIdentifierLocation = isNewIdentifierDefinitionLocation(contextToken); + if (previousToken !== contextToken) { + ts.Debug.assert(!!previousToken, "Expected 'contextToken' to be defined when different from 'previousToken'."); + } + var adjustedPosition = previousToken !== contextToken ? + previousToken.getStart() : + position; + var scopeNode = getScopeNode(contextToken, adjustedPosition, sourceFile) || sourceFile; + var symbolMeanings = 793056 | 107455 | 1536 | 8388608; + symbols = typeChecker.getSymbolsInScope(scopeNode, symbolMeanings); + } + return true; + } + function getScopeNode(initialToken, position, sourceFile) { + var scope = initialToken; + while (scope && !ts.positionBelongsToNode(scope, position, sourceFile)) { + scope = scope.parent; + } + return scope; + } + function isCompletionListBlocker(previousToken) { + var start = new Date().getTime(); + var result = isInStringOrRegularExpressionOrTemplateLiteral(previousToken) || + isIdentifierDefinitionLocation(previousToken) || + isRightOfIllegalDot(previousToken); + log("getCompletionsAtPosition: isCompletionListBlocker: " + (new Date().getTime() - start)); + return result; + } + function showCompletionsInImportsClause(node) { + if (node) { + if (node.kind === 14 || node.kind === 23) { + return node.parent.kind === 212; + } + } + return false; + } + function isNewIdentifierDefinitionLocation(previousToken) { + if (previousToken) { + var containingNodeKind = previousToken.parent.kind; + switch (previousToken.kind) { + case 23: + return containingNodeKind === 157 + || containingNodeKind === 135 + || containingNodeKind === 158 + || containingNodeKind === 153 + || containingNodeKind === 169; + case 16: + return containingNodeKind === 157 + || containingNodeKind === 135 + || containingNodeKind === 158 + || containingNodeKind === 161; + case 18: + return containingNodeKind === 153; + case 117: + return true; + case 20: + return containingNodeKind === 205; + case 14: + return containingNodeKind === 201; + case 53: + return containingNodeKind === 198 + || containingNodeKind === 169; + case 11: + return containingNodeKind === 171; + case 12: + return containingNodeKind === 176; + case 108: + case 106: + case 107: + return containingNodeKind === 132; + } + switch (previousToken.getText()) { + case "public": + case "protected": + case "private": + return true; + } + } + return false; + } + function isInStringOrRegularExpressionOrTemplateLiteral(previousToken) { + if (previousToken.kind === 8 + || previousToken.kind === 9 + || ts.isTemplateLiteralKind(previousToken.kind)) { + var start_2 = previousToken.getStart(); + var end = previousToken.getEnd(); + if (start_2 < position && position < end) { + return true; + } + else if (position === end) { + return !!previousToken.isUnterminated; + } + } + return false; + } + function getContainingObjectLiteralApplicableForCompletion(previousToken) { + // The locations in an object literal expression that are applicable for completion are property name definition locations. + if (previousToken) { + var parent_2 = previousToken.parent; + switch (previousToken.kind) { + case 14: + case 23: + if (parent_2 && parent_2.kind === 154) { + return parent_2; + } + break; + } + } + return undefined; + } + function isFunction(kind) { + switch (kind) { + case 162: + case 163: + case 200: + case 134: + case 133: + case 136: + case 137: + case 138: + case 139: + case 140: + return true; + } + return false; + } + function isIdentifierDefinitionLocation(previousToken) { + if (previousToken) { + var containingNodeKind = previousToken.parent.kind; + switch (previousToken.kind) { + case 23: + return containingNodeKind === 198 || + containingNodeKind === 199 || + containingNodeKind === 180 || + containingNodeKind === 204 || + isFunction(containingNodeKind) || + containingNodeKind === 201 || + containingNodeKind === 200 || + containingNodeKind === 202 || + containingNodeKind === 151 || + containingNodeKind === 150; + case 20: + return containingNodeKind === 151; + case 18: + return containingNodeKind === 151; + case 16: + return containingNodeKind === 223 || + isFunction(containingNodeKind); + case 14: + return containingNodeKind === 204 || + containingNodeKind === 202 || + containingNodeKind === 145 || + containingNodeKind === 150; + case 22: + return containingNodeKind === 131 && + previousToken.parent && previousToken.parent.parent && + (previousToken.parent.parent.kind === 202 || + previousToken.parent.parent.kind === 145); + case 24: + return containingNodeKind === 201 || + containingNodeKind === 200 || + containingNodeKind === 202 || + isFunction(containingNodeKind); + case 109: + return containingNodeKind === 132; + case 21: + return containingNodeKind === 129 || + containingNodeKind === 135 || + (previousToken.parent && previousToken.parent.parent && + previousToken.parent.parent.kind === 151); + case 108: + case 106: + case 107: + return containingNodeKind === 129; + case 69: + case 77: + case 103: + case 83: + case 98: + case 116: + case 120: + case 85: + case 104: + case 70: + case 110: + return true; + } + switch (previousToken.getText()) { + case "class": + case "interface": + case "enum": + case "function": + case "var": + case "static": + case "let": + case "const": + case "yield": + return true; + } + } + return false; + } + function isRightOfIllegalDot(previousToken) { + if (previousToken && previousToken.kind === 7) { + var text = previousToken.getFullText(); + return text.charAt(text.length - 1) === "."; + } + return false; + } + function filterModuleExports(exports, importDeclaration) { + var exisingImports = {}; + if (!importDeclaration.importClause) { + return exports; + } + if (importDeclaration.importClause.namedBindings && + importDeclaration.importClause.namedBindings.kind === 212) { + ts.forEach(importDeclaration.importClause.namedBindings.elements, function (el) { + var name = el.propertyName || el.name; + exisingImports[name.text] = true; + }); + } + if (ts.isEmpty(exisingImports)) { + return exports; + } + return ts.filter(exports, function (e) { return !ts.lookUp(exisingImports, e.name); }); + } + function filterContextualMembersList(contextualMemberSymbols, existingMembers) { + if (!existingMembers || existingMembers.length === 0) { + return contextualMemberSymbols; + } + var existingMemberNames = {}; + ts.forEach(existingMembers, function (m) { + if (m.kind !== 224 && m.kind !== 225) { + return; + } + if (m.getStart() <= position && position <= m.getEnd()) { + return; + } + existingMemberNames[m.name.text] = true; + }); + var filteredMembers = []; + ts.forEach(contextualMemberSymbols, function (s) { + if (!existingMemberNames[s.name]) { + filteredMembers.push(s); + } + }); + return filteredMembers; + } + } + function getCompletionsAtPosition(fileName, position) { + synchronizeHostData(); + var completionData = getCompletionData(fileName, position); + if (!completionData) { + return undefined; + } + var symbols = completionData.symbols, isMemberCompletion = completionData.isMemberCompletion, isNewIdentifierLocation = completionData.isNewIdentifierLocation, location = completionData.location, isRightOfDot = completionData.isRightOfDot; + var entries; + if (isRightOfDot && ts.isJavaScript(fileName)) { + entries = getCompletionEntriesFromSymbols(symbols); + ts.addRange(entries, getJavaScriptCompletionEntries()); + } + else { + if (!symbols || symbols.length === 0) { + return undefined; + } + entries = getCompletionEntriesFromSymbols(symbols); + } + if (!isMemberCompletion) { + ts.addRange(entries, keywordCompletions); + } + return { isMemberCompletion: isMemberCompletion, isNewIdentifierLocation: isNewIdentifierLocation, entries: entries }; + function getJavaScriptCompletionEntries() { + var entries = []; + var allNames = {}; + var target = program.getCompilerOptions().target; + for (var _i = 0, _a = program.getSourceFiles(); _i < _a.length; _i++) { + var sourceFile = _a[_i]; + var nameTable = getNameTable(sourceFile); + for (var name_1 in nameTable) { + if (!allNames[name_1]) { + allNames[name_1] = name_1; + var displayName = getCompletionEntryDisplayName(name_1, target, true); + if (displayName) { + var entry = { + name: displayName, + kind: ScriptElementKind.warning, + kindModifiers: "", + sortText: "1" + }; + entries.push(entry); + } + } + } + } + return entries; + } + function createCompletionEntry(symbol, location) { + var displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, true); + if (!displayName) { + return undefined; + } + return { + name: displayName, + kind: getSymbolKind(symbol, location), + kindModifiers: getSymbolModifiers(symbol), + sortText: "0", + }; + } + function getCompletionEntriesFromSymbols(symbols) { + var start = new Date().getTime(); + var entries = []; + if (symbols) { + var nameToSymbol = {}; + for (var _i = 0; _i < symbols.length; _i++) { + var symbol = symbols[_i]; + var entry = createCompletionEntry(symbol, location); + if (entry) { + var id = ts.escapeIdentifier(entry.name); + if (!ts.lookUp(nameToSymbol, id)) { + entries.push(entry); + nameToSymbol[id] = symbol; + } + } + } + } + log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (new Date().getTime() - start)); + return entries; + } + } + function getCompletionEntryDetails(fileName, position, entryName) { + synchronizeHostData(); + var completionData = getCompletionData(fileName, position); + if (completionData) { + var symbols = completionData.symbols, location_1 = completionData.location; + var target = program.getCompilerOptions().target; + var symbol = ts.forEach(symbols, function (s) { return getCompletionEntryDisplayNameForSymbol(s, target, false) === entryName ? s : undefined; }); + if (symbol) { + var displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getValidSourceFile(fileName), location_1, location_1, 7); + return { + name: entryName, + kind: displayPartsDocumentationsAndSymbolKind.symbolKind, + kindModifiers: getSymbolModifiers(symbol), + displayParts: displayPartsDocumentationsAndSymbolKind.displayParts, + documentation: displayPartsDocumentationsAndSymbolKind.documentation + }; + } + } + var keywordCompletion = ts.forEach(keywordCompletions, function (c) { return c.name === entryName; }); + if (keywordCompletion) { + return { + name: entryName, + kind: ScriptElementKind.keyword, + kindModifiers: ScriptElementKindModifier.none, + displayParts: [ts.displayPart(entryName, SymbolDisplayPartKind.keyword)], + documentation: undefined + }; + } + return undefined; + } + function getSymbolKind(symbol, location) { + var flags = symbol.getFlags(); + if (flags & 32) + return ScriptElementKind.classElement; + if (flags & 384) + return ScriptElementKind.enumElement; + if (flags & 524288) + return ScriptElementKind.typeElement; + if (flags & 64) + return ScriptElementKind.interfaceElement; + if (flags & 262144) + return ScriptElementKind.typeParameterElement; + var result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, location); + if (result === ScriptElementKind.unknown) { + if (flags & 262144) + return ScriptElementKind.typeParameterElement; + if (flags & 8) + return ScriptElementKind.variableElement; + if (flags & 8388608) + return ScriptElementKind.alias; + if (flags & 1536) + return ScriptElementKind.moduleElement; + } + return result; + } + function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, location) { + var typeChecker = program.getTypeChecker(); + if (typeChecker.isUndefinedSymbol(symbol)) { + return ScriptElementKind.variableElement; + } + if (typeChecker.isArgumentsSymbol(symbol)) { + return ScriptElementKind.localVariableElement; + } + if (flags & 3) { + if (ts.isFirstDeclarationOfSymbolParameter(symbol)) { + return ScriptElementKind.parameterElement; + } + else if (symbol.valueDeclaration && ts.isConst(symbol.valueDeclaration)) { + return ScriptElementKind.constElement; + } + else if (ts.forEach(symbol.declarations, ts.isLet)) { + return ScriptElementKind.letElement; + } + return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localVariableElement : ScriptElementKind.variableElement; + } + if (flags & 16) + return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localFunctionElement : ScriptElementKind.functionElement; + if (flags & 32768) + return ScriptElementKind.memberGetAccessorElement; + if (flags & 65536) + return ScriptElementKind.memberSetAccessorElement; + if (flags & 8192) + return ScriptElementKind.memberFunctionElement; + if (flags & 16384) + return ScriptElementKind.constructorImplementationElement; + if (flags & 4) { + if (flags & 268435456) { + var unionPropertyKind = ts.forEach(typeChecker.getRootSymbols(symbol), function (rootSymbol) { + var rootSymbolFlags = rootSymbol.getFlags(); + if (rootSymbolFlags & (98308 | 3)) { + return ScriptElementKind.memberVariableElement; + } + ts.Debug.assert(!!(rootSymbolFlags & 8192)); + }); + if (!unionPropertyKind) { + var typeOfUnionProperty = typeChecker.getTypeOfSymbolAtLocation(symbol, location); + if (typeOfUnionProperty.getCallSignatures().length) { + return ScriptElementKind.memberFunctionElement; + } + return ScriptElementKind.memberVariableElement; + } + return unionPropertyKind; + } + return ScriptElementKind.memberVariableElement; + } + return ScriptElementKind.unknown; + } + function getTypeKind(type) { + var flags = type.getFlags(); + if (flags & 128) + return ScriptElementKind.enumElement; + if (flags & 1024) + return ScriptElementKind.classElement; + if (flags & 2048) + return ScriptElementKind.interfaceElement; + if (flags & 512) + return ScriptElementKind.typeParameterElement; + if (flags & 1048703) + return ScriptElementKind.primitiveType; + if (flags & 256) + return ScriptElementKind.primitiveType; + return ScriptElementKind.unknown; + } + function getSymbolModifiers(symbol) { + return symbol && symbol.declarations && symbol.declarations.length > 0 + ? ts.getNodeModifiers(symbol.declarations[0]) + : ScriptElementKindModifier.none; + } + function getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, enclosingDeclaration, location, semanticMeaning) { + if (semanticMeaning === void 0) { semanticMeaning = getMeaningFromLocation(location); } + var typeChecker = program.getTypeChecker(); + var displayParts = []; + var documentation; + var symbolFlags = symbol.flags; + var symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags, location); + var hasAddedSymbolInfo; + var type; + if (symbolKind !== ScriptElementKind.unknown || symbolFlags & 32 || symbolFlags & 8388608) { + if (symbolKind === ScriptElementKind.memberGetAccessorElement || symbolKind === ScriptElementKind.memberSetAccessorElement) { + symbolKind = ScriptElementKind.memberVariableElement; + } + var signature; + type = typeChecker.getTypeOfSymbolAtLocation(symbol, location); + if (type) { + if (location.parent && location.parent.kind === 155) { + var right = location.parent.name; + if (right === location || (right && right.getFullWidth() === 0)) { + location = location.parent; + } + } + var callExpression; + if (location.kind === 157 || location.kind === 158) { + callExpression = location; + } + else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) { + callExpression = location.parent; + } + if (callExpression) { + var candidateSignatures = []; + signature = typeChecker.getResolvedSignature(callExpression, candidateSignatures); + if (!signature && candidateSignatures.length) { + signature = candidateSignatures[0]; + } + var useConstructSignatures = callExpression.kind === 158 || callExpression.expression.kind === 91; + var allSignatures = useConstructSignatures ? type.getConstructSignatures() : type.getCallSignatures(); + if (!ts.contains(allSignatures, signature.target || signature)) { + signature = allSignatures.length ? allSignatures[0] : undefined; + } + if (signature) { + if (useConstructSignatures && (symbolFlags & 32)) { + symbolKind = ScriptElementKind.constructorImplementationElement; + addPrefixForAnyFunctionOrVar(type.symbol, symbolKind); + } + else if (symbolFlags & 8388608) { + symbolKind = ScriptElementKind.alias; + pushTypePart(symbolKind); + displayParts.push(ts.spacePart()); + if (useConstructSignatures) { + displayParts.push(ts.keywordPart(88)); + displayParts.push(ts.spacePart()); + } + addFullSymbolName(symbol); + } + else { + addPrefixForAnyFunctionOrVar(symbol, symbolKind); + } + switch (symbolKind) { + case ScriptElementKind.memberVariableElement: + case ScriptElementKind.variableElement: + case ScriptElementKind.constElement: + case ScriptElementKind.letElement: + case ScriptElementKind.parameterElement: + case ScriptElementKind.localVariableElement: + displayParts.push(ts.punctuationPart(51)); + displayParts.push(ts.spacePart()); + if (useConstructSignatures) { + displayParts.push(ts.keywordPart(88)); + displayParts.push(ts.spacePart()); + } + if (!(type.flags & 32768)) { + displayParts.push.apply(displayParts, ts.symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, undefined, 1)); + } + addSignatureDisplayParts(signature, allSignatures, 8); + break; + default: + addSignatureDisplayParts(signature, allSignatures); + } + hasAddedSymbolInfo = true; + } + } + else if ((isNameOfFunctionDeclaration(location) && !(symbol.flags & 98304)) || + (location.kind === 114 && location.parent.kind === 135)) { + var functionDeclaration = location.parent; + var allSignatures = functionDeclaration.kind === 135 ? type.getConstructSignatures() : type.getCallSignatures(); + if (!typeChecker.isImplementationOfOverload(functionDeclaration)) { + signature = typeChecker.getSignatureFromDeclaration(functionDeclaration); + } + else { + signature = allSignatures[0]; + } + if (functionDeclaration.kind === 135) { + symbolKind = ScriptElementKind.constructorImplementationElement; + addPrefixForAnyFunctionOrVar(type.symbol, symbolKind); + } + else { + addPrefixForAnyFunctionOrVar(functionDeclaration.kind === 138 && + !(type.symbol.flags & 2048 || type.symbol.flags & 4096) ? type.symbol : symbol, symbolKind); + } + addSignatureDisplayParts(signature, allSignatures); + hasAddedSymbolInfo = true; + } + } + } + if (symbolFlags & 32 && !hasAddedSymbolInfo) { + displayParts.push(ts.keywordPart(69)); + displayParts.push(ts.spacePart()); + addFullSymbolName(symbol); + writeTypeParametersOfSymbol(symbol, sourceFile); + } + if ((symbolFlags & 64) && (semanticMeaning & 2)) { + addNewLineIfDisplayPartsExist(); + displayParts.push(ts.keywordPart(103)); + displayParts.push(ts.spacePart()); + addFullSymbolName(symbol); + writeTypeParametersOfSymbol(symbol, sourceFile); + } + if (symbolFlags & 524288) { + addNewLineIfDisplayPartsExist(); + displayParts.push(ts.keywordPart(123)); + displayParts.push(ts.spacePart()); + addFullSymbolName(symbol); + displayParts.push(ts.spacePart()); + displayParts.push(ts.operatorPart(53)); + displayParts.push(ts.spacePart()); + displayParts.push.apply(displayParts, ts.typeToDisplayParts(typeChecker, typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration)); + } + if (symbolFlags & 384) { + addNewLineIfDisplayPartsExist(); + if (ts.forEach(symbol.declarations, ts.isConstEnumDeclaration)) { + displayParts.push(ts.keywordPart(70)); + displayParts.push(ts.spacePart()); + } + displayParts.push(ts.keywordPart(77)); + displayParts.push(ts.spacePart()); + addFullSymbolName(symbol); + } + if (symbolFlags & 1536) { + addNewLineIfDisplayPartsExist(); + displayParts.push(ts.keywordPart(117)); + displayParts.push(ts.spacePart()); + addFullSymbolName(symbol); + } + if ((symbolFlags & 262144) && (semanticMeaning & 2)) { + addNewLineIfDisplayPartsExist(); + displayParts.push(ts.punctuationPart(16)); + displayParts.push(ts.textPart("type parameter")); + displayParts.push(ts.punctuationPart(17)); + displayParts.push(ts.spacePart()); + addFullSymbolName(symbol); + displayParts.push(ts.spacePart()); + displayParts.push(ts.keywordPart(86)); + displayParts.push(ts.spacePart()); + if (symbol.parent) { + addFullSymbolName(symbol.parent, enclosingDeclaration); + writeTypeParametersOfSymbol(symbol.parent, enclosingDeclaration); + } + else { + var signatureDeclaration = ts.getDeclarationOfKind(symbol, 128).parent; + var signature = typeChecker.getSignatureFromDeclaration(signatureDeclaration); + if (signatureDeclaration.kind === 139) { + displayParts.push(ts.keywordPart(88)); + displayParts.push(ts.spacePart()); + } + else if (signatureDeclaration.kind !== 138 && signatureDeclaration.name) { + addFullSymbolName(signatureDeclaration.symbol); + } + displayParts.push.apply(displayParts, ts.signatureToDisplayParts(typeChecker, signature, sourceFile, 32)); + } + } + if (symbolFlags & 8) { + addPrefixForAnyFunctionOrVar(symbol, "enum member"); + var declaration = symbol.declarations[0]; + if (declaration.kind === 226) { + var constantValue = typeChecker.getConstantValue(declaration); + if (constantValue !== undefined) { + displayParts.push(ts.spacePart()); + displayParts.push(ts.operatorPart(53)); + displayParts.push(ts.spacePart()); + displayParts.push(ts.displayPart(constantValue.toString(), SymbolDisplayPartKind.numericLiteral)); + } + } + } + if (symbolFlags & 8388608) { + addNewLineIfDisplayPartsExist(); + displayParts.push(ts.keywordPart(85)); + displayParts.push(ts.spacePart()); + addFullSymbolName(symbol); + ts.forEach(symbol.declarations, function (declaration) { + if (declaration.kind === 208) { + var importEqualsDeclaration = declaration; + if (ts.isExternalModuleImportEqualsDeclaration(importEqualsDeclaration)) { + displayParts.push(ts.spacePart()); + displayParts.push(ts.operatorPart(53)); + displayParts.push(ts.spacePart()); + displayParts.push(ts.keywordPart(118)); + displayParts.push(ts.punctuationPart(16)); + displayParts.push(ts.displayPart(ts.getTextOfNode(ts.getExternalModuleImportEqualsDeclarationExpression(importEqualsDeclaration)), SymbolDisplayPartKind.stringLiteral)); + displayParts.push(ts.punctuationPart(17)); + } + else { + var internalAliasSymbol = typeChecker.getSymbolAtLocation(importEqualsDeclaration.moduleReference); + if (internalAliasSymbol) { + displayParts.push(ts.spacePart()); + displayParts.push(ts.operatorPart(53)); + displayParts.push(ts.spacePart()); + addFullSymbolName(internalAliasSymbol, enclosingDeclaration); + } + } + return true; + } + }); + } + if (!hasAddedSymbolInfo) { + if (symbolKind !== ScriptElementKind.unknown) { + if (type) { + addPrefixForAnyFunctionOrVar(symbol, symbolKind); + if (symbolKind === ScriptElementKind.memberVariableElement || + symbolFlags & 3 || + symbolKind === ScriptElementKind.localVariableElement) { + displayParts.push(ts.punctuationPart(51)); + displayParts.push(ts.spacePart()); + if (type.symbol && type.symbol.flags & 262144) { + var typeParameterParts = ts.mapToDisplayParts(function (writer) { + typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(type, writer, enclosingDeclaration); + }); + displayParts.push.apply(displayParts, typeParameterParts); + } + else { + displayParts.push.apply(displayParts, ts.typeToDisplayParts(typeChecker, type, enclosingDeclaration)); + } + } + else if (symbolFlags & 16 || + symbolFlags & 8192 || + symbolFlags & 16384 || + symbolFlags & 131072 || + symbolFlags & 98304 || + symbolKind === ScriptElementKind.memberFunctionElement) { + var allSignatures = type.getCallSignatures(); + addSignatureDisplayParts(allSignatures[0], allSignatures); + } + } + } + else { + symbolKind = getSymbolKind(symbol, location); + } + } + if (!documentation) { + documentation = symbol.getDocumentationComment(); + } + return { displayParts: displayParts, documentation: documentation, symbolKind: symbolKind }; + function addNewLineIfDisplayPartsExist() { + if (displayParts.length) { + displayParts.push(ts.lineBreakPart()); + } + } + function addFullSymbolName(symbol, enclosingDeclaration) { + var fullSymbolDisplayParts = ts.symbolToDisplayParts(typeChecker, symbol, enclosingDeclaration || sourceFile, undefined, 1 | 2); + displayParts.push.apply(displayParts, fullSymbolDisplayParts); + } + function addPrefixForAnyFunctionOrVar(symbol, symbolKind) { + addNewLineIfDisplayPartsExist(); + if (symbolKind) { + pushTypePart(symbolKind); + displayParts.push(ts.spacePart()); + addFullSymbolName(symbol); + } + } + function pushTypePart(symbolKind) { + switch (symbolKind) { + case ScriptElementKind.variableElement: + case ScriptElementKind.functionElement: + case ScriptElementKind.letElement: + case ScriptElementKind.constElement: + case ScriptElementKind.constructorImplementationElement: + displayParts.push(ts.textOrKeywordPart(symbolKind)); + return; + default: + displayParts.push(ts.punctuationPart(16)); + displayParts.push(ts.textOrKeywordPart(symbolKind)); + displayParts.push(ts.punctuationPart(17)); + return; + } + } + function addSignatureDisplayParts(signature, allSignatures, flags) { + displayParts.push.apply(displayParts, ts.signatureToDisplayParts(typeChecker, signature, enclosingDeclaration, flags | 32)); + if (allSignatures.length > 1) { + displayParts.push(ts.spacePart()); + displayParts.push(ts.punctuationPart(16)); + displayParts.push(ts.operatorPart(33)); + displayParts.push(ts.displayPart((allSignatures.length - 1).toString(), SymbolDisplayPartKind.numericLiteral)); + displayParts.push(ts.spacePart()); + displayParts.push(ts.textPart(allSignatures.length === 2 ? "overload" : "overloads")); + displayParts.push(ts.punctuationPart(17)); + } + documentation = signature.getDocumentationComment(); + } + function writeTypeParametersOfSymbol(symbol, enclosingDeclaration) { + var typeParameterParts = ts.mapToDisplayParts(function (writer) { + typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplayFromSymbol(symbol, writer, enclosingDeclaration); + }); + displayParts.push.apply(displayParts, typeParameterParts); + } + } + function getQuickInfoAtPosition(fileName, position) { + synchronizeHostData(); + var sourceFile = getValidSourceFile(fileName); + var node = ts.getTouchingPropertyName(sourceFile, position); + if (!node) { + return undefined; + } + if (isLabelName(node)) { + return undefined; + } + var typeChecker = program.getTypeChecker(); + var symbol = typeChecker.getSymbolAtLocation(node); + if (!symbol) { + switch (node.kind) { + case 65: + case 155: + case 126: + case 93: + case 91: + var type = typeChecker.getTypeAtLocation(node); + if (type) { + return { + kind: ScriptElementKind.unknown, + kindModifiers: ScriptElementKindModifier.none, + textSpan: ts.createTextSpan(node.getStart(), node.getWidth()), + displayParts: ts.typeToDisplayParts(typeChecker, type, getContainerNode(node)), + documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined + }; + } + } + return undefined; + } + var displayPartsDocumentationsAndKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, getContainerNode(node), node); + return { + kind: displayPartsDocumentationsAndKind.symbolKind, + kindModifiers: getSymbolModifiers(symbol), + textSpan: ts.createTextSpan(node.getStart(), node.getWidth()), + displayParts: displayPartsDocumentationsAndKind.displayParts, + documentation: displayPartsDocumentationsAndKind.documentation + }; + } + function createDefinitionInfo(node, symbolKind, symbolName, containerName) { + return { + fileName: node.getSourceFile().fileName, + textSpan: ts.createTextSpanFromBounds(node.getStart(), node.getEnd()), + kind: symbolKind, + name: symbolName, + containerKind: undefined, + containerName: containerName + }; + } + function getDefinitionAtPosition(fileName, position) { + synchronizeHostData(); + var sourceFile = getValidSourceFile(fileName); + var node = ts.getTouchingPropertyName(sourceFile, position); + if (!node) { + return undefined; + } + if (isJumpStatementTarget(node)) { + var labelName = node.text; + var label = getTargetLabel(node.parent, node.text); + return label ? [createDefinitionInfo(label, ScriptElementKind.label, labelName, undefined)] : undefined; + } + var comment = ts.forEach(sourceFile.referencedFiles, function (r) { return (r.pos <= position && position < r.end) ? r : undefined; }); + if (comment) { + var referenceFile = ts.tryResolveScriptReference(program, sourceFile, comment); + if (referenceFile) { + return [{ + fileName: referenceFile.fileName, + textSpan: ts.createTextSpanFromBounds(0, 0), + kind: ScriptElementKind.scriptElement, + name: comment.fileName, + containerName: undefined, + containerKind: undefined + }]; + } + return undefined; + } + var typeChecker = program.getTypeChecker(); + var symbol = typeChecker.getSymbolAtLocation(node); + if (!symbol) { + return undefined; + } + if (symbol.flags & 8388608) { + var declaration = symbol.declarations[0]; + if (node.kind === 65 && node.parent === declaration) { + symbol = typeChecker.getAliasedSymbol(symbol); + } + } + if (node.parent.kind === 225) { + var shorthandSymbol = typeChecker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration); + if (!shorthandSymbol) { + return []; + } + var shorthandDeclarations = shorthandSymbol.getDeclarations(); + var shorthandSymbolKind = getSymbolKind(shorthandSymbol, node); + var shorthandSymbolName = typeChecker.symbolToString(shorthandSymbol); + var shorthandContainerName = typeChecker.symbolToString(symbol.parent, node); + return ts.map(shorthandDeclarations, function (declaration) { return createDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName); }); + } + var result = []; + var declarations = symbol.getDeclarations(); + var symbolName = typeChecker.symbolToString(symbol); + var symbolKind = getSymbolKind(symbol, node); + var containerSymbol = symbol.parent; + var containerName = containerSymbol ? typeChecker.symbolToString(containerSymbol, node) : ""; + if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) && + !tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) { + ts.forEach(declarations, function (declaration) { + result.push(createDefinitionInfo(declaration, symbolKind, symbolName, containerName)); + }); + } + return result; + function tryAddConstructSignature(symbol, location, symbolKind, symbolName, containerName, result) { + if (isNewExpressionTarget(location) || location.kind === 114) { + if (symbol.flags & 32) { + var classDeclaration = symbol.getDeclarations()[0]; + ts.Debug.assert(classDeclaration && classDeclaration.kind === 201); + return tryAddSignature(classDeclaration.members, true, symbolKind, symbolName, containerName, result); + } + } + return false; + } + function tryAddCallSignature(symbol, location, symbolKind, symbolName, containerName, result) { + if (isCallExpressionTarget(location) || isNewExpressionTarget(location) || isNameOfFunctionDeclaration(location)) { + return tryAddSignature(symbol.declarations, false, symbolKind, symbolName, containerName, result); + } + return false; + } + function tryAddSignature(signatureDeclarations, selectConstructors, symbolKind, symbolName, containerName, result) { + var declarations = []; + var definition; + ts.forEach(signatureDeclarations, function (d) { + if ((selectConstructors && d.kind === 135) || + (!selectConstructors && (d.kind === 200 || d.kind === 134 || d.kind === 133))) { + declarations.push(d); + if (d.body) + definition = d; + } + }); + if (definition) { + result.push(createDefinitionInfo(definition, symbolKind, symbolName, containerName)); + return true; + } + else if (declarations.length) { + result.push(createDefinitionInfo(declarations[declarations.length - 1], symbolKind, symbolName, containerName)); + return true; + } + return false; + } + } + function getOccurrencesAtPosition(fileName, position) { + var results = getOccurrencesAtPositionCore(fileName, position); + if (results) { + var sourceFile = getCanonicalFileName(ts.normalizeSlashes(fileName)); + results = ts.filter(results, function (r) { return getCanonicalFileName(ts.normalizeSlashes(r.fileName)) === sourceFile; }); + } + return results; + } + function getDocumentHighlights(fileName, position, filesToSearch) { + synchronizeHostData(); + filesToSearch = ts.map(filesToSearch, ts.normalizeSlashes); + var sourceFilesToSearch = ts.filter(program.getSourceFiles(), function (f) { return ts.contains(filesToSearch, f.fileName); }); + var sourceFile = getValidSourceFile(fileName); + var node = ts.getTouchingWord(sourceFile, position); + if (!node) { + return undefined; + } + return getSemanticDocumentHighlights(node) || getSyntacticDocumentHighlights(node); + function getHighlightSpanForNode(node) { + var start = node.getStart(); + var end = node.getEnd(); + return { + fileName: sourceFile.fileName, + textSpan: ts.createTextSpanFromBounds(start, end), + kind: HighlightSpanKind.none + }; + } + function getSemanticDocumentHighlights(node) { + if (node.kind === 65 || + node.kind === 93 || + node.kind === 91 || + isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || + isNameOfExternalModuleImportOrDeclaration(node)) { + var referencedSymbols = getReferencedSymbolsForNodes(node, sourceFilesToSearch, false, false); + return convertReferencedSymbols(referencedSymbols); + } + return undefined; + function convertReferencedSymbols(referencedSymbols) { + if (!referencedSymbols) { + return undefined; + } + var fileNameToDocumentHighlights = {}; + var result = []; + for (var _i = 0; _i < referencedSymbols.length; _i++) { + var referencedSymbol = referencedSymbols[_i]; + for (var _a = 0, _b = referencedSymbol.references; _a < _b.length; _a++) { + var referenceEntry = _b[_a]; + var fileName_1 = referenceEntry.fileName; + var documentHighlights = ts.getProperty(fileNameToDocumentHighlights, fileName_1); + if (!documentHighlights) { + documentHighlights = { fileName: fileName_1, highlightSpans: [] }; + fileNameToDocumentHighlights[fileName_1] = documentHighlights; + result.push(documentHighlights); + } + documentHighlights.highlightSpans.push({ + textSpan: referenceEntry.textSpan, + kind: referenceEntry.isWriteAccess ? HighlightSpanKind.writtenReference : HighlightSpanKind.reference + }); + } + } + return result; + } + } + function getSyntacticDocumentHighlights(node) { + var fileName = sourceFile.fileName; + var highlightSpans = getHighlightSpans(node); + if (!highlightSpans || highlightSpans.length === 0) { + return undefined; + } + return [{ fileName: fileName, highlightSpans: highlightSpans }]; + function hasKind(node, kind) { + return node !== undefined && node.kind === kind; + } + function parent(node) { + return node && node.parent; + } + function getHighlightSpans(node) { + if (node) { + switch (node.kind) { + case 84: + case 76: + if (hasKind(node.parent, 183)) { + return getIfElseOccurrences(node.parent); + } + break; + case 90: + if (hasKind(node.parent, 191)) { + return getReturnOccurrences(node.parent); + } + break; + case 94: + if (hasKind(node.parent, 195)) { + return getThrowOccurrences(node.parent); + } + break; + case 68: + if (hasKind(parent(parent(node)), 196)) { + return getTryCatchFinallyOccurrences(node.parent.parent); + } + break; + case 96: + case 81: + if (hasKind(parent(node), 196)) { + return getTryCatchFinallyOccurrences(node.parent); + } + break; + case 92: + if (hasKind(node.parent, 193)) { + return getSwitchCaseDefaultOccurrences(node.parent); + } + break; + case 67: + case 73: + if (hasKind(parent(parent(parent(node))), 193)) { + return getSwitchCaseDefaultOccurrences(node.parent.parent.parent); + } + break; + case 66: + case 71: + if (hasKind(node.parent, 190) || hasKind(node.parent, 189)) { + return getBreakOrContinueStatementOccurences(node.parent); + } + break; + case 82: + if (hasKind(node.parent, 186) || + hasKind(node.parent, 187) || + hasKind(node.parent, 188)) { + return getLoopBreakContinueOccurrences(node.parent); + } + break; + case 100: + case 75: + if (hasKind(node.parent, 185) || hasKind(node.parent, 184)) { + return getLoopBreakContinueOccurrences(node.parent); + } + break; + case 114: + if (hasKind(node.parent, 135)) { + return getConstructorOccurrences(node.parent); + } + break; + case 116: + case 120: + if (hasKind(node.parent, 136) || hasKind(node.parent, 137)) { + return getGetAndSetOccurrences(node.parent); + } + default: + if (ts.isModifier(node.kind) && node.parent && + (ts.isDeclaration(node.parent) || node.parent.kind === 180)) { + return getModifierOccurrences(node.kind, node.parent); + } + } + } + return undefined; + } + function aggregateOwnedThrowStatements(node) { + var statementAccumulator = []; + aggregate(node); + return statementAccumulator; + function aggregate(node) { + if (node.kind === 195) { + statementAccumulator.push(node); + } + else if (node.kind === 196) { + var tryStatement = node; + if (tryStatement.catchClause) { + aggregate(tryStatement.catchClause); + } + else { + aggregate(tryStatement.tryBlock); + } + if (tryStatement.finallyBlock) { + aggregate(tryStatement.finallyBlock); + } + } + else if (!ts.isFunctionLike(node)) { + ts.forEachChild(node, aggregate); + } + } + ; + } + function getThrowStatementOwner(throwStatement) { + var child = throwStatement; + while (child.parent) { + var parent_3 = child.parent; + if (ts.isFunctionBlock(parent_3) || parent_3.kind === 227) { + return parent_3; + } + if (parent_3.kind === 196) { + var tryStatement = parent_3; + if (tryStatement.tryBlock === child && tryStatement.catchClause) { + return child; + } + } + child = parent_3; + } + return undefined; + } + function aggregateAllBreakAndContinueStatements(node) { + var statementAccumulator = []; + aggregate(node); + return statementAccumulator; + function aggregate(node) { + if (node.kind === 190 || node.kind === 189) { + statementAccumulator.push(node); + } + else if (!ts.isFunctionLike(node)) { + ts.forEachChild(node, aggregate); + } + } + ; + } + function ownsBreakOrContinueStatement(owner, statement) { + var actualOwner = getBreakOrContinueOwner(statement); + return actualOwner && actualOwner === owner; + } + function getBreakOrContinueOwner(statement) { + for (var node_1 = statement.parent; node_1; node_1 = node_1.parent) { + switch (node_1.kind) { + case 193: + if (statement.kind === 189) { + continue; + } + case 186: + case 187: + case 188: + case 185: + case 184: + if (!statement.label || isLabeledBy(node_1, statement.label.text)) { + return node_1; + } + break; + default: + if (ts.isFunctionLike(node_1)) { + return undefined; + } + break; + } + } + return undefined; + } + function getModifierOccurrences(modifier, declaration) { + var container = declaration.parent; + if (ts.isAccessibilityModifier(modifier)) { + if (!(container.kind === 201 || + (declaration.kind === 129 && hasKind(container, 135)))) { + return undefined; + } + } + else if (modifier === 109) { + if (container.kind !== 201) { + return undefined; + } + } + else if (modifier === 78 || modifier === 115) { + if (!(container.kind === 206 || container.kind === 227)) { + return undefined; + } + } + else { + return undefined; + } + var keywords = []; + var modifierFlag = getFlagFromModifier(modifier); + var nodes; + switch (container.kind) { + case 206: + case 227: + nodes = container.statements; + break; + case 135: + nodes = container.parameters.concat(container.parent.members); + break; + case 201: + nodes = container.members; + if (modifierFlag & 112) { + var constructor = ts.forEach(container.members, function (member) { + return member.kind === 135 && member; + }); + if (constructor) { + nodes = nodes.concat(constructor.parameters); + } + } + break; + default: + ts.Debug.fail("Invalid container kind."); + } + ts.forEach(nodes, function (node) { + if (node.modifiers && node.flags & modifierFlag) { + ts.forEach(node.modifiers, function (child) { return pushKeywordIf(keywords, child, modifier); }); + } + }); + return ts.map(keywords, getHighlightSpanForNode); + function getFlagFromModifier(modifier) { + switch (modifier) { + case 108: + return 16; + case 106: + return 32; + case 107: + return 64; + case 109: + return 128; + case 78: + return 1; + case 115: + return 2; + default: + ts.Debug.fail(); + } + } + } + function pushKeywordIf(keywordList, token) { + var expected = []; + for (var _i = 2; _i < arguments.length; _i++) { + expected[_i - 2] = arguments[_i]; + } + if (token && ts.contains(expected, token.kind)) { + keywordList.push(token); + return true; + } + return false; + } + function getGetAndSetOccurrences(accessorDeclaration) { + var keywords = []; + tryPushAccessorKeyword(accessorDeclaration.symbol, 136); + tryPushAccessorKeyword(accessorDeclaration.symbol, 137); + return ts.map(keywords, getHighlightSpanForNode); + function tryPushAccessorKeyword(accessorSymbol, accessorKind) { + var accessor = ts.getDeclarationOfKind(accessorSymbol, accessorKind); + if (accessor) { + ts.forEach(accessor.getChildren(), function (child) { return pushKeywordIf(keywords, child, 116, 120); }); + } + } + } + function getConstructorOccurrences(constructorDeclaration) { + var declarations = constructorDeclaration.symbol.getDeclarations(); + var keywords = []; + ts.forEach(declarations, function (declaration) { + ts.forEach(declaration.getChildren(), function (token) { + return pushKeywordIf(keywords, token, 114); + }); + }); + return ts.map(keywords, getHighlightSpanForNode); + } + function getLoopBreakContinueOccurrences(loopNode) { + var keywords = []; + if (pushKeywordIf(keywords, loopNode.getFirstToken(), 82, 100, 75)) { + if (loopNode.kind === 184) { + var loopTokens = loopNode.getChildren(); + for (var i = loopTokens.length - 1; i >= 0; i--) { + if (pushKeywordIf(keywords, loopTokens[i], 100)) { + break; + } + } + } + } + var breaksAndContinues = aggregateAllBreakAndContinueStatements(loopNode.statement); + ts.forEach(breaksAndContinues, function (statement) { + if (ownsBreakOrContinueStatement(loopNode, statement)) { + pushKeywordIf(keywords, statement.getFirstToken(), 66, 71); + } + }); + return ts.map(keywords, getHighlightSpanForNode); + } + function getBreakOrContinueStatementOccurences(breakOrContinueStatement) { + var owner = getBreakOrContinueOwner(breakOrContinueStatement); + if (owner) { + switch (owner.kind) { + case 186: + case 187: + case 188: + case 184: + case 185: + return getLoopBreakContinueOccurrences(owner); + case 193: + return getSwitchCaseDefaultOccurrences(owner); + } + } + return undefined; + } + function getSwitchCaseDefaultOccurrences(switchStatement) { + var keywords = []; + pushKeywordIf(keywords, switchStatement.getFirstToken(), 92); + ts.forEach(switchStatement.caseBlock.clauses, function (clause) { + pushKeywordIf(keywords, clause.getFirstToken(), 67, 73); + var breaksAndContinues = aggregateAllBreakAndContinueStatements(clause); + ts.forEach(breaksAndContinues, function (statement) { + if (ownsBreakOrContinueStatement(switchStatement, statement)) { + pushKeywordIf(keywords, statement.getFirstToken(), 66); + } + }); + }); + return ts.map(keywords, getHighlightSpanForNode); + } + function getTryCatchFinallyOccurrences(tryStatement) { + var keywords = []; + pushKeywordIf(keywords, tryStatement.getFirstToken(), 96); + if (tryStatement.catchClause) { + pushKeywordIf(keywords, tryStatement.catchClause.getFirstToken(), 68); + } + if (tryStatement.finallyBlock) { + var finallyKeyword = ts.findChildOfKind(tryStatement, 81, sourceFile); + pushKeywordIf(keywords, finallyKeyword, 81); + } + return ts.map(keywords, getHighlightSpanForNode); + } + function getThrowOccurrences(throwStatement) { + var owner = getThrowStatementOwner(throwStatement); + if (!owner) { + return undefined; + } + var keywords = []; + ts.forEach(aggregateOwnedThrowStatements(owner), function (throwStatement) { + pushKeywordIf(keywords, throwStatement.getFirstToken(), 94); + }); + if (ts.isFunctionBlock(owner)) { + ts.forEachReturnStatement(owner, function (returnStatement) { + pushKeywordIf(keywords, returnStatement.getFirstToken(), 90); + }); + } + return ts.map(keywords, getHighlightSpanForNode); + } + function getReturnOccurrences(returnStatement) { + var func = ts.getContainingFunction(returnStatement); + if (!(func && hasKind(func.body, 179))) { + return undefined; + } + var keywords = []; + ts.forEachReturnStatement(func.body, function (returnStatement) { + pushKeywordIf(keywords, returnStatement.getFirstToken(), 90); + }); + ts.forEach(aggregateOwnedThrowStatements(func.body), function (throwStatement) { + pushKeywordIf(keywords, throwStatement.getFirstToken(), 94); + }); + return ts.map(keywords, getHighlightSpanForNode); + } + function getIfElseOccurrences(ifStatement) { + var keywords = []; + while (hasKind(ifStatement.parent, 183) && ifStatement.parent.elseStatement === ifStatement) { + ifStatement = ifStatement.parent; + } + while (ifStatement) { + var children = ifStatement.getChildren(); + pushKeywordIf(keywords, children[0], 84); + for (var i = children.length - 1; i >= 0; i--) { + if (pushKeywordIf(keywords, children[i], 76)) { + break; + } + } + if (!hasKind(ifStatement.elseStatement, 183)) { + break; + } + ifStatement = ifStatement.elseStatement; + } + var result = []; + for (var i = 0; i < keywords.length; i++) { + if (keywords[i].kind === 76 && i < keywords.length - 1) { + var elseKeyword = keywords[i]; + var ifKeyword = keywords[i + 1]; + var shouldCombindElseAndIf = true; + for (var j = ifKeyword.getStart() - 1; j >= elseKeyword.end; j--) { + if (!ts.isWhiteSpace(sourceFile.text.charCodeAt(j))) { + shouldCombindElseAndIf = false; + break; + } + } + if (shouldCombindElseAndIf) { + result.push({ + fileName: fileName, + textSpan: ts.createTextSpanFromBounds(elseKeyword.getStart(), ifKeyword.end), + kind: HighlightSpanKind.reference + }); + i++; + continue; + } + } + result.push(getHighlightSpanForNode(keywords[i])); + } + return result; + } + } + } + function getOccurrencesAtPositionCore(fileName, position) { + synchronizeHostData(); + return convertDocumentHighlights(getDocumentHighlights(fileName, position, [fileName])); + function convertDocumentHighlights(documentHighlights) { + if (!documentHighlights) { + return undefined; + } + var result = []; + for (var _i = 0; _i < documentHighlights.length; _i++) { + var entry = documentHighlights[_i]; + for (var _a = 0, _b = entry.highlightSpans; _a < _b.length; _a++) { + var highlightSpan = _b[_a]; + result.push({ + fileName: entry.fileName, + textSpan: highlightSpan.textSpan, + isWriteAccess: highlightSpan.kind === HighlightSpanKind.writtenReference + }); + } + } + return result; + } + } + function convertReferences(referenceSymbols) { + if (!referenceSymbols) { + return undefined; + } + var referenceEntries = []; + for (var _i = 0; _i < referenceSymbols.length; _i++) { + var referenceSymbol = referenceSymbols[_i]; + ts.addRange(referenceEntries, referenceSymbol.references); + } + return referenceEntries; + } + function findRenameLocations(fileName, position, findInStrings, findInComments) { + var referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments); + return convertReferences(referencedSymbols); + } + function getReferencesAtPosition(fileName, position) { + var referencedSymbols = findReferencedSymbols(fileName, position, false, false); + return convertReferences(referencedSymbols); + } + function findReferences(fileName, position) { + var referencedSymbols = findReferencedSymbols(fileName, position, false, false); + return ts.filter(referencedSymbols, function (rs) { return !!rs.definition; }); + } + function findReferencedSymbols(fileName, position, findInStrings, findInComments) { + synchronizeHostData(); + var sourceFile = getValidSourceFile(fileName); + var node = ts.getTouchingPropertyName(sourceFile, position); + if (!node) { + return undefined; + } + if (node.kind !== 65 && + !isLiteralNameOfPropertyDeclarationOrIndexAccess(node) && + !isNameOfExternalModuleImportOrDeclaration(node)) { + return undefined; + } + ts.Debug.assert(node.kind === 65 || node.kind === 7 || node.kind === 8); + return getReferencedSymbolsForNodes(node, program.getSourceFiles(), findInStrings, findInComments); + } + function getReferencedSymbolsForNodes(node, sourceFiles, findInStrings, findInComments) { + var typeChecker = program.getTypeChecker(); + if (isLabelName(node)) { + if (isJumpStatementTarget(node)) { + var labelDefinition = getTargetLabel(node.parent, node.text); + return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : undefined; + } + else { + return getLabelReferencesInNode(node.parent, node); + } + } + if (node.kind === 93) { + return getReferencesForThisKeyword(node, sourceFiles); + } + if (node.kind === 91) { + return getReferencesForSuperKeyword(node); + } + var symbol = typeChecker.getSymbolAtLocation(node); + if (!symbol) { + return undefined; + } + var declarations = symbol.declarations; + if (!declarations || !declarations.length) { + return undefined; + } + var result; + var searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations); + var declaredName = getDeclaredName(symbol, node); + var scope = getSymbolScope(symbol); + var symbolToIndex = []; + if (scope) { + result = []; + getReferencesInNode(scope, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex); + } + else { + var internedName = getInternedName(symbol, node, declarations); + for (var _i = 0; _i < sourceFiles.length; _i++) { + var sourceFile = sourceFiles[_i]; + cancellationToken.throwIfCancellationRequested(); + var nameTable = getNameTable(sourceFile); + if (ts.lookUp(nameTable, internedName)) { + result = result || []; + getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex); + } + } + } + return result; + function getDefinition(symbol) { + var info = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, node.getSourceFile(), getContainerNode(node), node); + var name = ts.map(info.displayParts, function (p) { return p.text; }).join(""); + var declarations = symbol.declarations; + if (!declarations || declarations.length === 0) { + return undefined; + } + return { + containerKind: "", + containerName: "", + name: name, + kind: info.symbolKind, + fileName: declarations[0].getSourceFile().fileName, + textSpan: ts.createTextSpan(declarations[0].getStart(), 0) + }; + } + function isImportOrExportSpecifierName(location) { + return location.parent && + (location.parent.kind === 213 || location.parent.kind === 217) && + location.parent.propertyName === location; + } + function isImportOrExportSpecifierImportSymbol(symbol) { + return (symbol.flags & 8388608) && ts.forEach(symbol.declarations, function (declaration) { + return declaration.kind === 213 || declaration.kind === 217; + }); + } + function getDeclaredName(symbol, location) { + var functionExpression = ts.forEach(symbol.declarations, function (d) { return d.kind === 162 ? d : undefined; }); + var name; + if (functionExpression && functionExpression.name) { + name = functionExpression.name.text; + } + if (isImportOrExportSpecifierName(location)) { + return location.getText(); + } + name = typeChecker.symbolToString(symbol); + return stripQuotes(name); + } + function getInternedName(symbol, location, declarations) { + if (isImportOrExportSpecifierName(location)) { + return location.getText(); + } + var functionExpression = ts.forEach(declarations, function (d) { return d.kind === 162 ? d : undefined; }); + var name = functionExpression && functionExpression.name + ? functionExpression.name.text + : symbol.name; + return stripQuotes(name); + } + function stripQuotes(name) { + var length = name.length; + if (length >= 2 && name.charCodeAt(0) === 34 && name.charCodeAt(length - 1) === 34) { + return name.substring(1, length - 1); + } + ; + return name; + } + function getSymbolScope(symbol) { + if (symbol.flags & (4 | 8192)) { + var privateDeclaration = ts.forEach(symbol.getDeclarations(), function (d) { return (d.flags & 32) ? d : undefined; }); + if (privateDeclaration) { + return ts.getAncestor(privateDeclaration, 201); + } + } + if (symbol.flags & 8388608) { + return undefined; + } + if (symbol.parent || (symbol.flags & 268435456)) { + return undefined; + } + var scope = undefined; + var declarations = symbol.getDeclarations(); + if (declarations) { + for (var _i = 0; _i < declarations.length; _i++) { + var declaration = declarations[_i]; + var container = getContainerNode(declaration); + if (!container) { + return undefined; + } + if (scope && scope !== container) { + return undefined; + } + if (container.kind === 227 && !ts.isExternalModule(container)) { + return undefined; + } + scope = container; + } + } + return scope; + } + function getPossibleSymbolReferencePositions(sourceFile, symbolName, start, end) { + var positions = []; + if (!symbolName || !symbolName.length) { + return positions; + } + var text = sourceFile.text; + var sourceLength = text.length; + var symbolNameLength = symbolName.length; + var position = text.indexOf(symbolName, start); + while (position >= 0) { + cancellationToken.throwIfCancellationRequested(); + if (position > end) + break; + var endPosition = position + symbolNameLength; + if ((position === 0 || !ts.isIdentifierPart(text.charCodeAt(position - 1), 2)) && + (endPosition === sourceLength || !ts.isIdentifierPart(text.charCodeAt(endPosition), 2))) { + positions.push(position); + } + position = text.indexOf(symbolName, position + symbolNameLength + 1); + } + return positions; + } + function getLabelReferencesInNode(container, targetLabel) { + var references = []; + var sourceFile = container.getSourceFile(); + var labelName = targetLabel.text; + var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, labelName, container.getStart(), container.getEnd()); + ts.forEach(possiblePositions, function (position) { + cancellationToken.throwIfCancellationRequested(); + var node = ts.getTouchingWord(sourceFile, position); + if (!node || node.getWidth() !== labelName.length) { + return; + } + if (node === targetLabel || + (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel)) { + references.push(getReferenceEntryFromNode(node)); + } + }); + var definition = { + containerKind: "", + containerName: "", + fileName: targetLabel.getSourceFile().fileName, + kind: ScriptElementKind.label, + name: labelName, + textSpan: ts.createTextSpanFromBounds(targetLabel.getStart(), targetLabel.getEnd()) + }; + return [{ definition: definition, references: references }]; + } + function isValidReferencePosition(node, searchSymbolName) { + if (node) { + switch (node.kind) { + case 65: + return node.getWidth() === searchSymbolName.length; + case 8: + if (isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || + isNameOfExternalModuleImportOrDeclaration(node)) { + return node.getWidth() === searchSymbolName.length + 2; + } + break; + case 7: + if (isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) { + return node.getWidth() === searchSymbolName.length; + } + break; + } + } + return false; + } + function getReferencesInNode(container, searchSymbol, searchText, searchLocation, searchMeaning, findInStrings, findInComments, result, symbolToIndex) { + var sourceFile = container.getSourceFile(); + var tripleSlashDirectivePrefixRegex = /^\/\/\/\s*= 0) { + var referencedSymbol = getReferencedSymbol(shorthandValueSymbol); + referencedSymbol.references.push(getReferenceEntryFromNode(referenceSymbolDeclaration.name)); + } + } + }); + } + return; + function getReferencedSymbol(symbol) { + var symbolId = ts.getSymbolId(symbol); + var index = symbolToIndex[symbolId]; + if (index === undefined) { + index = result.length; + symbolToIndex[symbolId] = index; + result.push({ + definition: getDefinition(symbol), + references: [] + }); + } + return result[index]; + } + function isInString(position) { + var token = ts.getTokenAtPosition(sourceFile, position); + return token && token.kind === 8 && position > token.getStart(); + } + function isInComment(position) { + var token = ts.getTokenAtPosition(sourceFile, position); + if (token && position < token.getStart()) { + var commentRanges = ts.getLeadingCommentRanges(sourceFile.text, token.pos); + return ts.forEach(commentRanges, function (c) { + if (c.pos < position && position < c.end) { + var commentText = sourceFile.text.substring(c.pos, c.end); + if (!tripleSlashDirectivePrefixRegex.test(commentText)) { + return true; + } + } + }); + } + return false; + } + } + function getReferencesForSuperKeyword(superKeyword) { + var searchSpaceNode = ts.getSuperContainer(superKeyword, false); + if (!searchSpaceNode) { + return undefined; + } + var staticFlag = 128; + switch (searchSpaceNode.kind) { + case 132: + case 131: + case 134: + case 133: + case 135: + case 136: + case 137: + staticFlag &= searchSpaceNode.flags; + searchSpaceNode = searchSpaceNode.parent; + break; + default: + return undefined; + } + var references = []; + var sourceFile = searchSpaceNode.getSourceFile(); + var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "super", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); + ts.forEach(possiblePositions, function (position) { + cancellationToken.throwIfCancellationRequested(); + var node = ts.getTouchingWord(sourceFile, position); + if (!node || node.kind !== 91) { + return; + } + var container = ts.getSuperContainer(node, false); + if (container && (128 & container.flags) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) { + references.push(getReferenceEntryFromNode(node)); + } + }); + var definition = getDefinition(searchSpaceNode.symbol); + return [{ definition: definition, references: references }]; + } + function getReferencesForThisKeyword(thisOrSuperKeyword, sourceFiles) { + var searchSpaceNode = ts.getThisContainer(thisOrSuperKeyword, false); + var staticFlag = 128; + switch (searchSpaceNode.kind) { + case 134: + case 133: + if (ts.isObjectLiteralMethod(searchSpaceNode)) { + break; + } + case 132: + case 131: + case 135: + case 136: + case 137: + staticFlag &= searchSpaceNode.flags; + searchSpaceNode = searchSpaceNode.parent; + break; + case 227: + if (ts.isExternalModule(searchSpaceNode)) { + return undefined; + } + case 200: + case 162: + break; + default: + return undefined; + } + var references = []; + var possiblePositions; + if (searchSpaceNode.kind === 227) { + ts.forEach(sourceFiles, function (sourceFile) { + possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", sourceFile.getStart(), sourceFile.getEnd()); + getThisReferencesInFile(sourceFile, sourceFile, possiblePositions, references); + }); + } + else { + var sourceFile = searchSpaceNode.getSourceFile(); + possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); + getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, references); + } + return [{ + definition: { + containerKind: "", + containerName: "", + fileName: node.getSourceFile().fileName, + kind: ScriptElementKind.variableElement, + name: "this", + textSpan: ts.createTextSpanFromBounds(node.getStart(), node.getEnd()) + }, + references: references + }]; + function getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, result) { + ts.forEach(possiblePositions, function (position) { + cancellationToken.throwIfCancellationRequested(); + var node = ts.getTouchingWord(sourceFile, position); + if (!node || node.kind !== 93) { + return; + } + var container = ts.getThisContainer(node, false); + switch (searchSpaceNode.kind) { + case 162: + case 200: + if (searchSpaceNode.symbol === container.symbol) { + result.push(getReferenceEntryFromNode(node)); + } + break; + case 134: + case 133: + if (ts.isObjectLiteralMethod(searchSpaceNode) && searchSpaceNode.symbol === container.symbol) { + result.push(getReferenceEntryFromNode(node)); + } + break; + case 201: + if (container.parent && searchSpaceNode.symbol === container.parent.symbol && (container.flags & 128) === staticFlag) { + result.push(getReferenceEntryFromNode(node)); + } + break; + case 227: + if (container.kind === 227 && !ts.isExternalModule(container)) { + result.push(getReferenceEntryFromNode(node)); + } + break; + } + }); + } + } + function populateSearchSymbolSet(symbol, location) { + var result = [symbol]; + if (isImportOrExportSpecifierImportSymbol(symbol)) { + result.push(typeChecker.getAliasedSymbol(symbol)); + } + if (isNameOfPropertyAssignment(location)) { + ts.forEach(getPropertySymbolsFromContextualType(location), function (contextualSymbol) { + result.push.apply(result, typeChecker.getRootSymbols(contextualSymbol)); + }); + var shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(location.parent); + if (shorthandValueSymbol) { + result.push(shorthandValueSymbol); + } + } + ts.forEach(typeChecker.getRootSymbols(symbol), function (rootSymbol) { + if (rootSymbol !== symbol) { + result.push(rootSymbol); + } + if (rootSymbol.parent && rootSymbol.parent.flags & (32 | 64)) { + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result); + } + }); + return result; + } + function getPropertySymbolsFromBaseTypes(symbol, propertyName, result) { + if (symbol && symbol.flags & (32 | 64)) { + ts.forEach(symbol.getDeclarations(), function (declaration) { + if (declaration.kind === 201) { + getPropertySymbolFromTypeReference(ts.getClassExtendsHeritageClauseElement(declaration)); + ts.forEach(ts.getClassImplementsHeritageClauseElements(declaration), getPropertySymbolFromTypeReference); + } + else if (declaration.kind === 202) { + ts.forEach(ts.getInterfaceBaseTypeNodes(declaration), getPropertySymbolFromTypeReference); + } + }); + } + return; + function getPropertySymbolFromTypeReference(typeReference) { + if (typeReference) { + var type = typeChecker.getTypeAtLocation(typeReference); + if (type) { + var propertySymbol = typeChecker.getPropertyOfType(type, propertyName); + if (propertySymbol) { + result.push(propertySymbol); + } + getPropertySymbolsFromBaseTypes(type.symbol, propertyName, result); + } + } + } + } + function getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation) { + if (searchSymbols.indexOf(referenceSymbol) >= 0) { + return referenceSymbol; + } + if (isImportOrExportSpecifierImportSymbol(referenceSymbol)) { + var aliasedSymbol = typeChecker.getAliasedSymbol(referenceSymbol); + if (searchSymbols.indexOf(aliasedSymbol) >= 0) { + return aliasedSymbol; + } + } + if (isNameOfPropertyAssignment(referenceLocation)) { + return ts.forEach(getPropertySymbolsFromContextualType(referenceLocation), function (contextualSymbol) { + return ts.forEach(typeChecker.getRootSymbols(contextualSymbol), function (s) { return searchSymbols.indexOf(s) >= 0 ? s : undefined; }); + }); + } + return ts.forEach(typeChecker.getRootSymbols(referenceSymbol), function (rootSymbol) { + if (searchSymbols.indexOf(rootSymbol) >= 0) { + return rootSymbol; + } + if (rootSymbol.parent && rootSymbol.parent.flags & (32 | 64)) { + var result_2 = []; + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result_2); + return ts.forEach(result_2, function (s) { return searchSymbols.indexOf(s) >= 0 ? s : undefined; }); + } + return undefined; + }); + } + function getPropertySymbolsFromContextualType(node) { + if (isNameOfPropertyAssignment(node)) { + var objectLiteral = node.parent.parent; + var contextualType = typeChecker.getContextualType(objectLiteral); + var name_2 = node.text; + if (contextualType) { + if (contextualType.flags & 16384) { + var unionProperty = contextualType.getProperty(name_2); + if (unionProperty) { + return [unionProperty]; + } + else { + var result_3 = []; + ts.forEach(contextualType.types, function (t) { + var symbol = t.getProperty(name_2); + if (symbol) { + result_3.push(symbol); + } + }); + return result_3; + } + } + else { + var symbol_1 = contextualType.getProperty(name_2); + if (symbol_1) { + return [symbol_1]; + } + } + } + } + return undefined; + } + function getIntersectingMeaningFromDeclarations(meaning, declarations) { + if (declarations) { + var lastIterationMeaning; + do { + lastIterationMeaning = meaning; + for (var _i = 0; _i < declarations.length; _i++) { + var declaration = declarations[_i]; + var declarationMeaning = getMeaningFromDeclaration(declaration); + if (declarationMeaning & meaning) { + meaning |= declarationMeaning; + } + } + } while (meaning !== lastIterationMeaning); + } + return meaning; + } + } + function getReferenceEntryFromNode(node) { + var start = node.getStart(); + var end = node.getEnd(); + if (node.kind === 8) { + start += 1; + end -= 1; + } + return { + fileName: node.getSourceFile().fileName, + textSpan: ts.createTextSpanFromBounds(start, end), + isWriteAccess: isWriteAccess(node) + }; + } + function isWriteAccess(node) { + if (node.kind === 65 && ts.isDeclarationName(node)) { + return true; + } + var parent = node.parent; + if (parent) { + if (parent.kind === 168 || parent.kind === 167) { + return true; + } + else if (parent.kind === 169 && parent.left === node) { + var operator = parent.operatorToken.kind; + return 53 <= operator && operator <= 64; + } + } + return false; + } + function getNavigateToItems(searchValue, maxResultCount) { + synchronizeHostData(); + return ts.NavigateTo.getNavigateToItems(program, cancellationToken, searchValue, maxResultCount); + } + function containErrors(diagnostics) { + return ts.forEach(diagnostics, function (diagnostic) { return diagnostic.category === ts.DiagnosticCategory.Error; }); + } + function getEmitOutput(fileName) { + synchronizeHostData(); + var sourceFile = getValidSourceFile(fileName); + var outputFiles = []; + function writeFile(fileName, data, writeByteOrderMark) { + outputFiles.push({ + name: fileName, + writeByteOrderMark: writeByteOrderMark, + text: data + }); + } + var emitOutput = program.emit(sourceFile, writeFile); + return { + outputFiles: outputFiles, + emitSkipped: emitOutput.emitSkipped + }; + } + function getMeaningFromDeclaration(node) { + switch (node.kind) { + case 129: + case 198: + case 152: + case 132: + case 131: + case 224: + case 225: + case 226: + case 134: + case 133: + case 135: + case 136: + case 137: + case 200: + case 162: + case 163: + case 223: + return 1; + case 128: + case 202: + case 203: + case 145: + return 2; + case 201: + case 204: + return 1 | 2; + case 205: + if (node.name.kind === 8) { + return 4 | 1; + } + else if (ts.getModuleInstanceState(node) === 1) { + return 4 | 1; + } + else { + return 4; + } + case 212: + case 213: + case 208: + case 209: + case 214: + case 215: + return 1 | 2 | 4; + case 227: + return 4 | 1; + } + return 1 | 2 | 4; + ts.Debug.fail("Unknown declaration type"); + } + function isTypeReference(node) { + if (ts.isRightSideOfQualifiedNameOrPropertyAccess(node)) { + node = node.parent; + } + return node.parent.kind === 141 || node.parent.kind === 177; + } + function isNamespaceReference(node) { + return isQualifiedNameNamespaceReference(node) || isPropertyAccessNamespaceReference(node); + } + function isPropertyAccessNamespaceReference(node) { + var root = node; + var isLastClause = true; + if (root.parent.kind === 155) { + while (root.parent && root.parent.kind === 155) { + root = root.parent; + } + isLastClause = root.name === node; + } + if (!isLastClause && root.parent.kind === 177 && root.parent.parent.kind === 222) { + var decl = root.parent.parent.parent; + return (decl.kind === 201 && root.parent.parent.token === 102) || + (decl.kind === 202 && root.parent.parent.token === 79); + } + return false; + } + function isQualifiedNameNamespaceReference(node) { + var root = node; + var isLastClause = true; + if (root.parent.kind === 126) { + while (root.parent && root.parent.kind === 126) { + root = root.parent; + } + isLastClause = root.right === node; + } + return root.parent.kind === 141 && !isLastClause; + } + function isInRightSideOfImport(node) { + while (node.parent.kind === 126) { + node = node.parent; + } + return ts.isInternalModuleImportEqualsDeclaration(node.parent) && node.parent.moduleReference === node; + } + function getMeaningFromRightHandSideOfImportEquals(node) { + ts.Debug.assert(node.kind === 65); + if (node.parent.kind === 126 && + node.parent.right === node && + node.parent.parent.kind === 208) { + return 1 | 2 | 4; + } + return 4; + } + function getMeaningFromLocation(node) { + if (node.parent.kind === 214) { + return 1 | 2 | 4; + } + else if (isInRightSideOfImport(node)) { + return getMeaningFromRightHandSideOfImportEquals(node); + } + else if (ts.isDeclarationName(node)) { + return getMeaningFromDeclaration(node.parent); + } + else if (isTypeReference(node)) { + return 2; + } + else if (isNamespaceReference(node)) { + return 4; + } + else { + return 1; + } + } + function getSignatureHelpItems(fileName, position) { + synchronizeHostData(); + var sourceFile = getValidSourceFile(fileName); + return ts.SignatureHelp.getSignatureHelpItems(program, sourceFile, position, cancellationToken); + } + function getSourceFile(fileName) { + return syntaxTreeCache.getCurrentSourceFile(fileName); + } + function getNameOrDottedNameSpan(fileName, startPos, endPos) { + var sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + var node = ts.getTouchingPropertyName(sourceFile, startPos); + if (!node) { + return; + } + switch (node.kind) { + case 155: + case 126: + case 8: + case 80: + case 95: + case 89: + case 91: + case 93: + case 65: + break; + default: + return; + } + var nodeForStartPos = node; + while (true) { + if (isRightSideOfPropertyAccess(nodeForStartPos) || isRightSideOfQualifiedName(nodeForStartPos)) { + nodeForStartPos = nodeForStartPos.parent; + } + else if (isNameOfModuleDeclaration(nodeForStartPos)) { + if (nodeForStartPos.parent.parent.kind === 205 && + nodeForStartPos.parent.parent.body === nodeForStartPos.parent) { + nodeForStartPos = nodeForStartPos.parent.parent.name; + } + else { + break; + } + } + else { + break; + } + } + return ts.createTextSpanFromBounds(nodeForStartPos.getStart(), node.getEnd()); + } + function getBreakpointStatementAtPosition(fileName, position) { + var sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + return ts.BreakpointResolver.spanInSourceFileAtLocation(sourceFile, position); + } + function getNavigationBarItems(fileName) { + var sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + return ts.NavigationBar.getNavigationBarItems(sourceFile); + } + function getSemanticClassifications(fileName, span) { + synchronizeHostData(); + var sourceFile = getValidSourceFile(fileName); + var typeChecker = program.getTypeChecker(); + var result = []; + processNode(sourceFile); + return result; + function classifySymbol(symbol, meaningAtPosition) { + var flags = symbol.getFlags(); + if (flags & 32) { + return ClassificationTypeNames.className; + } + else if (flags & 384) { + return ClassificationTypeNames.enumName; + } + else if (flags & 524288) { + return ClassificationTypeNames.typeAlias; + } + else if (meaningAtPosition & 2) { + if (flags & 64) { + return ClassificationTypeNames.interfaceName; + } + else if (flags & 262144) { + return ClassificationTypeNames.typeParameterName; + } + } + else if (flags & 1536) { + if (meaningAtPosition & 4 || + (meaningAtPosition & 1 && hasValueSideModule(symbol))) { + return ClassificationTypeNames.moduleName; + } + } + return undefined; + function hasValueSideModule(symbol) { + return ts.forEach(symbol.declarations, function (declaration) { + return declaration.kind === 205 && ts.getModuleInstanceState(declaration) == 1; + }); + } + } + function processNode(node) { + if (node && ts.textSpanIntersectsWith(span, node.getStart(), node.getWidth())) { + if (node.kind === 65 && node.getWidth() > 0) { + var symbol = typeChecker.getSymbolAtLocation(node); + if (symbol) { + var type = classifySymbol(symbol, getMeaningFromLocation(node)); + if (type) { + result.push({ + textSpan: ts.createTextSpan(node.getStart(), node.getWidth()), + classificationType: type + }); + } + } + } + ts.forEachChild(node, processNode); + } + } + } + function getSyntacticClassifications(fileName, span) { + var sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + var triviaScanner = ts.createScanner(2, false, sourceFile.text); + var mergeConflictScanner = ts.createScanner(2, false, sourceFile.text); + var result = []; + processElement(sourceFile); + return result; + function classifyLeadingTrivia(token) { + var tokenStart = ts.skipTrivia(sourceFile.text, token.pos, false); + if (tokenStart === token.pos) { + return; + } + triviaScanner.setTextPos(token.pos); + while (true) { + var start = triviaScanner.getTextPos(); + var kind = triviaScanner.scan(); + var end = triviaScanner.getTextPos(); + var width = end - start; + if (ts.textSpanIntersectsWith(span, start, width)) { + if (!ts.isTrivia(kind)) { + return; + } + if (ts.isComment(kind)) { + result.push({ + textSpan: ts.createTextSpan(start, width), + classificationType: ClassificationTypeNames.comment + }); + continue; + } + if (kind === 6) { + var text = sourceFile.text; + var ch = text.charCodeAt(start); + if (ch === 60 || ch === 62) { + result.push({ + textSpan: ts.createTextSpan(start, width), + classificationType: ClassificationTypeNames.comment + }); + continue; + } + ts.Debug.assert(ch === 61); + classifyDisabledMergeCode(text, start, end); + } + } + } + } + function classifyDisabledMergeCode(text, start, end) { + for (var i = start; i < end; i++) { + if (ts.isLineBreak(text.charCodeAt(i))) { + break; + } + } + result.push({ + textSpan: ts.createTextSpanFromBounds(start, i), + classificationType: ClassificationTypeNames.comment + }); + mergeConflictScanner.setTextPos(i); + while (mergeConflictScanner.getTextPos() < end) { + classifyDisabledCodeToken(); + } + } + function classifyDisabledCodeToken() { + var start = mergeConflictScanner.getTextPos(); + var tokenKind = mergeConflictScanner.scan(); + var end = mergeConflictScanner.getTextPos(); + var type = classifyTokenType(tokenKind); + if (type) { + result.push({ + textSpan: ts.createTextSpanFromBounds(start, end), + classificationType: type + }); + } + } + function classifyToken(token) { + classifyLeadingTrivia(token); + if (token.getWidth() > 0) { + var type = classifyTokenType(token.kind, token); + if (type) { + result.push({ + textSpan: ts.createTextSpan(token.getStart(), token.getWidth()), + classificationType: type + }); + } + } + } + function classifyTokenType(tokenKind, token) { + if (ts.isKeyword(tokenKind)) { + return ClassificationTypeNames.keyword; + } + if (tokenKind === 24 || tokenKind === 25) { + if (token && ts.getTypeArgumentOrTypeParameterList(token.parent)) { + return ClassificationTypeNames.punctuation; + } + } + if (ts.isPunctuation(tokenKind)) { + if (token) { + if (tokenKind === 53) { + if (token.parent.kind === 198 || + token.parent.kind === 132 || + token.parent.kind === 129) { + return ClassificationTypeNames.operator; + } + } + if (token.parent.kind === 169 || + token.parent.kind === 167 || + token.parent.kind === 168 || + token.parent.kind === 170) { + return ClassificationTypeNames.operator; + } + } + return ClassificationTypeNames.punctuation; + } + else if (tokenKind === 7) { + return ClassificationTypeNames.numericLiteral; + } + else if (tokenKind === 8) { + return ClassificationTypeNames.stringLiteral; + } + else if (tokenKind === 9) { + return ClassificationTypeNames.stringLiteral; + } + else if (ts.isTemplateLiteralKind(tokenKind)) { + return ClassificationTypeNames.stringLiteral; + } + else if (tokenKind === 65) { + if (token) { + switch (token.parent.kind) { + case 201: + if (token.parent.name === token) { + return ClassificationTypeNames.className; + } + return; + case 128: + if (token.parent.name === token) { + return ClassificationTypeNames.typeParameterName; + } + return; + case 202: + if (token.parent.name === token) { + return ClassificationTypeNames.interfaceName; + } + return; + case 204: + if (token.parent.name === token) { + return ClassificationTypeNames.enumName; + } + return; + case 205: + if (token.parent.name === token) { + return ClassificationTypeNames.moduleName; + } + return; + } + } + return ClassificationTypeNames.text; + } + } + function processElement(element) { + if (ts.textSpanIntersectsWith(span, element.getFullStart(), element.getFullWidth())) { + var children = element.getChildren(); + for (var _i = 0; _i < children.length; _i++) { + var child = children[_i]; + if (ts.isToken(child)) { + classifyToken(child); + } + else { + processElement(child); + } + } + } + } + } + function getOutliningSpans(fileName) { + var sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + return ts.OutliningElementsCollector.collectElements(sourceFile); + } + function getBraceMatchingAtPosition(fileName, position) { + var sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + var result = []; + var token = ts.getTouchingToken(sourceFile, position); + if (token.getStart(sourceFile) === position) { + var matchKind = getMatchingTokenKind(token); + if (matchKind) { + var parentElement = token.parent; + var childNodes = parentElement.getChildren(sourceFile); + for (var _i = 0; _i < childNodes.length; _i++) { + var current = childNodes[_i]; + if (current.kind === matchKind) { + var range1 = ts.createTextSpan(token.getStart(sourceFile), token.getWidth(sourceFile)); + var range2 = ts.createTextSpan(current.getStart(sourceFile), current.getWidth(sourceFile)); + if (range1.start < range2.start) { + result.push(range1, range2); + } + else { + result.push(range2, range1); + } + break; + } + } + } + } + return result; + function getMatchingTokenKind(token) { + switch (token.kind) { + case 14: return 15; + case 16: return 17; + case 18: return 19; + case 24: return 25; + case 15: return 14; + case 17: return 16; + case 19: return 18; + case 25: return 24; + } + return undefined; + } + } + function getIndentationAtPosition(fileName, position, editorOptions) { + var start = new Date().getTime(); + var sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + log("getIndentationAtPosition: getCurrentSourceFile: " + (new Date().getTime() - start)); + start = new Date().getTime(); + var result = ts.formatting.SmartIndenter.getIndentation(position, sourceFile, editorOptions); + log("getIndentationAtPosition: computeIndentation : " + (new Date().getTime() - start)); + return result; + } + function getFormattingEditsForRange(fileName, start, end, options) { + var sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + return ts.formatting.formatSelection(start, end, sourceFile, getRuleProvider(options), options); + } + function getFormattingEditsForDocument(fileName, options) { + var sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + return ts.formatting.formatDocument(sourceFile, getRuleProvider(options), options); + } + function getFormattingEditsAfterKeystroke(fileName, position, key, options) { + var sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + if (key === "}") { + return ts.formatting.formatOnClosingCurly(position, sourceFile, getRuleProvider(options), options); + } + else if (key === ";") { + return ts.formatting.formatOnSemicolon(position, sourceFile, getRuleProvider(options), options); + } + else if (key === "\n") { + return ts.formatting.formatOnEnter(position, sourceFile, getRuleProvider(options), options); + } + return []; + } + function getTodoComments(fileName, descriptors) { + synchronizeHostData(); + var sourceFile = getValidSourceFile(fileName); + cancellationToken.throwIfCancellationRequested(); + var fileContents = sourceFile.text; + var result = []; + if (descriptors.length > 0) { + var regExp = getTodoCommentsRegExp(); + var matchArray; + while (matchArray = regExp.exec(fileContents)) { + cancellationToken.throwIfCancellationRequested(); + var firstDescriptorCaptureIndex = 3; + ts.Debug.assert(matchArray.length === descriptors.length + firstDescriptorCaptureIndex); + var preamble = matchArray[1]; + var matchPosition = matchArray.index + preamble.length; + var token = ts.getTokenAtPosition(sourceFile, matchPosition); + if (!isInsideComment(sourceFile, token, matchPosition)) { + continue; + } + var descriptor = undefined; + for (var i = 0, n = descriptors.length; i < n; i++) { + if (matchArray[i + firstDescriptorCaptureIndex]) { + descriptor = descriptors[i]; + } + } + ts.Debug.assert(descriptor !== undefined); + if (isLetterOrDigit(fileContents.charCodeAt(matchPosition + descriptor.text.length))) { + continue; + } + var message = matchArray[2]; + result.push({ + descriptor: descriptor, + message: message, + position: matchPosition + }); + } + } + return result; + function escapeRegExp(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + } + function getTodoCommentsRegExp() { + // NOTE: ?: means 'non-capture group'. It allows us to have groups without having to + // filter them out later in the final result array. + var singleLineCommentStart = /(?:\/\/+\s*)/.source; + var multiLineCommentStart = /(?:\/\*+\s*)/.source; + var anyNumberOfSpacesAndAsterixesAtStartOfLine = /(?:^(?:\s|\*)*)/.source; + var preamble = "(" + anyNumberOfSpacesAndAsterixesAtStartOfLine + "|" + singleLineCommentStart + "|" + multiLineCommentStart + ")"; + var literals = "(?:" + ts.map(descriptors, function (d) { return "(" + escapeRegExp(d.text) + ")"; }).join("|") + ")"; + var endOfLineOrEndOfComment = /(?:$|\*\/)/.source; + var messageRemainder = /(?:.*?)/.source; + var messagePortion = "(" + literals + messageRemainder + ")"; + var regExpString = preamble + messagePortion + endOfLineOrEndOfComment; + return new RegExp(regExpString, "gim"); + } + function isLetterOrDigit(char) { + return (char >= 97 && char <= 122) || + (char >= 65 && char <= 90) || + (char >= 48 && char <= 57); + } + } + function getRenameInfo(fileName, position) { + synchronizeHostData(); + var sourceFile = getValidSourceFile(fileName); + var typeChecker = program.getTypeChecker(); + var node = ts.getTouchingWord(sourceFile, position); + if (node && node.kind === 65) { + var symbol = typeChecker.getSymbolAtLocation(node); + if (symbol) { + var declarations = symbol.getDeclarations(); + if (declarations && declarations.length > 0) { + var defaultLibFileName = host.getDefaultLibFileName(host.getCompilationSettings()); + if (defaultLibFileName) { + for (var _i = 0; _i < declarations.length; _i++) { + var current = declarations[_i]; + var sourceFile_1 = current.getSourceFile(); + if (sourceFile_1 && getCanonicalFileName(ts.normalizePath(sourceFile_1.fileName)) === getCanonicalFileName(ts.normalizePath(defaultLibFileName))) { + return getRenameInfoError(ts.getLocaleSpecificMessage(ts.Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library.key)); + } + } + } + var kind = getSymbolKind(symbol, node); + if (kind) { + return { + canRename: true, + localizedErrorMessage: undefined, + displayName: symbol.name, + fullDisplayName: typeChecker.getFullyQualifiedName(symbol), + kind: kind, + kindModifiers: getSymbolModifiers(symbol), + triggerSpan: ts.createTextSpan(node.getStart(), node.getWidth()) + }; + } + } + } + } + return getRenameInfoError(ts.getLocaleSpecificMessage(ts.Diagnostics.You_cannot_rename_this_element.key)); + function getRenameInfoError(localizedErrorMessage) { + return { + canRename: false, + localizedErrorMessage: localizedErrorMessage, + displayName: undefined, + fullDisplayName: undefined, + kind: undefined, + kindModifiers: undefined, + triggerSpan: undefined + }; + } + } + return { + dispose: dispose, + cleanupSemanticCache: cleanupSemanticCache, + getSyntacticDiagnostics: getSyntacticDiagnostics, + getSemanticDiagnostics: getSemanticDiagnostics, + getCompilerOptionsDiagnostics: getCompilerOptionsDiagnostics, + getSyntacticClassifications: getSyntacticClassifications, + getSemanticClassifications: getSemanticClassifications, + getCompletionsAtPosition: getCompletionsAtPosition, + getCompletionEntryDetails: getCompletionEntryDetails, + getSignatureHelpItems: getSignatureHelpItems, + getQuickInfoAtPosition: getQuickInfoAtPosition, + getDefinitionAtPosition: getDefinitionAtPosition, + getReferencesAtPosition: getReferencesAtPosition, + findReferences: findReferences, + getOccurrencesAtPosition: getOccurrencesAtPosition, + getDocumentHighlights: getDocumentHighlights, + getNameOrDottedNameSpan: getNameOrDottedNameSpan, + getBreakpointStatementAtPosition: getBreakpointStatementAtPosition, + getNavigateToItems: getNavigateToItems, + getRenameInfo: getRenameInfo, + findRenameLocations: findRenameLocations, + getNavigationBarItems: getNavigationBarItems, + getOutliningSpans: getOutliningSpans, + getTodoComments: getTodoComments, + getBraceMatchingAtPosition: getBraceMatchingAtPosition, + getIndentationAtPosition: getIndentationAtPosition, + getFormattingEditsForRange: getFormattingEditsForRange, + getFormattingEditsForDocument: getFormattingEditsForDocument, + getFormattingEditsAfterKeystroke: getFormattingEditsAfterKeystroke, + getEmitOutput: getEmitOutput, + getSourceFile: getSourceFile, + getProgram: getProgram + }; + } + ts.createLanguageService = createLanguageService; + function getNameTable(sourceFile) { + if (!sourceFile.nameTable) { + initializeNameTable(sourceFile); + } + return sourceFile.nameTable; + } + ts.getNameTable = getNameTable; + function initializeNameTable(sourceFile) { + var nameTable = {}; + walk(sourceFile); + sourceFile.nameTable = nameTable; + function walk(node) { + switch (node.kind) { + case 65: + nameTable[node.text] = node.text; + break; + case 8: + case 7: + if (ts.isDeclarationName(node) || + node.parent.kind === 219 || + isArgumentOfElementAccessExpression(node)) { + nameTable[node.text] = node.text; + } + break; + default: + ts.forEachChild(node, walk); + } + } + } + function isArgumentOfElementAccessExpression(node) { + return node && + node.parent && + node.parent.kind === 156 && + node.parent.argumentExpression === node; + } + function createClassifier() { + var scanner = ts.createScanner(2, false); + var noRegexTable = []; + noRegexTable[65] = true; + noRegexTable[8] = true; + noRegexTable[7] = true; + noRegexTable[9] = true; + noRegexTable[93] = true; + noRegexTable[38] = true; + noRegexTable[39] = true; + noRegexTable[17] = true; + noRegexTable[19] = true; + noRegexTable[15] = true; + noRegexTable[95] = true; + noRegexTable[80] = true; + var templateStack = []; + function canFollow(keyword1, keyword2) { + if (ts.isAccessibilityModifier(keyword1)) { + if (keyword2 === 116 || + keyword2 === 120 || + keyword2 === 114 || + keyword2 === 109) { + return true; + } + return false; + } + return true; + } + function getClassificationsForLine(text, lexState, syntacticClassifierAbsent) { + var offset = 0; + var token = 0; + var lastNonTriviaToken = 0; + while (templateStack.length > 0) { + templateStack.pop(); + } + switch (lexState) { + case 3: + text = '"\\\n' + text; + offset = 3; + break; + case 2: + text = "'\\\n" + text; + offset = 3; + break; + case 1: + text = "/*\n" + text; + offset = 3; + break; + case 4: + text = "`\n" + text; + offset = 2; + break; + case 5: + text = "}\n" + text; + offset = 2; + case 6: + templateStack.push(11); + break; + } + scanner.setText(text); + var result = { + finalLexState: 0, + entries: [] + }; + var angleBracketStack = 0; + do { + token = scanner.scan(); + if (!ts.isTrivia(token)) { + if ((token === 36 || token === 57) && !noRegexTable[lastNonTriviaToken]) { + if (scanner.reScanSlashToken() === 9) { + token = 9; + } + } + else if (lastNonTriviaToken === 20 && isKeyword(token)) { + token = 65; + } + else if (isKeyword(lastNonTriviaToken) && isKeyword(token) && !canFollow(lastNonTriviaToken, token)) { + token = 65; + } + else if (lastNonTriviaToken === 65 && + token === 24) { + angleBracketStack++; + } + else if (token === 25 && angleBracketStack > 0) { + angleBracketStack--; + } + else if (token === 112 || + token === 121 || + token === 119 || + token === 113 || + token === 122) { + if (angleBracketStack > 0 && !syntacticClassifierAbsent) { + token = 65; + } + } + else if (token === 11) { + templateStack.push(token); + } + else if (token === 14) { + if (templateStack.length > 0) { + templateStack.push(token); + } + } + else if (token === 15) { + if (templateStack.length > 0) { + var lastTemplateStackToken = ts.lastOrUndefined(templateStack); + if (lastTemplateStackToken === 11) { + token = scanner.reScanTemplateToken(); + if (token === 13) { + templateStack.pop(); + } + else { + ts.Debug.assert(token === 12, "Should have been a template middle. Was " + token); + } + } + else { + ts.Debug.assert(lastTemplateStackToken === 14, "Should have been an open brace. Was: " + token); + templateStack.pop(); + } + } + } + lastNonTriviaToken = token; + } + processToken(); + } while (token !== 1); + return result; + function processToken() { + var start = scanner.getTokenPos(); + var end = scanner.getTextPos(); + addResult(end - start, classFromKind(token)); + if (end >= text.length) { + if (token === 8) { + var tokenText = scanner.getTokenText(); + if (scanner.isUnterminated()) { + var lastCharIndex = tokenText.length - 1; + var numBackslashes = 0; + while (tokenText.charCodeAt(lastCharIndex - numBackslashes) === 92) { + numBackslashes++; + } + if (numBackslashes & 1) { + var quoteChar = tokenText.charCodeAt(0); + result.finalLexState = quoteChar === 34 + ? 3 + : 2; + } + } + } + else if (token === 3) { + if (scanner.isUnterminated()) { + result.finalLexState = 1; + } + } + else if (ts.isTemplateLiteralKind(token)) { + if (scanner.isUnterminated()) { + if (token === 13) { + result.finalLexState = 5; + } + else if (token === 10) { + result.finalLexState = 4; + } + else { + ts.Debug.fail("Only 'NoSubstitutionTemplateLiteral's and 'TemplateTail's can be unterminated; got SyntaxKind #" + token); + } + } + } + else if (templateStack.length > 0 && ts.lastOrUndefined(templateStack) === 11) { + result.finalLexState = 6; + } + } + } + function addResult(length, classification) { + if (length > 0) { + if (result.entries.length === 0) { + length -= offset; + } + result.entries.push({ length: length, classification: classification }); + } + } + } + function isBinaryExpressionOperatorToken(token) { + switch (token) { + case 35: + case 36: + case 37: + case 33: + case 34: + case 40: + case 41: + case 42: + case 24: + case 25: + case 26: + case 27: + case 87: + case 86: + case 28: + case 29: + case 30: + case 31: + case 43: + case 45: + case 44: + case 48: + case 49: + case 63: + case 62: + case 64: + case 59: + case 60: + case 61: + case 54: + case 55: + case 56: + case 57: + case 58: + case 53: + case 23: + return true; + default: + return false; + } + } + function isPrefixUnaryExpressionOperatorToken(token) { + switch (token) { + case 33: + case 34: + case 47: + case 46: + case 38: + case 39: + return true; + default: + return false; + } + } + function isKeyword(token) { + return token >= 66 && token <= 125; + } + function classFromKind(token) { + if (isKeyword(token)) { + return TokenClass.Keyword; + } + else if (isBinaryExpressionOperatorToken(token) || isPrefixUnaryExpressionOperatorToken(token)) { + return TokenClass.Operator; + } + else if (token >= 14 && token <= 64) { + return TokenClass.Punctuation; + } + switch (token) { + case 7: + return TokenClass.NumberLiteral; + case 8: + return TokenClass.StringLiteral; + case 9: + return TokenClass.RegExpLiteral; + case 6: + case 3: + case 2: + return TokenClass.Comment; + case 5: + case 4: + return TokenClass.Whitespace; + case 65: + default: + if (ts.isTemplateLiteralKind(token)) { + return TokenClass.StringLiteral; + } + return TokenClass.Identifier; + } + } + return { getClassificationsForLine: getClassificationsForLine }; + } + ts.createClassifier = createClassifier; + function getDefaultLibFilePath(options) { + if (typeof __dirname !== "undefined") { + return __dirname + ts.directorySeparator + ts.getDefaultLibFileName(options); + } + throw new Error("getDefaultLibFilePath is only supported when consumed as a node module. "); + } + ts.getDefaultLibFilePath = getDefaultLibFilePath; + function initializeServices() { + ts.objectAllocator = { + getNodeConstructor: function (kind) { + function Node() { + } + var proto = kind === 227 ? new SourceFileObject() : new NodeObject(); + proto.kind = kind; + proto.pos = 0; + proto.end = 0; + proto.flags = 0; + proto.parent = undefined; + Node.prototype = proto; + return Node; + }, + getSymbolConstructor: function () { return SymbolObject; }, + getTypeConstructor: function () { return TypeObject; }, + getSignatureConstructor: function () { return SignatureObject; }, + }; + } + initializeServices(); +})(ts || (ts = {})); diff --git a/dist/typescript/services/shims.js b/dist/typescript/services/shims.js new file mode 100644 index 000000000..79de27c65 --- /dev/null +++ b/dist/typescript/services/shims.js @@ -0,0 +1,563 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +/// +var debugObjectHost = this; +var ts; +(function (ts) { + function logInternalError(logger, err) { + logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); + } + var ScriptSnapshotShimAdapter = (function () { + function ScriptSnapshotShimAdapter(scriptSnapshotShim) { + this.scriptSnapshotShim = scriptSnapshotShim; + this.lineStartPositions = null; + } + ScriptSnapshotShimAdapter.prototype.getText = function (start, end) { + return this.scriptSnapshotShim.getText(start, end); + }; + ScriptSnapshotShimAdapter.prototype.getLength = function () { + return this.scriptSnapshotShim.getLength(); + }; + ScriptSnapshotShimAdapter.prototype.getChangeRange = function (oldSnapshot) { + var oldSnapshotShim = oldSnapshot; + var encoded = this.scriptSnapshotShim.getChangeRange(oldSnapshotShim.scriptSnapshotShim); + if (encoded == null) { + return null; + } + var decoded = JSON.parse(encoded); + return ts.createTextChangeRange(ts.createTextSpan(decoded.span.start, decoded.span.length), decoded.newLength); + }; + return ScriptSnapshotShimAdapter; + })(); + var LanguageServiceShimHostAdapter = (function () { + function LanguageServiceShimHostAdapter(shimHost) { + this.shimHost = shimHost; + } + LanguageServiceShimHostAdapter.prototype.log = function (s) { + this.shimHost.log(s); + }; + LanguageServiceShimHostAdapter.prototype.trace = function (s) { + this.shimHost.trace(s); + }; + LanguageServiceShimHostAdapter.prototype.error = function (s) { + this.shimHost.error(s); + }; + LanguageServiceShimHostAdapter.prototype.getCompilationSettings = function () { + var settingsJson = this.shimHost.getCompilationSettings(); + if (settingsJson == null || settingsJson == "") { + throw Error("LanguageServiceShimHostAdapter.getCompilationSettings: empty compilationSettings"); + return null; + } + return JSON.parse(settingsJson); + }; + LanguageServiceShimHostAdapter.prototype.getScriptFileNames = function () { + var encoded = this.shimHost.getScriptFileNames(); + return this.files = JSON.parse(encoded); + }; + LanguageServiceShimHostAdapter.prototype.getScriptSnapshot = function (fileName) { + if (this.files && this.files.indexOf(fileName) < 0) { + return undefined; + } + var scriptSnapshot = this.shimHost.getScriptSnapshot(fileName); + return scriptSnapshot && new ScriptSnapshotShimAdapter(scriptSnapshot); + }; + LanguageServiceShimHostAdapter.prototype.getScriptVersion = function (fileName) { + return this.shimHost.getScriptVersion(fileName); + }; + LanguageServiceShimHostAdapter.prototype.getLocalizedDiagnosticMessages = function () { + var diagnosticMessagesJson = this.shimHost.getLocalizedDiagnosticMessages(); + if (diagnosticMessagesJson == null || diagnosticMessagesJson == "") { + return null; + } + try { + return JSON.parse(diagnosticMessagesJson); + } + catch (e) { + this.log(e.description || "diagnosticMessages.generated.json has invalid JSON format"); + return null; + } + }; + LanguageServiceShimHostAdapter.prototype.getCancellationToken = function () { + return this.shimHost.getCancellationToken(); + }; + LanguageServiceShimHostAdapter.prototype.getCurrentDirectory = function () { + return this.shimHost.getCurrentDirectory(); + }; + LanguageServiceShimHostAdapter.prototype.getDefaultLibFileName = function (options) { + try { + return this.shimHost.getDefaultLibFileName(JSON.stringify(options)); + } + catch (e) { + return ""; + } + }; + return LanguageServiceShimHostAdapter; + })(); + ts.LanguageServiceShimHostAdapter = LanguageServiceShimHostAdapter; + var CoreServicesShimHostAdapter = (function () { + function CoreServicesShimHostAdapter(shimHost) { + this.shimHost = shimHost; + } + CoreServicesShimHostAdapter.prototype.readDirectory = function (rootDir, extension) { + var encoded = this.shimHost.readDirectory(rootDir, extension); + return JSON.parse(encoded); + }; + return CoreServicesShimHostAdapter; + })(); + ts.CoreServicesShimHostAdapter = CoreServicesShimHostAdapter; + function simpleForwardCall(logger, actionDescription, action) { + logger.log(actionDescription); + var start = Date.now(); + var result = action(); + var end = Date.now(); + logger.log(actionDescription + " completed in " + (end - start) + " msec"); + if (typeof (result) === "string") { + var str = result; + if (str.length > 128) { + str = str.substring(0, 128) + "..."; + } + logger.log(" result.length=" + str.length + ", result='" + JSON.stringify(str) + "'"); + } + return result; + } + function forwardJSONCall(logger, actionDescription, action) { + try { + var result = simpleForwardCall(logger, actionDescription, action); + return JSON.stringify({ result: result }); + } + catch (err) { + if (err instanceof ts.OperationCanceledException) { + return JSON.stringify({ canceled: true }); + } + logInternalError(logger, err); + err.description = actionDescription; + return JSON.stringify({ error: err }); + } + } + var ShimBase = (function () { + function ShimBase(factory) { + this.factory = factory; + factory.registerShim(this); + } + ShimBase.prototype.dispose = function (dummy) { + this.factory.unregisterShim(this); + }; + return ShimBase; + })(); + function realizeDiagnostics(diagnostics, newLine) { + return diagnostics.map(function (d) { return realizeDiagnostic(d, newLine); }); + } + ts.realizeDiagnostics = realizeDiagnostics; + function realizeDiagnostic(diagnostic, newLine) { + return { + message: ts.flattenDiagnosticMessageText(diagnostic.messageText, newLine), + start: diagnostic.start, + length: diagnostic.length, + category: ts.DiagnosticCategory[diagnostic.category].toLowerCase(), + code: diagnostic.code + }; + } + var LanguageServiceShimObject = (function (_super) { + __extends(LanguageServiceShimObject, _super); + function LanguageServiceShimObject(factory, host, languageService) { + _super.call(this, factory); + this.host = host; + this.languageService = languageService; + this.logger = this.host; + } + LanguageServiceShimObject.prototype.forwardJSONCall = function (actionDescription, action) { + return forwardJSONCall(this.logger, actionDescription, action); + }; + LanguageServiceShimObject.prototype.dispose = function (dummy) { + this.logger.log("dispose()"); + this.languageService.dispose(); + this.languageService = null; + if (debugObjectHost && debugObjectHost.CollectGarbage) { + debugObjectHost.CollectGarbage(); + this.logger.log("CollectGarbage()"); + } + this.logger = null; + _super.prototype.dispose.call(this, dummy); + }; + LanguageServiceShimObject.prototype.refresh = function (throwOnError) { + this.forwardJSONCall("refresh(" + throwOnError + ")", function () { + return null; + }); + }; + LanguageServiceShimObject.prototype.cleanupSemanticCache = function () { + var _this = this; + this.forwardJSONCall("cleanupSemanticCache()", function () { + _this.languageService.cleanupSemanticCache(); + return null; + }); + }; + LanguageServiceShimObject.prototype.realizeDiagnostics = function (diagnostics) { + var newLine = this.getNewLine(); + return ts.realizeDiagnostics(diagnostics, newLine); + }; + LanguageServiceShimObject.prototype.getSyntacticClassifications = function (fileName, start, length) { + var _this = this; + return this.forwardJSONCall("getSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")", function () { + var classifications = _this.languageService.getSyntacticClassifications(fileName, ts.createTextSpan(start, length)); + return classifications; + }); + }; + LanguageServiceShimObject.prototype.getSemanticClassifications = function (fileName, start, length) { + var _this = this; + return this.forwardJSONCall("getSemanticClassifications('" + fileName + "', " + start + ", " + length + ")", function () { + var classifications = _this.languageService.getSemanticClassifications(fileName, ts.createTextSpan(start, length)); + return classifications; + }); + }; + LanguageServiceShimObject.prototype.getNewLine = function () { + return this.host.getNewLine ? this.host.getNewLine() : "\r\n"; + }; + LanguageServiceShimObject.prototype.getSyntacticDiagnostics = function (fileName) { + var _this = this; + return this.forwardJSONCall("getSyntacticDiagnostics('" + fileName + "')", function () { + var diagnostics = _this.languageService.getSyntacticDiagnostics(fileName); + return _this.realizeDiagnostics(diagnostics); + }); + }; + LanguageServiceShimObject.prototype.getSemanticDiagnostics = function (fileName) { + var _this = this; + return this.forwardJSONCall("getSemanticDiagnostics('" + fileName + "')", function () { + var diagnostics = _this.languageService.getSemanticDiagnostics(fileName); + return _this.realizeDiagnostics(diagnostics); + }); + }; + LanguageServiceShimObject.prototype.getCompilerOptionsDiagnostics = function () { + var _this = this; + return this.forwardJSONCall("getCompilerOptionsDiagnostics()", function () { + var diagnostics = _this.languageService.getCompilerOptionsDiagnostics(); + return _this.realizeDiagnostics(diagnostics); + }); + }; + LanguageServiceShimObject.prototype.getQuickInfoAtPosition = function (fileName, position) { + var _this = this; + return this.forwardJSONCall("getQuickInfoAtPosition('" + fileName + "', " + position + ")", function () { + var quickInfo = _this.languageService.getQuickInfoAtPosition(fileName, position); + return quickInfo; + }); + }; + LanguageServiceShimObject.prototype.getNameOrDottedNameSpan = function (fileName, startPos, endPos) { + var _this = this; + return this.forwardJSONCall("getNameOrDottedNameSpan('" + fileName + "', " + startPos + ", " + endPos + ")", function () { + var spanInfo = _this.languageService.getNameOrDottedNameSpan(fileName, startPos, endPos); + return spanInfo; + }); + }; + LanguageServiceShimObject.prototype.getBreakpointStatementAtPosition = function (fileName, position) { + var _this = this; + return this.forwardJSONCall("getBreakpointStatementAtPosition('" + fileName + "', " + position + ")", function () { + var spanInfo = _this.languageService.getBreakpointStatementAtPosition(fileName, position); + return spanInfo; + }); + }; + LanguageServiceShimObject.prototype.getSignatureHelpItems = function (fileName, position) { + var _this = this; + return this.forwardJSONCall("getSignatureHelpItems('" + fileName + "', " + position + ")", function () { + var signatureInfo = _this.languageService.getSignatureHelpItems(fileName, position); + return signatureInfo; + }); + }; + LanguageServiceShimObject.prototype.getDefinitionAtPosition = function (fileName, position) { + var _this = this; + return this.forwardJSONCall("getDefinitionAtPosition('" + fileName + "', " + position + ")", function () { + return _this.languageService.getDefinitionAtPosition(fileName, position); + }); + }; + LanguageServiceShimObject.prototype.getRenameInfo = function (fileName, position) { + var _this = this; + return this.forwardJSONCall("getRenameInfo('" + fileName + "', " + position + ")", function () { + return _this.languageService.getRenameInfo(fileName, position); + }); + }; + LanguageServiceShimObject.prototype.findRenameLocations = function (fileName, position, findInStrings, findInComments) { + var _this = this; + return this.forwardJSONCall("findRenameLocations('" + fileName + "', " + position + ", " + findInStrings + ", " + findInComments + ")", function () { + return _this.languageService.findRenameLocations(fileName, position, findInStrings, findInComments); + }); + }; + LanguageServiceShimObject.prototype.getBraceMatchingAtPosition = function (fileName, position) { + var _this = this; + return this.forwardJSONCall("getBraceMatchingAtPosition('" + fileName + "', " + position + ")", function () { + var textRanges = _this.languageService.getBraceMatchingAtPosition(fileName, position); + return textRanges; + }); + }; + LanguageServiceShimObject.prototype.getIndentationAtPosition = function (fileName, position, options) { + var _this = this; + return this.forwardJSONCall("getIndentationAtPosition('" + fileName + "', " + position + ")", function () { + var localOptions = JSON.parse(options); + return _this.languageService.getIndentationAtPosition(fileName, position, localOptions); + }); + }; + LanguageServiceShimObject.prototype.getReferencesAtPosition = function (fileName, position) { + var _this = this; + return this.forwardJSONCall("getReferencesAtPosition('" + fileName + "', " + position + ")", function () { + return _this.languageService.getReferencesAtPosition(fileName, position); + }); + }; + LanguageServiceShimObject.prototype.findReferences = function (fileName, position) { + var _this = this; + return this.forwardJSONCall("findReferences('" + fileName + "', " + position + ")", function () { + return _this.languageService.findReferences(fileName, position); + }); + }; + LanguageServiceShimObject.prototype.getOccurrencesAtPosition = function (fileName, position) { + var _this = this; + return this.forwardJSONCall("getOccurrencesAtPosition('" + fileName + "', " + position + ")", function () { + return _this.languageService.getOccurrencesAtPosition(fileName, position); + }); + }; + LanguageServiceShimObject.prototype.getDocumentHighlights = function (fileName, position, filesToSearch) { + var _this = this; + return this.forwardJSONCall("getDocumentHighlights('" + fileName + "', " + position + ")", function () { + return _this.languageService.getDocumentHighlights(fileName, position, JSON.parse(filesToSearch)); + }); + }; + LanguageServiceShimObject.prototype.getCompletionsAtPosition = function (fileName, position) { + var _this = this; + return this.forwardJSONCall("getCompletionsAtPosition('" + fileName + "', " + position + ")", function () { + var completion = _this.languageService.getCompletionsAtPosition(fileName, position); + return completion; + }); + }; + LanguageServiceShimObject.prototype.getCompletionEntryDetails = function (fileName, position, entryName) { + var _this = this; + return this.forwardJSONCall("getCompletionEntryDetails('" + fileName + "', " + position + ", " + entryName + ")", function () { + var details = _this.languageService.getCompletionEntryDetails(fileName, position, entryName); + return details; + }); + }; + LanguageServiceShimObject.prototype.getFormattingEditsForRange = function (fileName, start, end, options) { + var _this = this; + return this.forwardJSONCall("getFormattingEditsForRange('" + fileName + "', " + start + ", " + end + ")", function () { + var localOptions = JSON.parse(options); + var edits = _this.languageService.getFormattingEditsForRange(fileName, start, end, localOptions); + return edits; + }); + }; + LanguageServiceShimObject.prototype.getFormattingEditsForDocument = function (fileName, options) { + var _this = this; + return this.forwardJSONCall("getFormattingEditsForDocument('" + fileName + "')", function () { + var localOptions = JSON.parse(options); + var edits = _this.languageService.getFormattingEditsForDocument(fileName, localOptions); + return edits; + }); + }; + LanguageServiceShimObject.prototype.getFormattingEditsAfterKeystroke = function (fileName, position, key, options) { + var _this = this; + return this.forwardJSONCall("getFormattingEditsAfterKeystroke('" + fileName + "', " + position + ", '" + key + "')", function () { + var localOptions = JSON.parse(options); + var edits = _this.languageService.getFormattingEditsAfterKeystroke(fileName, position, key, localOptions); + return edits; + }); + }; + LanguageServiceShimObject.prototype.getNavigateToItems = function (searchValue, maxResultCount) { + var _this = this; + return this.forwardJSONCall("getNavigateToItems('" + searchValue + "', " + maxResultCount + ")", function () { + var items = _this.languageService.getNavigateToItems(searchValue, maxResultCount); + return items; + }); + }; + LanguageServiceShimObject.prototype.getNavigationBarItems = function (fileName) { + var _this = this; + return this.forwardJSONCall("getNavigationBarItems('" + fileName + "')", function () { + var items = _this.languageService.getNavigationBarItems(fileName); + return items; + }); + }; + LanguageServiceShimObject.prototype.getOutliningSpans = function (fileName) { + var _this = this; + return this.forwardJSONCall("getOutliningSpans('" + fileName + "')", function () { + var items = _this.languageService.getOutliningSpans(fileName); + return items; + }); + }; + LanguageServiceShimObject.prototype.getTodoComments = function (fileName, descriptors) { + var _this = this; + return this.forwardJSONCall("getTodoComments('" + fileName + "')", function () { + var items = _this.languageService.getTodoComments(fileName, JSON.parse(descriptors)); + return items; + }); + }; + LanguageServiceShimObject.prototype.getEmitOutput = function (fileName) { + var _this = this; + return this.forwardJSONCall("getEmitOutput('" + fileName + "')", function () { + var output = _this.languageService.getEmitOutput(fileName); + output.emitOutputStatus = output.emitSkipped ? 1 : 0; + return output; + }); + }; + return LanguageServiceShimObject; + })(ShimBase); + var ClassifierShimObject = (function (_super) { + __extends(ClassifierShimObject, _super); + function ClassifierShimObject(factory) { + _super.call(this, factory); + this.classifier = ts.createClassifier(); + } + ClassifierShimObject.prototype.getClassificationsForLine = function (text, lexState, classifyKeywordsInGenerics) { + var classification = this.classifier.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics); + var items = classification.entries; + var result = ""; + for (var i = 0; i < items.length; i++) { + result += items[i].length + "\n"; + result += items[i].classification + "\n"; + } + result += classification.finalLexState; + return result; + }; + return ClassifierShimObject; + })(ShimBase); + var CoreServicesShimObject = (function (_super) { + __extends(CoreServicesShimObject, _super); + function CoreServicesShimObject(factory, logger, host) { + _super.call(this, factory); + this.logger = logger; + this.host = host; + } + CoreServicesShimObject.prototype.forwardJSONCall = function (actionDescription, action) { + return forwardJSONCall(this.logger, actionDescription, action); + }; + CoreServicesShimObject.prototype.getPreProcessedFileInfo = function (fileName, sourceTextSnapshot) { + return this.forwardJSONCall("getPreProcessedFileInfo('" + fileName + "')", function () { + var result = ts.preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength())); + var convertResult = { + referencedFiles: [], + importedFiles: [], + isLibFile: result.isLibFile + }; + ts.forEach(result.referencedFiles, function (refFile) { + convertResult.referencedFiles.push({ + path: ts.normalizePath(refFile.fileName), + position: refFile.pos, + length: refFile.end - refFile.pos + }); + }); + ts.forEach(result.importedFiles, function (importedFile) { + convertResult.importedFiles.push({ + path: ts.normalizeSlashes(importedFile.fileName), + position: importedFile.pos, + length: importedFile.end - importedFile.pos + }); + }); + return convertResult; + }); + }; + CoreServicesShimObject.prototype.getTSConfigFileInfo = function (fileName, sourceTextSnapshot) { + var _this = this; + return this.forwardJSONCall("getTSConfigFileInfo('" + fileName + "')", function () { + var text = sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()); + var result = ts.parseConfigFileText(fileName, text); + if (result.error) { + return { + options: {}, + files: [], + errors: [realizeDiagnostic(result.error, '\r\n')] + }; + } + var configFile = ts.parseConfigFile(result.config, _this.host, ts.getDirectoryPath(ts.normalizeSlashes(fileName))); + return { + options: configFile.options, + files: configFile.fileNames, + errors: realizeDiagnostics(configFile.errors, '\r\n') + }; + }); + }; + CoreServicesShimObject.prototype.getDefaultCompilationSettings = function () { + return this.forwardJSONCall("getDefaultCompilationSettings()", function () { + return ts.getDefaultCompilerOptions(); + }); + }; + return CoreServicesShimObject; + })(ShimBase); + var TypeScriptServicesFactory = (function () { + function TypeScriptServicesFactory() { + this._shims = []; + this.documentRegistry = ts.createDocumentRegistry(); + } + TypeScriptServicesFactory.prototype.getServicesVersion = function () { + return ts.servicesVersion; + }; + TypeScriptServicesFactory.prototype.createLanguageServiceShim = function (host) { + try { + var hostAdapter = new LanguageServiceShimHostAdapter(host); + var languageService = ts.createLanguageService(hostAdapter, this.documentRegistry); + return new LanguageServiceShimObject(this, host, languageService); + } + catch (err) { + logInternalError(host, err); + throw err; + } + }; + TypeScriptServicesFactory.prototype.createClassifierShim = function (logger) { + try { + return new ClassifierShimObject(this); + } + catch (err) { + logInternalError(logger, err); + throw err; + } + }; + TypeScriptServicesFactory.prototype.createCoreServicesShim = function (host) { + try { + var adapter = new CoreServicesShimHostAdapter(host); + return new CoreServicesShimObject(this, host, adapter); + } + catch (err) { + logInternalError(host, err); + throw err; + } + }; + TypeScriptServicesFactory.prototype.close = function () { + this._shims = []; + this.documentRegistry = ts.createDocumentRegistry(); + }; + TypeScriptServicesFactory.prototype.registerShim = function (shim) { + this._shims.push(shim); + }; + TypeScriptServicesFactory.prototype.unregisterShim = function (shim) { + for (var i = 0, n = this._shims.length; i < n; i++) { + if (this._shims[i] === shim) { + delete this._shims[i]; + return; + } + } + throw new Error("Invalid operation"); + }; + return TypeScriptServicesFactory; + })(); + ts.TypeScriptServicesFactory = TypeScriptServicesFactory; + if (typeof module !== "undefined" && module.exports) { + module.exports = ts; + } +})(ts || (ts = {})); +var TypeScript; +(function (TypeScript) { + var Services; + (function (Services) { + Services.TypeScriptServicesFactory = ts.TypeScriptServicesFactory; + })(Services = TypeScript.Services || (TypeScript.Services = {})); +})(TypeScript || (TypeScript = {})); +var toolsVersion = "1.4"; diff --git a/dist/typescript/services/signatureHelp.js b/dist/typescript/services/signatureHelp.js new file mode 100644 index 000000000..1a6198e07 --- /dev/null +++ b/dist/typescript/services/signatureHelp.js @@ -0,0 +1,315 @@ +/// +var ts; +(function (ts) { + var SignatureHelp; + (function (SignatureHelp) { + var emptyArray = []; + var ArgumentListKind; + (function (ArgumentListKind) { + ArgumentListKind[ArgumentListKind["TypeArguments"] = 0] = "TypeArguments"; + ArgumentListKind[ArgumentListKind["CallArguments"] = 1] = "CallArguments"; + ArgumentListKind[ArgumentListKind["TaggedTemplateArguments"] = 2] = "TaggedTemplateArguments"; + })(ArgumentListKind || (ArgumentListKind = {})); + function getSignatureHelpItems(program, sourceFile, position, cancellationToken) { + var typeChecker = program.getTypeChecker(); + var startingToken = ts.findTokenOnLeftOfPosition(sourceFile, position); + if (!startingToken) { + return undefined; + } + var argumentInfo = getContainingArgumentInfo(startingToken); + cancellationToken.throwIfCancellationRequested(); + if (!argumentInfo) { + return undefined; + } + var call = argumentInfo.invocation; + var candidates = []; + var resolvedSignature = typeChecker.getResolvedSignature(call, candidates); + cancellationToken.throwIfCancellationRequested(); + if (!candidates.length) { + if (ts.isJavaScript(sourceFile.fileName)) { + return createJavaScriptSignatureHelpItems(argumentInfo); + } + return undefined; + } + return createSignatureHelpItems(candidates, resolvedSignature, argumentInfo); + function createJavaScriptSignatureHelpItems(argumentInfo) { + if (argumentInfo.invocation.kind !== 157) { + return undefined; + } + var callExpression = argumentInfo.invocation; + var expression = callExpression.expression; + var name = expression.kind === 65 + ? expression + : expression.kind === 155 + ? expression.name + : undefined; + if (!name || !name.text) { + return undefined; + } + var typeChecker = program.getTypeChecker(); + for (var _i = 0, _a = program.getSourceFiles(); _i < _a.length; _i++) { + var sourceFile_1 = _a[_i]; + var nameToDeclarations = sourceFile_1.getNamedDeclarations(); + var declarations = ts.getProperty(nameToDeclarations, name.text); + if (declarations) { + for (var _b = 0; _b < declarations.length; _b++) { + var declaration = declarations[_b]; + var symbol = declaration.symbol; + if (symbol) { + var type = typeChecker.getTypeOfSymbolAtLocation(symbol, declaration); + if (type) { + var callSignatures = type.getCallSignatures(); + if (callSignatures && callSignatures.length) { + return createSignatureHelpItems(callSignatures, callSignatures[0], argumentInfo); + } + } + } + } + } + } + } + function getImmediatelyContainingArgumentInfo(node) { + if (node.parent.kind === 157 || node.parent.kind === 158) { + var callExpression = node.parent; + if (node.kind === 24 || + node.kind === 16) { + var list = getChildListThatStartsWithOpenerToken(callExpression, node, sourceFile); + var isTypeArgList = callExpression.typeArguments && callExpression.typeArguments.pos === list.pos; + ts.Debug.assert(list !== undefined); + return { + kind: isTypeArgList ? 0 : 1, + invocation: callExpression, + argumentsSpan: getApplicableSpanForArguments(list), + argumentIndex: 0, + argumentCount: getArgumentCount(list) + }; + } + var listItemInfo = ts.findListItemInfo(node); + if (listItemInfo) { + var list = listItemInfo.list; + var isTypeArgList = callExpression.typeArguments && callExpression.typeArguments.pos === list.pos; + var argumentIndex = getArgumentIndex(list, node); + var argumentCount = getArgumentCount(list); + ts.Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, "argumentCount < argumentIndex, " + argumentCount + " < " + argumentIndex); + return { + kind: isTypeArgList ? 0 : 1, + invocation: callExpression, + argumentsSpan: getApplicableSpanForArguments(list), + argumentIndex: argumentIndex, + argumentCount: argumentCount + }; + } + } + else if (node.kind === 10 && node.parent.kind === 159) { + if (ts.isInsideTemplateLiteral(node, position)) { + return getArgumentListInfoForTemplate(node.parent, 0); + } + } + else if (node.kind === 11 && node.parent.parent.kind === 159) { + var templateExpression = node.parent; + var tagExpression = templateExpression.parent; + ts.Debug.assert(templateExpression.kind === 171); + var argumentIndex = ts.isInsideTemplateLiteral(node, position) ? 0 : 1; + return getArgumentListInfoForTemplate(tagExpression, argumentIndex); + } + else if (node.parent.kind === 176 && node.parent.parent.parent.kind === 159) { + var templateSpan = node.parent; + var templateExpression = templateSpan.parent; + var tagExpression = templateExpression.parent; + ts.Debug.assert(templateExpression.kind === 171); + if (node.kind === 13 && !ts.isInsideTemplateLiteral(node, position)) { + return undefined; + } + var spanIndex = templateExpression.templateSpans.indexOf(templateSpan); + var argumentIndex = getArgumentIndexForTemplatePiece(spanIndex, node); + return getArgumentListInfoForTemplate(tagExpression, argumentIndex); + } + return undefined; + } + function getArgumentIndex(argumentsList, node) { + var argumentIndex = 0; + var listChildren = argumentsList.getChildren(); + for (var _i = 0; _i < listChildren.length; _i++) { + var child = listChildren[_i]; + if (child === node) { + break; + } + if (child.kind !== 23) { + argumentIndex++; + } + } + return argumentIndex; + } + function getArgumentCount(argumentsList) { + var listChildren = argumentsList.getChildren(); + var argumentCount = ts.countWhere(listChildren, function (arg) { return arg.kind !== 23; }); + if (listChildren.length > 0 && ts.lastOrUndefined(listChildren).kind === 23) { + argumentCount++; + } + return argumentCount; + } + function getArgumentIndexForTemplatePiece(spanIndex, node) { + ts.Debug.assert(position >= node.getStart(), "Assumed 'position' could not occur before node."); + if (ts.isTemplateLiteralKind(node.kind)) { + if (ts.isInsideTemplateLiteral(node, position)) { + return 0; + } + return spanIndex + 2; + } + return spanIndex + 1; + } + function getArgumentListInfoForTemplate(tagExpression, argumentIndex) { + var argumentCount = tagExpression.template.kind === 10 + ? 1 + : tagExpression.template.templateSpans.length + 1; + ts.Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, "argumentCount < argumentIndex, " + argumentCount + " < " + argumentIndex); + return { + kind: 2, + invocation: tagExpression, + argumentsSpan: getApplicableSpanForTaggedTemplate(tagExpression), + argumentIndex: argumentIndex, + argumentCount: argumentCount + }; + } + function getApplicableSpanForArguments(argumentsList) { + var applicableSpanStart = argumentsList.getFullStart(); + var applicableSpanEnd = ts.skipTrivia(sourceFile.text, argumentsList.getEnd(), false); + return ts.createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); + } + function getApplicableSpanForTaggedTemplate(taggedTemplate) { + var template = taggedTemplate.template; + var applicableSpanStart = template.getStart(); + var applicableSpanEnd = template.getEnd(); + if (template.kind === 171) { + var lastSpan = ts.lastOrUndefined(template.templateSpans); + if (lastSpan.literal.getFullWidth() === 0) { + applicableSpanEnd = ts.skipTrivia(sourceFile.text, applicableSpanEnd, false); + } + } + return ts.createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); + } + function getContainingArgumentInfo(node) { + for (var n = node; n.kind !== 227; n = n.parent) { + if (ts.isFunctionBlock(n)) { + return undefined; + } + if (n.pos < n.parent.pos || n.end > n.parent.end) { + ts.Debug.fail("Node of kind " + n.kind + " is not a subspan of its parent of kind " + n.parent.kind); + } + var argumentInfo_1 = getImmediatelyContainingArgumentInfo(n); + if (argumentInfo_1) { + return argumentInfo_1; + } + } + return undefined; + } + function getChildListThatStartsWithOpenerToken(parent, openerToken, sourceFile) { + var children = parent.getChildren(sourceFile); + var indexOfOpenerToken = children.indexOf(openerToken); + ts.Debug.assert(indexOfOpenerToken >= 0 && children.length > indexOfOpenerToken + 1); + return children[indexOfOpenerToken + 1]; + } + function selectBestInvalidOverloadIndex(candidates, argumentCount) { + var maxParamsSignatureIndex = -1; + var maxParams = -1; + for (var i = 0; i < candidates.length; i++) { + var candidate = candidates[i]; + if (candidate.hasRestParameter || candidate.parameters.length >= argumentCount) { + return i; + } + if (candidate.parameters.length > maxParams) { + maxParams = candidate.parameters.length; + maxParamsSignatureIndex = i; + } + } + return maxParamsSignatureIndex; + } + function createSignatureHelpItems(candidates, bestSignature, argumentListInfo) { + var applicableSpan = argumentListInfo.argumentsSpan; + var isTypeParameterList = argumentListInfo.kind === 0; + var invocation = argumentListInfo.invocation; + var callTarget = ts.getInvokedExpression(invocation); + var callTargetSymbol = typeChecker.getSymbolAtLocation(callTarget); + var callTargetDisplayParts = callTargetSymbol && ts.symbolToDisplayParts(typeChecker, callTargetSymbol, undefined, undefined); + var items = ts.map(candidates, function (candidateSignature) { + var signatureHelpParameters; + var prefixDisplayParts = []; + var suffixDisplayParts = []; + if (callTargetDisplayParts) { + prefixDisplayParts.push.apply(prefixDisplayParts, callTargetDisplayParts); + } + if (isTypeParameterList) { + prefixDisplayParts.push(ts.punctuationPart(24)); + var typeParameters = candidateSignature.typeParameters; + signatureHelpParameters = typeParameters && typeParameters.length > 0 ? ts.map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray; + suffixDisplayParts.push(ts.punctuationPart(25)); + var parameterParts = ts.mapToDisplayParts(function (writer) { + return typeChecker.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.parameters, writer, invocation); + }); + suffixDisplayParts.push.apply(suffixDisplayParts, parameterParts); + } + else { + var typeParameterParts = ts.mapToDisplayParts(function (writer) { + return typeChecker.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, invocation); + }); + prefixDisplayParts.push.apply(prefixDisplayParts, typeParameterParts); + prefixDisplayParts.push(ts.punctuationPart(16)); + var parameters = candidateSignature.parameters; + signatureHelpParameters = parameters.length > 0 ? ts.map(parameters, createSignatureHelpParameterForParameter) : emptyArray; + suffixDisplayParts.push(ts.punctuationPart(17)); + } + var returnTypeParts = ts.mapToDisplayParts(function (writer) { + return typeChecker.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, invocation); + }); + suffixDisplayParts.push.apply(suffixDisplayParts, returnTypeParts); + return { + isVariadic: candidateSignature.hasRestParameter, + prefixDisplayParts: prefixDisplayParts, + suffixDisplayParts: suffixDisplayParts, + separatorDisplayParts: [ts.punctuationPart(23), ts.spacePart()], + parameters: signatureHelpParameters, + documentation: candidateSignature.getDocumentationComment() + }; + }); + var argumentIndex = argumentListInfo.argumentIndex; + var argumentCount = argumentListInfo.argumentCount; + var selectedItemIndex = candidates.indexOf(bestSignature); + if (selectedItemIndex < 0) { + selectedItemIndex = selectBestInvalidOverloadIndex(candidates, argumentCount); + } + ts.Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, "argumentCount < argumentIndex, " + argumentCount + " < " + argumentIndex); + return { + items: items, + applicableSpan: applicableSpan, + selectedItemIndex: selectedItemIndex, + argumentIndex: argumentIndex, + argumentCount: argumentCount + }; + function createSignatureHelpParameterForParameter(parameter) { + var displayParts = ts.mapToDisplayParts(function (writer) { + return typeChecker.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, invocation); + }); + var isOptional = ts.hasQuestionToken(parameter.valueDeclaration); + return { + name: parameter.name, + documentation: parameter.getDocumentationComment(), + displayParts: displayParts, + isOptional: isOptional + }; + } + function createSignatureHelpParameterForTypeParameter(typeParameter) { + var displayParts = ts.mapToDisplayParts(function (writer) { + return typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(typeParameter, writer, invocation); + }); + return { + name: typeParameter.symbol.name, + documentation: emptyArray, + displayParts: displayParts, + isOptional: false + }; + } + } + } + SignatureHelp.getSignatureHelpItems = getSignatureHelpItems; + })(SignatureHelp = ts.SignatureHelp || (ts.SignatureHelp = {})); +})(ts || (ts = {})); diff --git a/dist/typescript/services/utilities.js b/dist/typescript/services/utilities.js new file mode 100644 index 000000000..6e92200f2 --- /dev/null +++ b/dist/typescript/services/utilities.js @@ -0,0 +1,569 @@ +var ts; +(function (ts) { + function getEndLinePosition(line, sourceFile) { + ts.Debug.assert(line >= 0); + var lineStarts = sourceFile.getLineStarts(); + var lineIndex = line; + if (lineIndex + 1 === lineStarts.length) { + return sourceFile.text.length - 1; + } + else { + var start = lineStarts[lineIndex]; + var pos = lineStarts[lineIndex + 1] - 1; + ts.Debug.assert(ts.isLineBreak(sourceFile.text.charCodeAt(pos))); + while (start <= pos && ts.isLineBreak(sourceFile.text.charCodeAt(pos))) { + pos--; + } + return pos; + } + } + ts.getEndLinePosition = getEndLinePosition; + function getLineStartPositionForPosition(position, sourceFile) { + var lineStarts = sourceFile.getLineStarts(); + var line = sourceFile.getLineAndCharacterOfPosition(position).line; + return lineStarts[line]; + } + ts.getLineStartPositionForPosition = getLineStartPositionForPosition; + function rangeContainsRange(r1, r2) { + return startEndContainsRange(r1.pos, r1.end, r2); + } + ts.rangeContainsRange = rangeContainsRange; + function startEndContainsRange(start, end, range) { + return start <= range.pos && end >= range.end; + } + ts.startEndContainsRange = startEndContainsRange; + function rangeContainsStartEnd(range, start, end) { + return range.pos <= start && range.end >= end; + } + ts.rangeContainsStartEnd = rangeContainsStartEnd; + function rangeOverlapsWithStartEnd(r1, start, end) { + return startEndOverlapsWithStartEnd(r1.pos, r1.end, start, end); + } + ts.rangeOverlapsWithStartEnd = rangeOverlapsWithStartEnd; + function startEndOverlapsWithStartEnd(start1, end1, start2, end2) { + var start = Math.max(start1, start2); + var end = Math.min(end1, end2); + return start < end; + } + ts.startEndOverlapsWithStartEnd = startEndOverlapsWithStartEnd; + function positionBelongsToNode(candidate, position, sourceFile) { + return candidate.end > position || !isCompletedNode(candidate, sourceFile); + } + ts.positionBelongsToNode = positionBelongsToNode; + function isCompletedNode(n, sourceFile) { + if (ts.nodeIsMissing(n)) { + return false; + } + switch (n.kind) { + case 201: + case 202: + case 204: + case 154: + case 150: + case 145: + case 179: + case 206: + case 207: + return nodeEndsWith(n, 15, sourceFile); + case 223: + return isCompletedNode(n.block, sourceFile); + case 158: + if (!n.arguments) { + return true; + } + case 157: + case 161: + case 149: + return nodeEndsWith(n, 17, sourceFile); + case 142: + case 143: + return isCompletedNode(n.type, sourceFile); + case 135: + case 136: + case 137: + case 200: + case 162: + case 134: + case 133: + case 139: + case 138: + case 163: + if (n.body) { + return isCompletedNode(n.body, sourceFile); + } + if (n.type) { + return isCompletedNode(n.type, sourceFile); + } + return hasChildOfKind(n, 17, sourceFile); + case 205: + return n.body && isCompletedNode(n.body, sourceFile); + case 183: + if (n.elseStatement) { + return isCompletedNode(n.elseStatement, sourceFile); + } + return isCompletedNode(n.thenStatement, sourceFile); + case 182: + return isCompletedNode(n.expression, sourceFile); + case 153: + case 151: + case 156: + case 127: + case 147: + return nodeEndsWith(n, 19, sourceFile); + case 140: + if (n.type) { + return isCompletedNode(n.type, sourceFile); + } + return hasChildOfKind(n, 19, sourceFile); + case 220: + case 221: + return false; + case 186: + case 187: + case 188: + case 185: + return isCompletedNode(n.statement, sourceFile); + case 184: + var hasWhileKeyword = findChildOfKind(n, 100, sourceFile); + if (hasWhileKeyword) { + return nodeEndsWith(n, 17, sourceFile); + } + return isCompletedNode(n.statement, sourceFile); + case 144: + return isCompletedNode(n.exprName, sourceFile); + case 165: + case 164: + case 166: + case 172: + case 173: + var unaryWordExpression = n; + return isCompletedNode(unaryWordExpression.expression, sourceFile); + case 159: + return isCompletedNode(n.template, sourceFile); + case 171: + var lastSpan = ts.lastOrUndefined(n.templateSpans); + return isCompletedNode(lastSpan, sourceFile); + case 176: + return ts.nodeIsPresent(n.literal); + case 167: + return isCompletedNode(n.operand, sourceFile); + case 169: + return isCompletedNode(n.right, sourceFile); + case 170: + return isCompletedNode(n.whenFalse, sourceFile); + default: + return true; + } + } + ts.isCompletedNode = isCompletedNode; + function nodeEndsWith(n, expectedLastToken, sourceFile) { + var children = n.getChildren(sourceFile); + if (children.length) { + var last = children[children.length - 1]; + if (last.kind === expectedLastToken) { + return true; + } + else if (last.kind === 22 && children.length !== 1) { + return children[children.length - 2].kind === expectedLastToken; + } + } + return false; + } + function findListItemInfo(node) { + var list = findContainingList(node); + if (!list) { + return undefined; + } + var children = list.getChildren(); + var listItemIndex = ts.indexOf(children, node); + return { + listItemIndex: listItemIndex, + list: list + }; + } + ts.findListItemInfo = findListItemInfo; + function hasChildOfKind(n, kind, sourceFile) { + return !!findChildOfKind(n, kind, sourceFile); + } + ts.hasChildOfKind = hasChildOfKind; + function findChildOfKind(n, kind, sourceFile) { + return ts.forEach(n.getChildren(sourceFile), function (c) { return c.kind === kind && c; }); + } + ts.findChildOfKind = findChildOfKind; + function findContainingList(node) { + var syntaxList = ts.forEach(node.parent.getChildren(), function (c) { + if (c.kind === 228 && c.pos <= node.pos && c.end >= node.end) { + return c; + } + }); + ts.Debug.assert(!syntaxList || ts.contains(syntaxList.getChildren(), node)); + return syntaxList; + } + ts.findContainingList = findContainingList; + function getTouchingWord(sourceFile, position) { + return getTouchingToken(sourceFile, position, function (n) { return isWord(n.kind); }); + } + ts.getTouchingWord = getTouchingWord; + function getTouchingPropertyName(sourceFile, position) { + return getTouchingToken(sourceFile, position, function (n) { return isPropertyName(n.kind); }); + } + ts.getTouchingPropertyName = getTouchingPropertyName; + function getTouchingToken(sourceFile, position, includeItemAtEndPosition) { + return getTokenAtPositionWorker(sourceFile, position, false, includeItemAtEndPosition); + } + ts.getTouchingToken = getTouchingToken; + function getTokenAtPosition(sourceFile, position) { + return getTokenAtPositionWorker(sourceFile, position, true, undefined); + } + ts.getTokenAtPosition = getTokenAtPosition; + function getTokenAtPositionWorker(sourceFile, position, allowPositionInLeadingTrivia, includeItemAtEndPosition) { + var current = sourceFile; + outer: while (true) { + if (isToken(current)) { + return current; + } + for (var i = 0, n = current.getChildCount(sourceFile); i < n; i++) { + var child = current.getChildAt(i); + var start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile); + if (start <= position) { + var end = child.getEnd(); + if (position < end || (position === end && child.kind === 1)) { + current = child; + continue outer; + } + else if (includeItemAtEndPosition && end === position) { + var previousToken = findPrecedingToken(position, sourceFile, child); + if (previousToken && includeItemAtEndPosition(previousToken)) { + return previousToken; + } + } + } + } + return current; + } + } + function findTokenOnLeftOfPosition(file, position) { + var tokenAtPosition = getTokenAtPosition(file, position); + if (isToken(tokenAtPosition) && position > tokenAtPosition.getStart(file) && position < tokenAtPosition.getEnd()) { + return tokenAtPosition; + } + return findPrecedingToken(position, file); + } + ts.findTokenOnLeftOfPosition = findTokenOnLeftOfPosition; + function findNextToken(previousToken, parent) { + return find(parent); + function find(n) { + if (isToken(n) && n.pos === previousToken.end) { + return n; + } + var children = n.getChildren(); + for (var _i = 0; _i < children.length; _i++) { + var child = children[_i]; + var shouldDiveInChildNode = (child.pos <= previousToken.pos && child.end > previousToken.end) || + (child.pos === previousToken.end); + if (shouldDiveInChildNode && nodeHasTokens(child)) { + return find(child); + } + } + return undefined; + } + } + ts.findNextToken = findNextToken; + function findPrecedingToken(position, sourceFile, startNode) { + return find(startNode || sourceFile); + function findRightmostToken(n) { + if (isToken(n)) { + return n; + } + var children = n.getChildren(); + var candidate = findRightmostChildNodeWithTokens(children, children.length); + return candidate && findRightmostToken(candidate); + } + function find(n) { + if (isToken(n)) { + return n; + } + var children = n.getChildren(); + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + if (nodeHasTokens(child)) { + if (position <= child.end) { + if (child.getStart(sourceFile) >= position) { + var candidate = findRightmostChildNodeWithTokens(children, i); + return candidate && findRightmostToken(candidate); + } + else { + return find(child); + } + } + } + } + ts.Debug.assert(startNode !== undefined || n.kind === 227); + if (children.length) { + var candidate = findRightmostChildNodeWithTokens(children, children.length); + return candidate && findRightmostToken(candidate); + } + } + function findRightmostChildNodeWithTokens(children, exclusiveStartPosition) { + for (var i = exclusiveStartPosition - 1; i >= 0; --i) { + if (nodeHasTokens(children[i])) { + return children[i]; + } + } + } + } + ts.findPrecedingToken = findPrecedingToken; + function nodeHasTokens(n) { + return n.getWidth() !== 0; + } + function getNodeModifiers(node) { + var flags = ts.getCombinedNodeFlags(node); + var result = []; + if (flags & 32) + result.push(ts.ScriptElementKindModifier.privateMemberModifier); + if (flags & 64) + result.push(ts.ScriptElementKindModifier.protectedMemberModifier); + if (flags & 16) + result.push(ts.ScriptElementKindModifier.publicMemberModifier); + if (flags & 128) + result.push(ts.ScriptElementKindModifier.staticModifier); + if (flags & 1) + result.push(ts.ScriptElementKindModifier.exportedModifier); + if (ts.isInAmbientContext(node)) + result.push(ts.ScriptElementKindModifier.ambientModifier); + return result.length > 0 ? result.join(',') : ts.ScriptElementKindModifier.none; + } + ts.getNodeModifiers = getNodeModifiers; + function getTypeArgumentOrTypeParameterList(node) { + if (node.kind === 141 || node.kind === 157) { + return node.typeArguments; + } + if (ts.isFunctionLike(node) || node.kind === 201 || node.kind === 202) { + return node.typeParameters; + } + return undefined; + } + ts.getTypeArgumentOrTypeParameterList = getTypeArgumentOrTypeParameterList; + function isToken(n) { + return n.kind >= 0 && n.kind <= 125; + } + ts.isToken = isToken; + function isWord(kind) { + return kind === 65 || ts.isKeyword(kind); + } + ts.isWord = isWord; + function isPropertyName(kind) { + return kind === 8 || kind === 7 || isWord(kind); + } + function isComment(kind) { + return kind === 2 || kind === 3; + } + ts.isComment = isComment; + function isPunctuation(kind) { + return 14 <= kind && kind <= 64; + } + ts.isPunctuation = isPunctuation; + function isInsideTemplateLiteral(node, position) { + return ts.isTemplateLiteralKind(node.kind) + && (node.getStart() < position && position < node.getEnd()) || (!!node.isUnterminated && position === node.getEnd()); + } + ts.isInsideTemplateLiteral = isInsideTemplateLiteral; + function isAccessibilityModifier(kind) { + switch (kind) { + case 108: + case 106: + case 107: + return true; + } + return false; + } + ts.isAccessibilityModifier = isAccessibilityModifier; + function compareDataObjects(dst, src) { + for (var e in dst) { + if (typeof dst[e] === "object") { + if (!compareDataObjects(dst[e], src[e])) { + return false; + } + } + else if (typeof dst[e] !== "function") { + if (dst[e] !== src[e]) { + return false; + } + } + } + return true; + } + ts.compareDataObjects = compareDataObjects; +})(ts || (ts = {})); +var ts; +(function (ts) { + function isFirstDeclarationOfSymbolParameter(symbol) { + return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === 129; + } + ts.isFirstDeclarationOfSymbolParameter = isFirstDeclarationOfSymbolParameter; + var displayPartWriter = getDisplayPartWriter(); + function getDisplayPartWriter() { + var displayParts; + var lineStart; + var indent; + resetWriter(); + return { + displayParts: function () { return displayParts; }, + writeKeyword: function (text) { return writeKind(text, ts.SymbolDisplayPartKind.keyword); }, + writeOperator: function (text) { return writeKind(text, ts.SymbolDisplayPartKind.operator); }, + writePunctuation: function (text) { return writeKind(text, ts.SymbolDisplayPartKind.punctuation); }, + writeSpace: function (text) { return writeKind(text, ts.SymbolDisplayPartKind.space); }, + writeStringLiteral: function (text) { return writeKind(text, ts.SymbolDisplayPartKind.stringLiteral); }, + writeParameter: function (text) { return writeKind(text, ts.SymbolDisplayPartKind.parameterName); }, + writeSymbol: writeSymbol, + writeLine: writeLine, + increaseIndent: function () { indent++; }, + decreaseIndent: function () { indent--; }, + clear: resetWriter, + trackSymbol: function () { } + }; + function writeIndent() { + if (lineStart) { + var indentString = ts.getIndentString(indent); + if (indentString) { + displayParts.push(displayPart(indentString, ts.SymbolDisplayPartKind.space)); + } + lineStart = false; + } + } + function writeKind(text, kind) { + writeIndent(); + displayParts.push(displayPart(text, kind)); + } + function writeSymbol(text, symbol) { + writeIndent(); + displayParts.push(symbolPart(text, symbol)); + } + function writeLine() { + displayParts.push(lineBreakPart()); + lineStart = true; + } + function resetWriter() { + displayParts = []; + lineStart = true; + indent = 0; + } + } + function symbolPart(text, symbol) { + return displayPart(text, displayPartKind(symbol), symbol); + function displayPartKind(symbol) { + var flags = symbol.flags; + if (flags & 3) { + return isFirstDeclarationOfSymbolParameter(symbol) ? ts.SymbolDisplayPartKind.parameterName : ts.SymbolDisplayPartKind.localName; + } + else if (flags & 4) { + return ts.SymbolDisplayPartKind.propertyName; + } + else if (flags & 32768) { + return ts.SymbolDisplayPartKind.propertyName; + } + else if (flags & 65536) { + return ts.SymbolDisplayPartKind.propertyName; + } + else if (flags & 8) { + return ts.SymbolDisplayPartKind.enumMemberName; + } + else if (flags & 16) { + return ts.SymbolDisplayPartKind.functionName; + } + else if (flags & 32) { + return ts.SymbolDisplayPartKind.className; + } + else if (flags & 64) { + return ts.SymbolDisplayPartKind.interfaceName; + } + else if (flags & 384) { + return ts.SymbolDisplayPartKind.enumName; + } + else if (flags & 1536) { + return ts.SymbolDisplayPartKind.moduleName; + } + else if (flags & 8192) { + return ts.SymbolDisplayPartKind.methodName; + } + else if (flags & 262144) { + return ts.SymbolDisplayPartKind.typeParameterName; + } + else if (flags & 524288) { + return ts.SymbolDisplayPartKind.aliasName; + } + else if (flags & 8388608) { + return ts.SymbolDisplayPartKind.aliasName; + } + return ts.SymbolDisplayPartKind.text; + } + } + ts.symbolPart = symbolPart; + function displayPart(text, kind, symbol) { + return { + text: text, + kind: ts.SymbolDisplayPartKind[kind] + }; + } + ts.displayPart = displayPart; + function spacePart() { + return displayPart(" ", ts.SymbolDisplayPartKind.space); + } + ts.spacePart = spacePart; + function keywordPart(kind) { + return displayPart(ts.tokenToString(kind), ts.SymbolDisplayPartKind.keyword); + } + ts.keywordPart = keywordPart; + function punctuationPart(kind) { + return displayPart(ts.tokenToString(kind), ts.SymbolDisplayPartKind.punctuation); + } + ts.punctuationPart = punctuationPart; + function operatorPart(kind) { + return displayPart(ts.tokenToString(kind), ts.SymbolDisplayPartKind.operator); + } + ts.operatorPart = operatorPart; + function textOrKeywordPart(text) { + var kind = ts.stringToToken(text); + return kind === undefined + ? textPart(text) + : keywordPart(kind); + } + ts.textOrKeywordPart = textOrKeywordPart; + function textPart(text) { + return displayPart(text, ts.SymbolDisplayPartKind.text); + } + ts.textPart = textPart; + function lineBreakPart() { + return displayPart("\n", ts.SymbolDisplayPartKind.lineBreak); + } + ts.lineBreakPart = lineBreakPart; + function mapToDisplayParts(writeDisplayParts) { + writeDisplayParts(displayPartWriter); + var result = displayPartWriter.displayParts(); + displayPartWriter.clear(); + return result; + } + ts.mapToDisplayParts = mapToDisplayParts; + function typeToDisplayParts(typechecker, type, enclosingDeclaration, flags) { + return mapToDisplayParts(function (writer) { + typechecker.getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); + }); + } + ts.typeToDisplayParts = typeToDisplayParts; + function symbolToDisplayParts(typeChecker, symbol, enclosingDeclaration, meaning, flags) { + return mapToDisplayParts(function (writer) { + typeChecker.getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning, flags); + }); + } + ts.symbolToDisplayParts = symbolToDisplayParts; + function signatureToDisplayParts(typechecker, signature, enclosingDeclaration, flags) { + return mapToDisplayParts(function (writer) { + typechecker.getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags); + }); + } + ts.signatureToDisplayParts = signatureToDisplayParts; + function isJavaScript(fileName) { + return ts.fileExtensionIs(fileName, ".js"); + } + ts.isJavaScript = isJavaScript; +})(ts || (ts = {})); diff --git a/dist/worker/child.js b/dist/worker/child.js index 3000d647c..34b9a1fba 100644 --- a/dist/worker/child.js +++ b/dist/worker/child.js @@ -1,5 +1,7 @@ ///ts:ref=globals /// ///ts:ref:generated +var makeTypeScriptGlobal_1 = require("../typescript/makeTypeScriptGlobal"); +makeTypeScriptGlobal_1.makeTsGlobal(); var workerLib = require('./lib/workerLib'); var child = new workerLib.Child(); var projectService = require('../main/lang/projectService'); diff --git a/lib/globals.ts b/lib/globals.ts index 2e8f107b9..2e2a37c9a 100644 --- a/lib/globals.ts +++ b/lib/globals.ts @@ -1,6 +1,4 @@ /// -/// -/// // From brackets plugin /// diff --git a/lib/linter.ts b/lib/linter.ts index 2816ad021..92b0e42e8 100644 --- a/lib/linter.ts +++ b/lib/linter.ts @@ -4,6 +4,9 @@ ///ts:ref=globals /// ///ts:ref:generated +import {makeTsGlobal} from "./typescript/makeTypeScriptGlobal"; +makeTsGlobal(); + ///ts:import=utils import utils = require('./main/lang/utils'); ///ts:import:generated ///ts:import=parent diff --git a/lib/main/atom/autoCompleteProvider.ts b/lib/main/atom/autoCompleteProvider.ts index 0bf3c79d0..7d613be6f 100644 --- a/lib/main/atom/autoCompleteProvider.ts +++ b/lib/main/atom/autoCompleteProvider.ts @@ -6,7 +6,6 @@ import parent = require('../../worker/parent'); ///ts:import:generated ///ts:import=atomConfig import atomConfig = require('./atomConfig'); ///ts:import:generated -import ts = require('typescript'); import fs = require('fs'); ///ts:import=atomUtils import atomUtils = require('./atomUtils'); ///ts:import:generated diff --git a/lib/main/atom/commands/commands.ts b/lib/main/atom/commands/commands.ts index c47b9d845..2ab2ce19e 100644 --- a/lib/main/atom/commands/commands.ts +++ b/lib/main/atom/commands/commands.ts @@ -3,7 +3,6 @@ import buildView = require("../buildView"); import atomUtils = require("../atomUtils"); import autoCompleteProvider = require("../autoCompleteProvider"); import path = require('path'); -import ts = require('typescript'); import documentationView = require("../views/documentationView"); import renameView = require("../views/renameView"); var apd = require('atom-package-dependencies'); diff --git a/lib/main/atom/debugAtomTs.ts b/lib/main/atom/debugAtomTs.ts index 190b69d77..c4e3ac439 100644 --- a/lib/main/atom/debugAtomTs.ts +++ b/lib/main/atom/debugAtomTs.ts @@ -6,7 +6,6 @@ import atomConfig = require('./atomConfig'); ///ts:import:generated ///ts:import=typescriptGrammar import typescriptGrammar = require('./typescriptGrammar'); ///ts:import:generated -import ts = require('typescript'); import TokenClass = ts.TokenClass; interface AtomTokenizeLineResult { diff --git a/lib/main/atom/tooltipManager.ts b/lib/main/atom/tooltipManager.ts index b9db5b675..7f55a4a20 100644 --- a/lib/main/atom/tooltipManager.ts +++ b/lib/main/atom/tooltipManager.ts @@ -11,7 +11,6 @@ import parent = require('../../worker/parent'); ///ts:import:generated import path = require('path'); import fs = require('fs'); -import ts = require('typescript'); import emissary = require('emissary'); var Subscriber = emissary.Subscriber; import tooltipView = require('./views/tooltipView'); diff --git a/lib/main/atom/typescriptGrammar.ts b/lib/main/atom/typescriptGrammar.ts index 8e0468beb..4cba96294 100644 --- a/lib/main/atom/typescriptGrammar.ts +++ b/lib/main/atom/typescriptGrammar.ts @@ -6,7 +6,6 @@ // https://github.com/fdecampredon/brackets-typescript/blob/master/src/main/mode.ts // https://github.com/p-e-w/language-javascript-semantic/blob/master/lib/javascript-semantic-grammar.coffee -import ts = require('typescript'); import TokenClass = ts.TokenClass; declare class AtomTSBaseGrammar { diff --git a/lib/main/atom/views/astView.ts b/lib/main/atom/views/astView.ts index c5ea012c3..461c7e5ec 100644 --- a/lib/main/atom/views/astView.ts +++ b/lib/main/atom/views/astView.ts @@ -1,6 +1,5 @@ import sp = require('atom-space-pen-views'); import mainPanelView = require('./mainPanelView'); -import ts = require('typescript'); import atomUtils = require("../atomUtils"); import * as parent from "../../../worker/parent"; import * as d3 from "d3"; diff --git a/lib/main/atom/views/dependencyView.ts b/lib/main/atom/views/dependencyView.ts index 7be92d101..b41787899 100644 --- a/lib/main/atom/views/dependencyView.ts +++ b/lib/main/atom/views/dependencyView.ts @@ -1,6 +1,5 @@ import sp = require('atom-space-pen-views'); import mainPanelView = require('./mainPanelView'); -import ts = require('typescript'); import atomUtils = require("../atomUtils"); import * as parent from "../../../worker/parent"; import * as d3 from "d3"; diff --git a/lib/main/atom/views/fileSymbolsView.ts b/lib/main/atom/views/fileSymbolsView.ts index f9259d814..7e8d73815 100644 --- a/lib/main/atom/views/fileSymbolsView.ts +++ b/lib/main/atom/views/fileSymbolsView.ts @@ -1,6 +1,5 @@ import sp = require('atom-space-pen-views'); import mainPanelView = require('./mainPanelView'); -import ts = require('typescript'); import atomUtils = require("../atomUtils"); diff --git a/lib/main/atom/views/projectSymbolsView.ts b/lib/main/atom/views/projectSymbolsView.ts index 090079d63..ce43e199f 100644 --- a/lib/main/atom/views/projectSymbolsView.ts +++ b/lib/main/atom/views/projectSymbolsView.ts @@ -1,6 +1,5 @@ import sp = require('atom-space-pen-views'); import mainPanelView = require('./mainPanelView'); -import ts = require('typescript'); import atomUtils = require("../atomUtils"); diff --git a/lib/main/atomts.ts b/lib/main/atomts.ts index 462ac66fd..c31657ac1 100644 --- a/lib/main/atomts.ts +++ b/lib/main/atomts.ts @@ -1,6 +1,9 @@ ///ts:ref=globals /// ///ts:ref:generated +import {makeTsGlobal} from "../typescript/makeTypeScriptGlobal"; +makeTsGlobal(); + import path = require('path'); import fs = require('fs'); import os = require('os'); @@ -28,7 +31,6 @@ import typescriptGrammar = require('./atom/typescriptGrammar'); ///ts:import:gen import _atom = require('atom'); import {$} from "atom-space-pen-views"; - import documentationView = require('./atom/views/documentationView'); import renameView = require('./atom/views/renameView'); import mainPanelView = require("./atom/views/mainPanelView"); @@ -60,6 +62,7 @@ var hideIfNotActiveOnStart = debounce(() => { /** only called once we have our dependencies */ function readyToActivate() { + // Add the documentation view documentationView.attach(); diff --git a/lib/main/lang/core/languageServiceHost2.ts b/lib/main/lang/core/languageServiceHost2.ts index eaebd8b4a..b4a1be00e 100644 --- a/lib/main/lang/core/languageServiceHost2.ts +++ b/lib/main/lang/core/languageServiceHost2.ts @@ -1,4 +1,3 @@ -import ts = require('typescript'); import path = require('path'); import utils = require('../utils'); import fs = require('fs'); diff --git a/lib/main/lang/core/project.ts b/lib/main/lang/core/project.ts index 9eedb81d9..6d378d04f 100644 --- a/lib/main/lang/core/project.ts +++ b/lib/main/lang/core/project.ts @@ -1,7 +1,6 @@ ///ts:ref=globals /// ///ts:ref:generated -import ts = require('typescript'); import path = require('path'); import fs = require('fs'); import os = require('os'); diff --git a/lib/main/lang/fixmyts/addClassMember.ts b/lib/main/lang/fixmyts/addClassMember.ts index 425165472..0396fc4ea 100644 --- a/lib/main/lang/fixmyts/addClassMember.ts +++ b/lib/main/lang/fixmyts/addClassMember.ts @@ -1,8 +1,6 @@ import {QuickFix, QuickFixQueryInformation, Refactoring} from "./quickFix"; -import * as ts from "typescript"; import * as ast from "./astUtils"; import {EOL} from "os"; -import {displayPartsToString, typeToDisplayParts} from "typescript"; function getIdentifierAndClassNames(error: ts.Diagnostic) { var errorText: string = error.messageText; @@ -58,7 +56,7 @@ class AddClassMember implements QuickFix { var type = info.typeChecker.getTypeAtLocation(binaryExpression.right); /** Discoverd from review of `services.getQuickInfoAtPosition` */ - typeString = displayPartsToString(typeToDisplayParts(info.typeChecker, type)).replace(/\s+/g, ' '); + typeString = ts.displayPartsToString(ts.typeToDisplayParts(info.typeChecker, type)).replace(/\s+/g, ' '); } // Find the containing class declaration diff --git a/lib/main/lang/fixmyts/astUtils.ts b/lib/main/lang/fixmyts/astUtils.ts index 47dd8a9e4..f80e31a1d 100644 --- a/lib/main/lang/fixmyts/astUtils.ts +++ b/lib/main/lang/fixmyts/astUtils.ts @@ -1,4 +1,3 @@ -import * as ts from "typescript"; export var forEachChild = ts.forEachChild; diff --git a/lib/main/lang/fixmyts/equalsToEquals.ts b/lib/main/lang/fixmyts/equalsToEquals.ts index 728df1637..1cd7e48a8 100644 --- a/lib/main/lang/fixmyts/equalsToEquals.ts +++ b/lib/main/lang/fixmyts/equalsToEquals.ts @@ -1,28 +1,25 @@ import {QuickFix, QuickFixQueryInformation, Refactoring} from "./quickFix"; -import * as ts from "typescript"; import * as ast from "./astUtils"; import {EOL} from "os"; -import {displayPartsToString, typeToDisplayParts, SyntaxKind} from "typescript"; - class EqualsToEquals implements QuickFix { key = EqualsToEquals.name; canProvideFix(info: QuickFixQueryInformation): string { - if (info.positionNode.kind === SyntaxKind.EqualsEqualsToken) { + if (info.positionNode.kind === ts.SyntaxKind.EqualsEqualsToken) { return "Convert == to ==="; } - if (info.positionNode.kind === SyntaxKind.ExclamationEqualsToken) { + if (info.positionNode.kind === ts.SyntaxKind.ExclamationEqualsToken) { return "Convert != to !=="; } } provideFix(info: QuickFixQueryInformation): Refactoring[] { - if (info.positionNode.kind === SyntaxKind.EqualsEqualsToken) { + if (info.positionNode.kind === ts.SyntaxKind.EqualsEqualsToken) { var newText = '==='; } - if (info.positionNode.kind === SyntaxKind.ExclamationEqualsToken) { + if (info.positionNode.kind === ts.SyntaxKind.ExclamationEqualsToken) { var newText = '!=='; } diff --git a/lib/main/lang/fixmyts/quickFix.ts b/lib/main/lang/fixmyts/quickFix.ts index 6a2f094c0..2719ada26 100644 --- a/lib/main/lang/fixmyts/quickFix.ts +++ b/lib/main/lang/fixmyts/quickFix.ts @@ -1,7 +1,6 @@ /** * Interfaces for quick fixes */ -import ts = require("typescript"); import project = require("../core/project"); diff --git a/lib/main/lang/fixmyts/quoteToTemplate.ts b/lib/main/lang/fixmyts/quoteToTemplate.ts index 36040f0c1..a3b9d832c 100644 --- a/lib/main/lang/fixmyts/quoteToTemplate.ts +++ b/lib/main/lang/fixmyts/quoteToTemplate.ts @@ -1,14 +1,12 @@ import {QuickFix, QuickFixQueryInformation, Refactoring} from "./quickFix"; -import * as ts from "typescript"; import * as ast from "./astUtils"; import {EOL} from "os"; -import {displayPartsToString, typeToDisplayParts, SyntaxKind} from "typescript"; class QuoteToTemplate implements QuickFix { key = QuoteToTemplate.name; canProvideFix(info: QuickFixQueryInformation): string { - if (info.positionNode.kind === SyntaxKind.StringLiteral) { + if (info.positionNode.kind === ts.SyntaxKind.StringLiteral) { return `Convert to Template String`; } } diff --git a/lib/main/lang/fixmyts/quotesToQuotes.ts b/lib/main/lang/fixmyts/quotesToQuotes.ts index d1f1c1032..0063c6703 100644 --- a/lib/main/lang/fixmyts/quotesToQuotes.ts +++ b/lib/main/lang/fixmyts/quotesToQuotes.ts @@ -1,14 +1,12 @@ import {QuickFix, QuickFixQueryInformation, Refactoring} from "./quickFix"; -import * as ts from "typescript"; import * as ast from "./astUtils"; import {EOL} from "os"; -import {displayPartsToString, typeToDisplayParts, SyntaxKind} from "typescript"; class QuotesToQuotes implements QuickFix { key = QuotesToQuotes.name; canProvideFix(info: QuickFixQueryInformation): string { - if (info.positionNode.kind === SyntaxKind.StringLiteral) { + if (info.positionNode.kind === ts.SyntaxKind.StringLiteral) { if (info.positionNode.getText().trim()[0] === `'`) { return `Convert ' to "`; } diff --git a/lib/main/lang/modules/astToText.ts b/lib/main/lang/modules/astToText.ts index 026f0f5e4..f52843e2a 100644 --- a/lib/main/lang/modules/astToText.ts +++ b/lib/main/lang/modules/astToText.ts @@ -6,9 +6,6 @@ // Inspired by `ts.forEachChild`: // https://github.com/Microsoft/TypeScript/blob/65cbd91667acf890f21a3527b3647c7bc994ca32/src/compiler/parser.ts#L43-L320 -import * as ts from "typescript"; -import {SyntaxKind, Node} from "typescript"; - export function astToText(srcFile: ts.Node) { //// A useful function for debugging diff --git a/lib/main/lang/modules/building.ts b/lib/main/lang/modules/building.ts index d75423b7d..3e9ec4be5 100644 --- a/lib/main/lang/modules/building.ts +++ b/lib/main/lang/modules/building.ts @@ -1,4 +1,3 @@ -import ts = require('typescript'); import project = require('../core/project'); import mkdirp = require('mkdirp'); import path = require('path'); diff --git a/lib/main/lang/modules/getExternalModules.ts b/lib/main/lang/modules/getExternalModules.ts index 41f50a29e..53390fe5e 100644 --- a/lib/main/lang/modules/getExternalModules.ts +++ b/lib/main/lang/modules/getExternalModules.ts @@ -1,18 +1,14 @@ // From https://github.com/Microsoft/TypeScript/pull/2173/files -import { -SyntaxKind, ModuleDeclaration, forEachChild, Program -} from "typescript"; - -export function getExternalModuleNames(program: Program): string[] { +export function getExternalModuleNames(program: ts.Program): string[] { var entries: string[] = []; program.getSourceFiles().forEach(sourceFile => { // Look for ambient external module declarations - forEachChild(sourceFile, child => { - if (child.kind === SyntaxKind.ModuleDeclaration && (child).name.kind === SyntaxKind.StringLiteral) { - entries.push((child).name.text); + ts.forEachChild(sourceFile, child => { + if (child.kind === ts.SyntaxKind.ModuleDeclaration && (child).name.kind === ts.SyntaxKind.StringLiteral) { + entries.push((child).name.text); } }); }); diff --git a/lib/main/lang/modules/programDependencies.ts b/lib/main/lang/modules/programDependencies.ts index ba533b03c..766b4e0ae 100644 --- a/lib/main/lang/modules/programDependencies.ts +++ b/lib/main/lang/modules/programDependencies.ts @@ -1,7 +1,6 @@ import {TypeScriptProjectFileDetails, pathIsRelative, consistentPath} from "../../tsconfig/tsconfig"; import tsconfig = require("../../tsconfig/tsconfig"); -import * as ts from "typescript"; import * as path from "path"; import * as fs from "fs"; diff --git a/lib/main/lang/projectService.ts b/lib/main/lang/projectService.ts index 6d9a407ec..001e70412 100644 --- a/lib/main/lang/projectService.ts +++ b/lib/main/lang/projectService.ts @@ -4,7 +4,6 @@ import fs = require('fs'); import path = require('path'); import os = require('os'); -import ts = require('typescript'); import mkdirp = require('mkdirp'); var fuzzaldrin: { filter: (list: any[], prefix: string, property?: { key: string }) => any } = require('fuzzaldrin'); @@ -733,7 +732,7 @@ export function getNavigateToItems(query: FilePathQuery): Promisefile.getNamedDeclarations()) { let item: NavigateToItem = { name: getDeclarationName(declaration), kind: getNodeKind(declaration), diff --git a/lib/main/tsconfig/formatting.ts b/lib/main/tsconfig/formatting.ts index 1e76e519d..2c1bb1177 100644 --- a/lib/main/tsconfig/formatting.ts +++ b/lib/main/tsconfig/formatting.ts @@ -1,7 +1,6 @@ ///ts:ref=globals /// ///ts:ref:generated -import ts = require('typescript'); import os = require('os'); /// The following two interfaces come from typescript.d.ts but camelCased for JSON parsing diff --git a/lib/main/tsconfig/tsconfig.ts b/lib/main/tsconfig/tsconfig.ts index e2a11eb51..d5ff3ae3a 100644 --- a/lib/main/tsconfig/tsconfig.ts +++ b/lib/main/tsconfig/tsconfig.ts @@ -144,7 +144,6 @@ function errorWithDetails(error: Error, details: T): Error { import fs = require('fs'); import path = require('path'); import expand = require('glob-expand'); -import ts = require('typescript'); import os = require('os'); import formatting = require('./formatting'); diff --git a/lib/tsconfig.json b/lib/tsconfig.json index cc456547d..9b54279c5 100644 --- a/lib/tsconfig.json +++ b/lib/tsconfig.json @@ -6,7 +6,7 @@ "noImplicitAny": false, "removeComments": true, "noLib": false, - "preserveConstEnums": false, + "preserveConstEnums": true, "outDir": "../dist", "sourceMap": false }, @@ -67,6 +67,45 @@ "./main/tsconfig/formatting.ts", "./main/tsconfig/simpleValidator.ts", "./main/tsconfig/tsconfig.ts", + "./typescript/compiler/binder.ts", + "./typescript/compiler/checker.ts", + "./typescript/compiler/commandLineParser.ts", + "./typescript/compiler/core.ts", + "./typescript/compiler/declarationEmitter.ts", + "./typescript/compiler/diagnosticInformationMap.generated.ts", + "./typescript/compiler/emitter.ts", + "./typescript/compiler/parser.ts", + "./typescript/compiler/program.ts", + "./typescript/compiler/scanner.ts", + "./typescript/compiler/sys.ts", + "./typescript/compiler/types.ts", + "./typescript/compiler/utilities.ts", + "./typescript/makeTypeScriptGlobal.ts", + "./typescript/services/breakpoints.ts", + "./typescript/services/formatting/formatting.ts", + "./typescript/services/formatting/formattingContext.ts", + "./typescript/services/formatting/formattingRequestKind.ts", + "./typescript/services/formatting/formattingScanner.ts", + "./typescript/services/formatting/references.ts", + "./typescript/services/formatting/rule.ts", + "./typescript/services/formatting/ruleAction.ts", + "./typescript/services/formatting/ruleDescriptor.ts", + "./typescript/services/formatting/ruleFlag.ts", + "./typescript/services/formatting/ruleOperation.ts", + "./typescript/services/formatting/ruleOperationContext.ts", + "./typescript/services/formatting/rules.ts", + "./typescript/services/formatting/rulesMap.ts", + "./typescript/services/formatting/rulesProvider.ts", + "./typescript/services/formatting/smartIndenter.ts", + "./typescript/services/formatting/tokenRange.ts", + "./typescript/services/navigateTo.ts", + "./typescript/services/navigationBar.ts", + "./typescript/services/outliningElementsCollector.ts", + "./typescript/services/patternMatcher.ts", + "./typescript/services/services.ts", + "./typescript/services/shims.ts", + "./typescript/services/signatureHelp.ts", + "./typescript/services/utilities.ts", "./typings/atom/atom.d.ts", "./typings/atompromise.d.ts", "./typings/bluebird.d.ts", diff --git a/lib/typescript/compiler/binder.ts b/lib/typescript/compiler/binder.ts new file mode 100644 index 000000000..f510a0bef --- /dev/null +++ b/lib/typescript/compiler/binder.ts @@ -0,0 +1,618 @@ +/// + +/* @internal */ +module ts { + export let bindTime = 0; + + export const enum ModuleInstanceState { + NonInstantiated = 0, + Instantiated = 1, + ConstEnumOnly = 2 + } + + export function getModuleInstanceState(node: Node): ModuleInstanceState { + // A module is uninstantiated if it contains only + // 1. interface declarations, type alias declarations + if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.TypeAliasDeclaration) { + return ModuleInstanceState.NonInstantiated; + } + // 2. const enum declarations + else if (isConstEnumDeclaration(node)) { + return ModuleInstanceState.ConstEnumOnly; + } + // 3. non-exported import declarations + else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && !(node.flags & NodeFlags.Export)) { + return ModuleInstanceState.NonInstantiated; + } + // 4. other uninstantiated module declarations. + else if (node.kind === SyntaxKind.ModuleBlock) { + let state = ModuleInstanceState.NonInstantiated; + forEachChild(node, n => { + switch (getModuleInstanceState(n)) { + case ModuleInstanceState.NonInstantiated: + // child is non-instantiated - continue searching + return false; + case ModuleInstanceState.ConstEnumOnly: + // child is const enum only - record state and continue searching + state = ModuleInstanceState.ConstEnumOnly; + return false; + case ModuleInstanceState.Instantiated: + // child is instantiated - record state and stop + state = ModuleInstanceState.Instantiated; + return true; + } + }); + return state; + } + else if (node.kind === SyntaxKind.ModuleDeclaration) { + return getModuleInstanceState((node).body); + } + else { + return ModuleInstanceState.Instantiated; + } + } + + export function bindSourceFile(file: SourceFile): void { + let start = new Date().getTime(); + bindSourceFileWorker(file); + bindTime += new Date().getTime() - start; + } + + function bindSourceFileWorker(file: SourceFile): void { + let parent: Node; + let container: Node; + let blockScopeContainer: Node; + let lastContainer: Node; + let symbolCount = 0; + let Symbol = objectAllocator.getSymbolConstructor(); + + if (!file.locals) { + file.locals = {}; + container = file; + setBlockScopeContainer(file, /*cleanLocals*/ false); + bind(file); + file.symbolCount = symbolCount; + } + + function createSymbol(flags: SymbolFlags, name: string): Symbol { + symbolCount++; + return new Symbol(flags, name); + } + + function setBlockScopeContainer(node: Node, cleanLocals: boolean) { + blockScopeContainer = node; + if (cleanLocals) { + blockScopeContainer.locals = undefined; + } + } + + function addDeclarationToSymbol(symbol: Symbol, node: Declaration, symbolKind: SymbolFlags) { + symbol.flags |= symbolKind; + if (!symbol.declarations) symbol.declarations = []; + symbol.declarations.push(node); + if (symbolKind & SymbolFlags.HasExports && !symbol.exports) symbol.exports = {}; + if (symbolKind & SymbolFlags.HasMembers && !symbol.members) symbol.members = {}; + node.symbol = symbol; + if (symbolKind & SymbolFlags.Value && !symbol.valueDeclaration) symbol.valueDeclaration = node; + } + + // Should not be called on a declaration with a computed property name, + // unless it is a well known Symbol. + function getDeclarationName(node: Declaration): string { + if (node.name) { + if (node.kind === SyntaxKind.ModuleDeclaration && node.name.kind === SyntaxKind.StringLiteral) { + return '"' + (node.name).text + '"'; + } + if (node.name.kind === SyntaxKind.ComputedPropertyName) { + let nameExpression = (node.name).expression; + Debug.assert(isWellKnownSymbolSyntactically(nameExpression)); + return getPropertyNameForKnownSymbolName((nameExpression).name.text); + } + return (node.name).text; + } + switch (node.kind) { + case SyntaxKind.ConstructorType: + case SyntaxKind.Constructor: + return "__constructor"; + case SyntaxKind.FunctionType: + case SyntaxKind.CallSignature: + return "__call"; + case SyntaxKind.ConstructSignature: + return "__new"; + case SyntaxKind.IndexSignature: + return "__index"; + case SyntaxKind.ExportDeclaration: + return "__export"; + case SyntaxKind.ExportAssignment: + return (node).isExportEquals ? "export=" : "default"; + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ClassDeclaration: + return node.flags & NodeFlags.Default ? "default" : undefined; + } + } + + function getDisplayName(node: Declaration): string { + return node.name ? declarationNameToString(node.name) : getDeclarationName(node); + } + + function declareSymbol(symbols: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol { + Debug.assert(!hasDynamicName(node)); + + // The exported symbol for an export default function/class node is always named "default" + let name = node.flags & NodeFlags.Default && parent ? "default" : getDeclarationName(node); + + let symbol: Symbol; + if (name !== undefined) { + symbol = hasProperty(symbols, name) ? symbols[name] : (symbols[name] = createSymbol(0, name)); + if (symbol.flags & excludes) { + if (node.name) { + node.name.parent = node; + } + + // Report errors every position with duplicate declaration + // Report errors on previous encountered declarations + let message = symbol.flags & SymbolFlags.BlockScopedVariable + ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 + : Diagnostics.Duplicate_identifier_0; + + forEach(symbol.declarations, declaration => { + file.bindDiagnostics.push(createDiagnosticForNode(declaration.name || declaration, message, getDisplayName(declaration))); + }); + file.bindDiagnostics.push(createDiagnosticForNode(node.name || node, message, getDisplayName(node))); + + symbol = createSymbol(0, name); + } + } + else { + symbol = createSymbol(0, "__missing"); + } + addDeclarationToSymbol(symbol, node, includes); + symbol.parent = parent; + + if ((node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) && symbol.exports) { + // TypeScript 1.0 spec (April 2014): 8.4 + // Every class automatically contains a static property member named 'prototype', + // the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter. + // It is an error to explicitly declare a static property member with the name 'prototype'. + let prototypeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Prototype, "prototype"); + if (hasProperty(symbol.exports, prototypeSymbol.name)) { + if (node.name) { + node.name.parent = node; + } + file.bindDiagnostics.push(createDiagnosticForNode(symbol.exports[prototypeSymbol.name].declarations[0], + Diagnostics.Duplicate_identifier_0, prototypeSymbol.name)); + } + symbol.exports[prototypeSymbol.name] = prototypeSymbol; + prototypeSymbol.parent = symbol; + } + + return symbol; + } + + function declareModuleMember(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags) { + let hasExportModifier = getCombinedNodeFlags(node) & NodeFlags.Export; + if (symbolKind & SymbolFlags.Alias) { + if (node.kind === SyntaxKind.ExportSpecifier || (node.kind === SyntaxKind.ImportEqualsDeclaration && hasExportModifier)) { + declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes); + } + else { + declareSymbol(container.locals, undefined, node, symbolKind, symbolExcludes); + } + } + else { + // Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue, + // ExportType, or ExportContainer flag, and an associated export symbol with all the correct flags set + // on it. There are 2 main reasons: + // + // 1. We treat locals and exports of the same name as mutually exclusive within a container. + // That means the binder will issue a Duplicate Identifier error if you mix locals and exports + // with the same name in the same container. + // TODO: Make this a more specific error and decouple it from the exclusion logic. + // 2. When we checkIdentifier in the checker, we set its resolved symbol to the local symbol, + // but return the export symbol (by calling getExportSymbolOfValueSymbolIfExported). That way + // when the emitter comes back to it, it knows not to qualify the name if it was found in a containing scope. + if (hasExportModifier || container.flags & NodeFlags.ExportContext) { + let exportKind = (symbolKind & SymbolFlags.Value ? SymbolFlags.ExportValue : 0) | + (symbolKind & SymbolFlags.Type ? SymbolFlags.ExportType : 0) | + (symbolKind & SymbolFlags.Namespace ? SymbolFlags.ExportNamespace : 0); + let local = declareSymbol(container.locals, undefined, node, exportKind, symbolExcludes); + local.exportSymbol = declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes); + node.localSymbol = local; + } + else { + declareSymbol(container.locals, undefined, node, symbolKind, symbolExcludes); + } + } + } + + // All container nodes are kept on a linked list in declaration order. This list is used by the getLocalNameOfContainer function + // in the type checker to validate that the local name used for a container is unique. + function bindChildren(node: Node, symbolKind: SymbolFlags, isBlockScopeContainer: boolean) { + if (symbolKind & SymbolFlags.HasLocals) { + node.locals = {}; + } + + let saveParent = parent; + let saveContainer = container; + let savedBlockScopeContainer = blockScopeContainer; + parent = node; + if (symbolKind & SymbolFlags.IsContainer) { + container = node; + + addToContainerChain(container); + } + + if (isBlockScopeContainer) { + // in incremental scenarios we might reuse nodes that already have locals being allocated + // during the bind step these locals should be dropped to prevent using stale data. + // locals should always be dropped unless they were previously initialized by the binder + // these cases are: + // - node has locals (symbolKind & HasLocals) !== 0 + // - node is a source file + setBlockScopeContainer(node, /*cleanLocals*/ (symbolKind & SymbolFlags.HasLocals) === 0 && node.kind !== SyntaxKind.SourceFile); + } + + forEachChild(node, bind); + container = saveContainer; + parent = saveParent; + blockScopeContainer = savedBlockScopeContainer; + } + + function addToContainerChain(node: Node) { + if (lastContainer) { + lastContainer.nextContainer = node; + } + + lastContainer = node; + } + + function bindDeclaration(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags, isBlockScopeContainer: boolean) { + switch (container.kind) { + case SyntaxKind.ModuleDeclaration: + declareModuleMember(node, symbolKind, symbolExcludes); + break; + case SyntaxKind.SourceFile: + if (isExternalModule(container)) { + declareModuleMember(node, symbolKind, symbolExcludes); + break; + } + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + declareSymbol(container.locals, undefined, node, symbolKind, symbolExcludes); + break; + case SyntaxKind.ClassExpression: + case SyntaxKind.ClassDeclaration: + if (node.flags & NodeFlags.Static) { + declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes); + break; + } + case SyntaxKind.TypeLiteral: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.InterfaceDeclaration: + declareSymbol(container.symbol.members, container.symbol, node, symbolKind, symbolExcludes); + break; + case SyntaxKind.EnumDeclaration: + declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes); + break; + } + bindChildren(node, symbolKind, isBlockScopeContainer); + } + + function isAmbientContext(node: Node): boolean { + while (node) { + if (node.flags & NodeFlags.Ambient) return true; + node = node.parent; + } + return false; + } + + function hasExportDeclarations(node: ModuleDeclaration | SourceFile): boolean { + var body = node.kind === SyntaxKind.SourceFile ? node : (node).body; + if (body.kind === SyntaxKind.SourceFile || body.kind === SyntaxKind.ModuleBlock) { + for (let stat of (body).statements) { + if (stat.kind === SyntaxKind.ExportDeclaration || stat.kind === SyntaxKind.ExportAssignment) { + return true; + } + } + } + return false; + } + + function setExportContextFlag(node: ModuleDeclaration | SourceFile) { + // A declaration source file or ambient module declaration that contains no export declarations (but possibly regular + // declarations with export modifiers) is an export context in which declarations are implicitly exported. + if (isAmbientContext(node) && !hasExportDeclarations(node)) { + node.flags |= NodeFlags.ExportContext; + } + else { + node.flags &= ~NodeFlags.ExportContext; + } + } + + function bindModuleDeclaration(node: ModuleDeclaration) { + setExportContextFlag(node); + if (node.name.kind === SyntaxKind.StringLiteral) { + bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true); + } + else { + let state = getModuleInstanceState(node); + if (state === ModuleInstanceState.NonInstantiated) { + bindDeclaration(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes, /*isBlockScopeContainer*/ true); + } + else { + bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true); + let currentModuleIsConstEnumOnly = state === ModuleInstanceState.ConstEnumOnly; + if (node.symbol.constEnumOnlyModule === undefined) { + // non-merged case - use the current state + node.symbol.constEnumOnlyModule = currentModuleIsConstEnumOnly; + } + else { + // merged case: module is const enum only if all its pieces are non-instantiated or const enum + node.symbol.constEnumOnlyModule = node.symbol.constEnumOnlyModule && currentModuleIsConstEnumOnly; + } + } + } + } + + function bindFunctionOrConstructorType(node: SignatureDeclaration) { + // For a given function symbol "<...>(...) => T" we want to generate a symbol identical + // to the one we would get for: { <...>(...): T } + // + // We do that by making an anonymous type literal symbol, and then setting the function + // symbol as its sole member. To the rest of the system, this symbol will be indistinguishable + // from an actual type literal symbol you would have gotten had you used the long form. + + let symbol = createSymbol(SymbolFlags.Signature, getDeclarationName(node)); + addDeclarationToSymbol(symbol, node, SymbolFlags.Signature); + bindChildren(node, SymbolFlags.Signature, /*isBlockScopeContainer:*/ false); + + let typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type"); + addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral); + typeLiteralSymbol.members = {}; + typeLiteralSymbol.members[node.kind === SyntaxKind.FunctionType ? "__call" : "__new"] = symbol + } + + function bindAnonymousDeclaration(node: Declaration, symbolKind: SymbolFlags, name: string, isBlockScopeContainer: boolean) { + let symbol = createSymbol(symbolKind, name); + addDeclarationToSymbol(symbol, node, symbolKind); + bindChildren(node, symbolKind, isBlockScopeContainer); + } + + function bindCatchVariableDeclaration(node: CatchClause) { + bindChildren(node, /*symbolKind:*/ 0, /*isBlockScopeContainer:*/ true); + } + + function bindBlockScopedDeclaration(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags) { + switch (blockScopeContainer.kind) { + case SyntaxKind.ModuleDeclaration: + declareModuleMember(node, symbolKind, symbolExcludes); + break; + case SyntaxKind.SourceFile: + if (isExternalModule(container)) { + declareModuleMember(node, symbolKind, symbolExcludes); + break; + } + // fall through. + default: + if (!blockScopeContainer.locals) { + blockScopeContainer.locals = {}; + addToContainerChain(blockScopeContainer); + } + declareSymbol(blockScopeContainer.locals, undefined, node, symbolKind, symbolExcludes); + } + bindChildren(node, symbolKind, /*isBlockScopeContainer*/ false); + } + + function bindBlockScopedVariableDeclaration(node: Declaration) { + bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes); + } + + function getDestructuringParameterName(node: Declaration) { + return "__" + indexOf((node.parent).parameters, node); + } + + function bind(node: Node) { + node.parent = parent; + + switch (node.kind) { + case SyntaxKind.TypeParameter: + bindDeclaration(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes, /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.Parameter: + bindParameter(node); + break; + case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: + if (isBindingPattern((node).name)) { + bindChildren(node, 0, /*isBlockScopeContainer*/ false); + } + else if (isBlockOrCatchScoped(node)) { + bindBlockScopedVariableDeclaration(node); + } + else { + bindDeclaration(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes, /*isBlockScopeContainer*/ false); + } + break; + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property | ((node).questionToken ? SymbolFlags.Optional : 0), SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.PropertyAssignment: + case SyntaxKind.ShorthandPropertyAssignment: + bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.EnumMember: + bindPropertyOrMethodOrAccessor(node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes, /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + bindDeclaration(node, SymbolFlags.Signature, 0, /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + // If this is an ObjectLiteralExpression method, then it sits in the same space + // as other properties in the object literal. So we use SymbolFlags.PropertyExcludes + // so that it will conflict with any other object literal members with the same + // name. + bindPropertyOrMethodOrAccessor(node, SymbolFlags.Method | ((node).questionToken ? SymbolFlags.Optional : 0), + isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true); + break; + case SyntaxKind.FunctionDeclaration: + bindDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes, /*isBlockScopeContainer*/ true); + break; + case SyntaxKind.Constructor: + bindDeclaration(node, SymbolFlags.Constructor, /*symbolExcludes:*/ 0, /*isBlockScopeContainer:*/ true); + break; + case SyntaxKind.GetAccessor: + bindPropertyOrMethodOrAccessor(node, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes, /*isBlockScopeContainer*/ true); + break; + case SyntaxKind.SetAccessor: + bindPropertyOrMethodOrAccessor(node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes, /*isBlockScopeContainer*/ true); + break; + + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + bindFunctionOrConstructorType(node); + break; + + case SyntaxKind.TypeLiteral: + bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type", /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.ObjectLiteralExpression: + bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object", /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + bindAnonymousDeclaration(node, SymbolFlags.Function, "__function", /*isBlockScopeContainer*/ true); + break; + case SyntaxKind.ClassExpression: + bindAnonymousDeclaration(node, SymbolFlags.Class, "__class", /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.CatchClause: + bindCatchVariableDeclaration(node); + break; + case SyntaxKind.ClassDeclaration: + bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes); + break; + case SyntaxKind.InterfaceDeclaration: + bindDeclaration(node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes, /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.TypeAliasDeclaration: + bindDeclaration(node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes, /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.EnumDeclaration: + if (isConst(node)) { + bindDeclaration(node, SymbolFlags.ConstEnum, SymbolFlags.ConstEnumExcludes, /*isBlockScopeContainer*/ false); + } + else { + bindDeclaration(node, SymbolFlags.RegularEnum, SymbolFlags.RegularEnumExcludes, /*isBlockScopeContainer*/ false); + } + break; + case SyntaxKind.ModuleDeclaration: + bindModuleDeclaration(node); + break; + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.NamespaceImport: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ExportSpecifier: + bindDeclaration(node, SymbolFlags.Alias, SymbolFlags.AliasExcludes, /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.ImportClause: + if ((node).name) { + bindDeclaration(node, SymbolFlags.Alias, SymbolFlags.AliasExcludes, /*isBlockScopeContainer*/ false); + } + else { + bindChildren(node, 0, /*isBlockScopeContainer*/ false); + } + break; + case SyntaxKind.ExportDeclaration: + if (!(node).exportClause) { + // All export * declarations are collected in an __export symbol + declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.ExportStar, 0); + } + bindChildren(node, 0, /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.ExportAssignment: + if ((node).expression.kind === SyntaxKind.Identifier) { + // An export default clause with an identifier exports all meanings of that identifier + declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes); + } + else { + // An export default clause with an expression exports a value + declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes); + } + bindChildren(node, 0, /*isBlockScopeContainer*/ false); + break; + case SyntaxKind.SourceFile: + setExportContextFlag(node); + if (isExternalModule(node)) { + bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + removeFileExtension((node).fileName) + '"', /*isBlockScopeContainer*/ true); + break; + } + case SyntaxKind.Block: + // do not treat function block a block-scope container + // all block-scope locals that reside in this block should go to the function locals. + // Otherwise this won't be considered as redeclaration of a block scoped local: + // function foo() { + // let x; + // let x; + // } + // 'let x' will be placed into the function locals and 'let x' - into the locals of the block + bindChildren(node, 0, /*isBlockScopeContainer*/ !isFunctionLike(node.parent)); + break; + case SyntaxKind.CatchClause: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.CaseBlock: + bindChildren(node, 0, /*isBlockScopeContainer*/ true); + break; + default: + let saveParent = parent; + parent = node; + forEachChild(node, bind); + parent = saveParent; + } + } + + function bindParameter(node: ParameterDeclaration) { + if (isBindingPattern(node.name)) { + bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, getDestructuringParameterName(node), /*isBlockScopeContainer*/ false); + } + else { + bindDeclaration(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes, /*isBlockScopeContainer*/ false); + } + + // If this is a property-parameter, then also declare the property symbol into the + // containing class. + if (node.flags & NodeFlags.AccessibilityModifier && + node.parent.kind === SyntaxKind.Constructor && + (node.parent.parent.kind === SyntaxKind.ClassDeclaration || node.parent.parent.kind === SyntaxKind.ClassExpression)) { + + let classDeclaration = node.parent.parent; + declareSymbol(classDeclaration.symbol.members, classDeclaration.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + } + } + + function bindPropertyOrMethodOrAccessor(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags, isBlockScopeContainer: boolean) { + if (hasDynamicName(node)) { + bindAnonymousDeclaration(node, symbolKind, "__computed", isBlockScopeContainer); + } + else { + bindDeclaration(node, symbolKind, symbolExcludes, isBlockScopeContainer); + } + } + } +} diff --git a/lib/typescript/compiler/checker.ts b/lib/typescript/compiler/checker.ts new file mode 100644 index 000000000..c1bc450c0 --- /dev/null +++ b/lib/typescript/compiler/checker.ts @@ -0,0 +1,13164 @@ +/// + +/* @internal */ +module ts { + let nextSymbolId = 1; + let nextNodeId = 1; + let nextMergeId = 1; + + export function getNodeId(node: Node): number { + if (!node.id) node.id = nextNodeId++; + return node.id; + } + + export let checkTime = 0; + + export function getSymbolId(symbol: Symbol): number { + if (!symbol.id) { + symbol.id = nextSymbolId++; + } + + return symbol.id; + } + + export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker { + let Symbol = objectAllocator.getSymbolConstructor(); + let Type = objectAllocator.getTypeConstructor(); + let Signature = objectAllocator.getSignatureConstructor(); + + let typeCount = 0; + + let emptyArray: any[] = []; + let emptySymbols: SymbolTable = {}; + + let compilerOptions = host.getCompilerOptions(); + let languageVersion = compilerOptions.target || ScriptTarget.ES3; + + let emitResolver = createResolver(); + + let undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined"); + let argumentsSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "arguments"); + + let checker: TypeChecker = { + getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"), + getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"), + getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount"), + getTypeCount: () => typeCount, + isUndefinedSymbol: symbol => symbol === undefinedSymbol, + isArgumentsSymbol: symbol => symbol === argumentsSymbol, + getDiagnostics, + getGlobalDiagnostics, + getTypeOfSymbolAtLocation, + getDeclaredTypeOfSymbol, + getPropertiesOfType, + getPropertyOfType, + getSignaturesOfType, + getIndexTypeOfType, + getReturnTypeOfSignature, + getSymbolsInScope, + getSymbolAtLocation, + getShorthandAssignmentValueSymbol, + getTypeAtLocation, + typeToString, + getSymbolDisplayBuilder, + symbolToString, + getAugmentedPropertiesOfType, + getRootSymbols, + getContextualType, + getFullyQualifiedName, + getResolvedSignature, + getConstantValue, + isValidPropertyAccess, + getSignatureFromDeclaration, + isImplementationOfOverload, + getAliasedSymbol: resolveAlias, + getEmitResolver, + getExportsOfModule: getExportsOfModuleAsArray, + }; + + let unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown"); + let resolvingSymbol = createSymbol(SymbolFlags.Transient, "__resolving__"); + + let anyType = createIntrinsicType(TypeFlags.Any, "any"); + let stringType = createIntrinsicType(TypeFlags.String, "string"); + let numberType = createIntrinsicType(TypeFlags.Number, "number"); + let booleanType = createIntrinsicType(TypeFlags.Boolean, "boolean"); + let esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol"); + let voidType = createIntrinsicType(TypeFlags.Void, "void"); + let undefinedType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsUndefinedOrNull, "undefined"); + let nullType = createIntrinsicType(TypeFlags.Null | TypeFlags.ContainsUndefinedOrNull, "null"); + let unknownType = createIntrinsicType(TypeFlags.Any, "unknown"); + let resolvingType = createIntrinsicType(TypeFlags.Any, "__resolving__"); + + let emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + let anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + let noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + + let anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, false, false); + let unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, false, false); + + let globals: SymbolTable = {}; + + let globalArraySymbol: Symbol; + let globalESSymbolConstructorSymbol: Symbol; + + let globalObjectType: ObjectType; + let globalFunctionType: ObjectType; + let globalArrayType: ObjectType; + let globalStringType: ObjectType; + let globalNumberType: ObjectType; + let globalBooleanType: ObjectType; + let globalRegExpType: ObjectType; + let globalTemplateStringsArrayType: ObjectType; + let globalESSymbolType: ObjectType; + let globalIterableType: ObjectType; + + let anyArrayType: Type; + let getGlobalClassDecoratorType: () => ObjectType; + let getGlobalParameterDecoratorType: () => ObjectType; + let getGlobalPropertyDecoratorType: () => ObjectType; + let getGlobalMethodDecoratorType: () => ObjectType; + + let tupleTypes: Map = {}; + let unionTypes: Map = {}; + let stringLiteralTypes: Map = {}; + let emitExtends = false; + let emitDecorate = false; + let emitParam = false; + + let mergedSymbols: Symbol[] = []; + let symbolLinks: SymbolLinks[] = []; + let nodeLinks: NodeLinks[] = []; + let potentialThisCollisions: Node[] = []; + + let diagnostics = createDiagnosticCollection(); + + let primitiveTypeInfo: Map<{ type: Type; flags: TypeFlags }> = { + "string": { + type: stringType, + flags: TypeFlags.StringLike + }, + "number": { + type: numberType, + flags: TypeFlags.NumberLike + }, + "boolean": { + type: booleanType, + flags: TypeFlags.Boolean + }, + "symbol": { + type: esSymbolType, + flags: TypeFlags.ESSymbol + } + }; + + function getEmitResolver(sourceFile?: SourceFile) { + // Ensure we have all the type information in place for this file so that all the + // emitter questions of this resolver will return the right information. + getDiagnostics(sourceFile); + return emitResolver; + } + + function error(location: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void { + let diagnostic = location + ? createDiagnosticForNode(location, message, arg0, arg1, arg2) + : createCompilerDiagnostic(message, arg0, arg1, arg2); + diagnostics.add(diagnostic); + } + + function createSymbol(flags: SymbolFlags, name: string): Symbol { + return new Symbol(flags, name); + } + + function getExcludedSymbolFlags(flags: SymbolFlags): SymbolFlags { + let result: SymbolFlags = 0; + if (flags & SymbolFlags.BlockScopedVariable) result |= SymbolFlags.BlockScopedVariableExcludes; + if (flags & SymbolFlags.FunctionScopedVariable) result |= SymbolFlags.FunctionScopedVariableExcludes; + if (flags & SymbolFlags.Property) result |= SymbolFlags.PropertyExcludes; + if (flags & SymbolFlags.EnumMember) result |= SymbolFlags.EnumMemberExcludes; + if (flags & SymbolFlags.Function) result |= SymbolFlags.FunctionExcludes; + if (flags & SymbolFlags.Class) result |= SymbolFlags.ClassExcludes; + if (flags & SymbolFlags.Interface) result |= SymbolFlags.InterfaceExcludes; + if (flags & SymbolFlags.RegularEnum) result |= SymbolFlags.RegularEnumExcludes; + if (flags & SymbolFlags.ConstEnum) result |= SymbolFlags.ConstEnumExcludes; + if (flags & SymbolFlags.ValueModule) result |= SymbolFlags.ValueModuleExcludes; + if (flags & SymbolFlags.Method) result |= SymbolFlags.MethodExcludes; + if (flags & SymbolFlags.GetAccessor) result |= SymbolFlags.GetAccessorExcludes; + if (flags & SymbolFlags.SetAccessor) result |= SymbolFlags.SetAccessorExcludes; + if (flags & SymbolFlags.TypeParameter) result |= SymbolFlags.TypeParameterExcludes; + if (flags & SymbolFlags.TypeAlias) result |= SymbolFlags.TypeAliasExcludes; + if (flags & SymbolFlags.Alias) result |= SymbolFlags.AliasExcludes; + return result; + } + + function recordMergedSymbol(target: Symbol, source: Symbol) { + if (!source.mergeId) source.mergeId = nextMergeId++; + mergedSymbols[source.mergeId] = target; + } + + function cloneSymbol(symbol: Symbol): Symbol { + let result = createSymbol(symbol.flags | SymbolFlags.Merged, symbol.name); + result.declarations = symbol.declarations.slice(0); + result.parent = symbol.parent; + if (symbol.valueDeclaration) result.valueDeclaration = symbol.valueDeclaration; + if (symbol.constEnumOnlyModule) result.constEnumOnlyModule = true; + if (symbol.members) result.members = cloneSymbolTable(symbol.members); + if (symbol.exports) result.exports = cloneSymbolTable(symbol.exports); + recordMergedSymbol(result, symbol); + return result; + } + + function mergeSymbol(target: Symbol, source: Symbol) { + if (!(target.flags & getExcludedSymbolFlags(source.flags))) { + if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) { + // reset flag when merging instantiated module into value module that has only const enums + target.constEnumOnlyModule = false; + } + target.flags |= source.flags; + if (!target.valueDeclaration && source.valueDeclaration) target.valueDeclaration = source.valueDeclaration; + forEach(source.declarations, node => { + target.declarations.push(node); + }); + if (source.members) { + if (!target.members) target.members = {}; + mergeSymbolTable(target.members, source.members); + } + if (source.exports) { + if (!target.exports) target.exports = {}; + mergeSymbolTable(target.exports, source.exports); + } + recordMergedSymbol(target, source); + } + else { + let message = target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable + ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; + forEach(source.declarations, node => { + error(node.name ? node.name : node, message, symbolToString(source)); + }); + forEach(target.declarations, node => { + error(node.name ? node.name : node, message, symbolToString(source)); + }); + } + } + + function cloneSymbolTable(symbolTable: SymbolTable): SymbolTable { + let result: SymbolTable = {}; + for (let id in symbolTable) { + if (hasProperty(symbolTable, id)) { + result[id] = symbolTable[id]; + } + } + return result; + } + + function mergeSymbolTable(target: SymbolTable, source: SymbolTable) { + for (let id in source) { + if (hasProperty(source, id)) { + if (!hasProperty(target, id)) { + target[id] = source[id]; + } + else { + let symbol = target[id]; + if (!(symbol.flags & SymbolFlags.Merged)) { + target[id] = symbol = cloneSymbol(symbol); + } + mergeSymbol(symbol, source[id]); + } + } + } + } + + function getSymbolLinks(symbol: Symbol): SymbolLinks { + if (symbol.flags & SymbolFlags.Transient) return symbol; + var id = getSymbolId(symbol); + return symbolLinks[id] || (symbolLinks[id] = {}); + } + + function getNodeLinks(node: Node): NodeLinks { + let nodeId = getNodeId(node); + return nodeLinks[nodeId] || (nodeLinks[nodeId] = {}); + } + + function getSourceFile(node: Node): SourceFile { + return getAncestor(node, SyntaxKind.SourceFile); + } + + function isGlobalSourceFile(node: Node) { + return node.kind === SyntaxKind.SourceFile && !isExternalModule(node); + } + + function getSymbol(symbols: SymbolTable, name: string, meaning: SymbolFlags): Symbol { + if (meaning && hasProperty(symbols, name)) { + let symbol = symbols[name]; + Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); + if (symbol.flags & meaning) { + return symbol; + } + if (symbol.flags & SymbolFlags.Alias) { + let target = resolveAlias(symbol); + // Unknown symbol means an error occurred in alias resolution, treat it as positive answer to avoid cascading errors + if (target === unknownSymbol || target.flags & meaning) { + return symbol; + } + } + } + // return undefined if we can't find a symbol. + } + + /** Returns true if node1 is defined before node 2**/ + function isDefinedBefore(node1: Node, node2: Node): boolean { + let file1 = getSourceFileOfNode(node1); + let file2 = getSourceFileOfNode(node2); + if (file1 === file2) { + return node1.pos <= node2.pos; + } + + if (!compilerOptions.out) { + return true; + } + + let sourceFiles = host.getSourceFiles(); + return sourceFiles.indexOf(file1) <= sourceFiles.indexOf(file2); + } + + // Resolve a given name for a given meaning at a given location. An error is reported if the name was not found and + // the nameNotFoundMessage argument is not undefined. Returns the resolved symbol, or undefined if no symbol with + // the given name can be found. + function resolveName(location: Node, name: string, meaning: SymbolFlags, nameNotFoundMessage: DiagnosticMessage, nameArg: string | Identifier): Symbol { + let result: Symbol; + let lastLocation: Node; + let propertyWithInvalidInitializer: Node; + let errorLocation = location; + let grandparent: Node; + + loop: while (location) { + // Locals of a source file are not in scope (because they get merged into the global symbol table) + if (location.locals && !isGlobalSourceFile(location)) { + if (result = getSymbol(location.locals, name, meaning)) { + break loop; + } + } + switch (location.kind) { + case SyntaxKind.SourceFile: + if (!isExternalModule(location)) break; + case SyntaxKind.ModuleDeclaration: + if (result = getSymbol(getSymbolOfNode(location).exports, name, meaning & SymbolFlags.ModuleMember)) { + if (result.flags & meaning || !(result.flags & SymbolFlags.Alias && getDeclarationOfAliasSymbol(result).kind === SyntaxKind.ExportSpecifier)) { + break loop; + } + result = undefined; + } + else if (location.kind === SyntaxKind.SourceFile || + (location.kind === SyntaxKind.ModuleDeclaration && (location).name.kind === SyntaxKind.StringLiteral)) { + result = getSymbol(getSymbolOfNode(location).exports, "default", meaning & SymbolFlags.ModuleMember); + let localSymbol = getLocalSymbolForExportDefault(result); + if (result && (result.flags & meaning) && localSymbol && localSymbol.name === name) { + break loop; + } + result = undefined; + } + break; + case SyntaxKind.EnumDeclaration: + if (result = getSymbol(getSymbolOfNode(location).exports, name, meaning & SymbolFlags.EnumMember)) { + break loop; + } + break; + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + // TypeScript 1.0 spec (April 2014): 8.4.1 + // Initializer expressions for instance member variables are evaluated in the scope + // of the class constructor body but are not permitted to reference parameters or + // local variables of the constructor. This effectively means that entities from outer scopes + // by the same name as a constructor parameter or local variable are inaccessible + // in initializer expressions for instance member variables. + if (location.parent.kind === SyntaxKind.ClassDeclaration && !(location.flags & NodeFlags.Static)) { + let ctor = findConstructorDeclaration(location.parent); + if (ctor && ctor.locals) { + if (getSymbol(ctor.locals, name, meaning & SymbolFlags.Value)) { + // Remember the property node, it will be used later to report appropriate error + propertyWithInvalidInitializer = location; + } + } + } + break; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + if (result = getSymbol(getSymbolOfNode(location).members, name, meaning & SymbolFlags.Type)) { + if (lastLocation && lastLocation.flags & NodeFlags.Static) { + // TypeScript 1.0 spec (April 2014): 3.4.1 + // The scope of a type parameter extends over the entire declaration with which the type + // parameter list is associated, with the exception of static member declarations in classes. + error(errorLocation, Diagnostics.Static_members_cannot_reference_class_type_parameters); + return undefined; + } + break loop; + } + break; + + // It is not legal to reference a class's own type parameters from a computed property name that + // belongs to the class. For example: + // + // function foo() { return '' } + // class C { // <-- Class's own type parameter T + // [foo()]() { } // <-- Reference to T from class's own computed property + // } + // + case SyntaxKind.ComputedPropertyName: + grandparent = location.parent.parent; + if (grandparent.kind === SyntaxKind.ClassDeclaration || grandparent.kind === SyntaxKind.InterfaceDeclaration) { + // A reference to this grandparent's type parameters would be an error + if (result = getSymbol(getSymbolOfNode(grandparent).members, name, meaning & SymbolFlags.Type)) { + error(errorLocation, Diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type); + return undefined; + } + } + break; + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + if (name === "arguments") { + result = argumentsSymbol; + break loop; + } + break; + case SyntaxKind.FunctionExpression: + if (name === "arguments") { + result = argumentsSymbol; + break loop; + } + let functionName = (location).name; + if (functionName && name === functionName.text) { + result = location.symbol; + break loop; + } + break; + case SyntaxKind.ClassExpression: + let className = (location).name; + if (className && name === className.text) { + result = location.symbol; + break loop; + } + break; + case SyntaxKind.Decorator: + // Decorators are resolved at the class declaration. Resolving at the parameter + // or member would result in looking up locals in the method. + // + // function y() {} + // class C { + // method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter. + // } + // + if (location.parent && location.parent.kind === SyntaxKind.Parameter) { + location = location.parent; + } + // + // function y() {} + // class C { + // @y method(x, y) {} // <-- decorator y should be resolved at the class declaration, not the method. + // } + // + if (location.parent && isClassElement(location.parent)) { + location = location.parent; + } + break; + } + lastLocation = location; + location = location.parent; + } + + if (!result) { + result = getSymbol(globals, name, meaning); + } + + if (!result) { + if (nameNotFoundMessage) { + error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg)); + } + return undefined; + } + + // Perform extra checks only if error reporting was requested + if (nameNotFoundMessage) { + if (propertyWithInvalidInitializer) { + // We have a match, but the reference occurred within a property initializer and the identifier also binds + // to a local variable in the constructor where the code will be emitted. + let propertyName = (propertyWithInvalidInitializer).name; + error(errorLocation, Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor, + declarationNameToString(propertyName), typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg)); + return undefined; + } + if (result.flags & SymbolFlags.BlockScopedVariable) { + checkResolvedBlockScopedVariable(result, errorLocation); + } + } + return result; + } + + function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void { + Debug.assert((result.flags & SymbolFlags.BlockScopedVariable) !== 0) + // Block-scoped variables cannot be used before their definition + let declaration = forEach(result.declarations, d => isBlockOrCatchScoped(d) ? d : undefined); + + Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined"); + + // first check if usage is lexically located after the declaration + let isUsedBeforeDeclaration = !isDefinedBefore(declaration, errorLocation); + if (!isUsedBeforeDeclaration) { + // lexical check succeeded however code still can be illegal. + // - block scoped variables cannot be used in its initializers + // let x = x; // illegal but usage is lexically after definition + // - in ForIn/ForOf statements variable cannot be contained in expression part + // for (let x in x) + // for (let x of x) + + // climb up to the variable declaration skipping binding patterns + let variableDeclaration = getAncestor(declaration, SyntaxKind.VariableDeclaration); + let container = getEnclosingBlockScopeContainer(variableDeclaration); + + if (variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement || + variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement) { + // variable statement/for statement case, + // use site should not be inside variable declaration (initializer of declaration or binding element) + isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, variableDeclaration, container); + } + else if (variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement || + variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) { + // ForIn/ForOf case - use site should not be used in expression part + let expression = (variableDeclaration.parent.parent).expression; + isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, expression, container); + } + } + if (isUsedBeforeDeclaration) { + error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(declaration.name)); + } + } + + /* Starting from 'initial' node walk up the parent chain until 'stopAt' node is reached. + * If at any point current node is equal to 'parent' node - return true. + * Return false if 'stopAt' node is reached or isFunctionLike(current) === true. + */ + function isSameScopeDescendentOf(initial: Node, parent: Node, stopAt: Node): boolean { + if (!parent) { + return false; + } + for (let current = initial; current && current !== stopAt && !isFunctionLike(current); current = current.parent) { + if (current === parent) { + return true; + } + } + return false; + } + + function getAnyImportSyntax(node: Node): AnyImportSyntax { + if (isAliasSymbolDeclaration(node)) { + if (node.kind === SyntaxKind.ImportEqualsDeclaration) { + return node; + } + + while (node && node.kind !== SyntaxKind.ImportDeclaration) { + node = node.parent; + } + return node; + } + } + + function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration { + return forEach(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined); + } + + function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol { + if (node.moduleReference.kind === SyntaxKind.ExternalModuleReference) { + return resolveExternalModuleSymbol(resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node))); + } + return getSymbolOfPartOfRightHandSideOfImportEquals(node.moduleReference, node); + } + + function getTargetOfImportClause(node: ImportClause): Symbol { + let moduleSymbol = resolveExternalModuleName(node, (node.parent).moduleSpecifier); + if (moduleSymbol) { + let exportDefaultSymbol = resolveSymbol(moduleSymbol.exports["default"]); + if (!exportDefaultSymbol) { + error(node.name, Diagnostics.External_module_0_has_no_default_export, symbolToString(moduleSymbol)); + } + return exportDefaultSymbol; + } + } + + function getTargetOfNamespaceImport(node: NamespaceImport): Symbol { + var moduleSpecifier = (node.parent.parent).moduleSpecifier; + return resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier); + } + + function getMemberOfModuleVariable(moduleSymbol: Symbol, name: string): Symbol { + if (moduleSymbol.flags & SymbolFlags.Variable) { + let typeAnnotation = (moduleSymbol.valueDeclaration).type; + if (typeAnnotation) { + return getPropertyOfType(getTypeFromTypeNode(typeAnnotation), name); + } + } + } + + // This function creates a synthetic symbol that combines the value side of one symbol with the + // type/namespace side of another symbol. Consider this example: + // + // declare module graphics { + // interface Point { + // x: number; + // y: number; + // } + // } + // declare var graphics: { + // Point: new (x: number, y: number) => graphics.Point; + // } + // declare module "graphics" { + // export = graphics; + // } + // + // An 'import { Point } from "graphics"' needs to create a symbol that combines the value side 'Point' + // property with the type/namespace side interface 'Point'. + function combineValueAndTypeSymbols(valueSymbol: Symbol, typeSymbol: Symbol): Symbol { + if (valueSymbol.flags & (SymbolFlags.Type | SymbolFlags.Namespace)) { + return valueSymbol; + } + let result = createSymbol(valueSymbol.flags | typeSymbol.flags, valueSymbol.name); + result.declarations = concatenate(valueSymbol.declarations, typeSymbol.declarations); + result.parent = valueSymbol.parent || typeSymbol.parent; + if (valueSymbol.valueDeclaration) result.valueDeclaration = valueSymbol.valueDeclaration; + if (typeSymbol.members) result.members = typeSymbol.members; + if (valueSymbol.exports) result.exports = valueSymbol.exports; + return result; + } + + function getExportOfModule(symbol: Symbol, name: string): Symbol { + if (symbol.flags & SymbolFlags.Module) { + let exports = getExportsOfSymbol(symbol); + if (hasProperty(exports, name)) { + return resolveSymbol(exports[name]); + } + } + } + + function getPropertyOfVariable(symbol: Symbol, name: string): Symbol { + if (symbol.flags & SymbolFlags.Variable) { + var typeAnnotation = (symbol.valueDeclaration).type; + if (typeAnnotation) { + return resolveSymbol(getPropertyOfType(getTypeFromTypeNode(typeAnnotation), name)); + } + } + } + + function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration, specifier: ImportOrExportSpecifier): Symbol { + let moduleSymbol = resolveExternalModuleName(node, node.moduleSpecifier); + let targetSymbol = resolveESModuleSymbol(moduleSymbol, node.moduleSpecifier); + if (targetSymbol) { + let name = specifier.propertyName || specifier.name; + if (name.text) { + let symbolFromModule = getExportOfModule(targetSymbol, name.text); + let symbolFromVariable = getPropertyOfVariable(targetSymbol, name.text); + let symbol = symbolFromModule && symbolFromVariable ? + combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) : + symbolFromModule || symbolFromVariable; + if (!symbol) { + error(name, Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(moduleSymbol), declarationNameToString(name)); + } + return symbol; + } + } + } + + function getTargetOfImportSpecifier(node: ImportSpecifier): Symbol { + return getExternalModuleMember(node.parent.parent.parent, node); + } + + function getTargetOfExportSpecifier(node: ExportSpecifier): Symbol { + return (node.parent.parent).moduleSpecifier ? + getExternalModuleMember(node.parent.parent, node) : + resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace); + } + + function getTargetOfExportAssignment(node: ExportAssignment): Symbol { + return resolveEntityName(node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace); + } + + function getTargetOfAliasDeclaration(node: Declaration): Symbol { + switch (node.kind) { + case SyntaxKind.ImportEqualsDeclaration: + return getTargetOfImportEqualsDeclaration(node); + case SyntaxKind.ImportClause: + return getTargetOfImportClause(node); + case SyntaxKind.NamespaceImport: + return getTargetOfNamespaceImport(node); + case SyntaxKind.ImportSpecifier: + return getTargetOfImportSpecifier(node); + case SyntaxKind.ExportSpecifier: + return getTargetOfExportSpecifier(node); + case SyntaxKind.ExportAssignment: + return getTargetOfExportAssignment(node); + } + } + + function resolveSymbol(symbol: Symbol): Symbol { + return symbol && symbol.flags & SymbolFlags.Alias && !(symbol.flags & (SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace)) ? resolveAlias(symbol) : symbol; + } + + function resolveAlias(symbol: Symbol): Symbol { + Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here."); + let links = getSymbolLinks(symbol); + if (!links.target) { + links.target = resolvingSymbol; + let node = getDeclarationOfAliasSymbol(symbol); + let target = getTargetOfAliasDeclaration(node); + if (links.target === resolvingSymbol) { + links.target = target || unknownSymbol; + } + else { + error(node, Diagnostics.Circular_definition_of_import_alias_0, symbolToString(symbol)); + } + } + else if (links.target === resolvingSymbol) { + links.target = unknownSymbol; + } + return links.target; + } + + function markExportAsReferenced(node: ImportEqualsDeclaration | ExportAssignment | ExportSpecifier) { + let symbol = getSymbolOfNode(node); + let target = resolveAlias(symbol); + if (target) { + let markAlias = + (target === unknownSymbol && compilerOptions.separateCompilation) || + (target !== unknownSymbol && (target.flags & SymbolFlags.Value) && !isConstEnumOrConstEnumOnlyModule(target)); + + if (markAlias) { + markAliasSymbolAsReferenced(symbol); + } + } + } + + // When an alias symbol is referenced, we need to mark the entity it references as referenced and in turn repeat that until + // we reach a non-alias or an exported entity (which is always considered referenced). We do this by checking the target of + // the alias as an expression (which recursively takes us back here if the target references another alias). + function markAliasSymbolAsReferenced(symbol: Symbol) { + let links = getSymbolLinks(symbol); + if (!links.referenced) { + links.referenced = true; + let node = getDeclarationOfAliasSymbol(symbol); + if (node.kind === SyntaxKind.ExportAssignment) { + // export default + checkExpressionCached((node).expression); + } + else if (node.kind === SyntaxKind.ExportSpecifier) { + // export { } or export { as foo } + checkExpressionCached((node).propertyName || (node).name); + } + else if (isInternalModuleImportEqualsDeclaration(node)) { + // import foo = + checkExpressionCached((node).moduleReference); + } + } + } + + // This function is only for imports with entity names + function getSymbolOfPartOfRightHandSideOfImportEquals(entityName: EntityName, importDeclaration?: ImportEqualsDeclaration): Symbol { + if (!importDeclaration) { + importDeclaration = getAncestor(entityName, SyntaxKind.ImportEqualsDeclaration); + Debug.assert(importDeclaration !== undefined); + } + // There are three things we might try to look for. In the following examples, + // the search term is enclosed in |...|: + // + // import a = |b|; // Namespace + // import a = |b.c|; // Value, type, namespace + // import a = |b.c|.d; // Namespace + if (entityName.kind === SyntaxKind.Identifier && isRightSideOfQualifiedNameOrPropertyAccess(entityName)) { + entityName = entityName.parent; + } + // Check for case 1 and 3 in the above example + if (entityName.kind === SyntaxKind.Identifier || entityName.parent.kind === SyntaxKind.QualifiedName) { + return resolveEntityName(entityName, SymbolFlags.Namespace); + } + else { + // Case 2 in above example + // entityName.kind could be a QualifiedName or a Missing identifier + Debug.assert(entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration); + return resolveEntityName(entityName, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace); + } + } + + function getFullyQualifiedName(symbol: Symbol): string { + return symbol.parent ? getFullyQualifiedName(symbol.parent) + "." + symbolToString(symbol) : symbolToString(symbol); + } + + // Resolves a qualified name and any involved aliases + function resolveEntityName(name: EntityName | Expression, meaning: SymbolFlags): Symbol { + if (nodeIsMissing(name)) { + return undefined; + } + + let symbol: Symbol; + if (name.kind === SyntaxKind.Identifier) { + symbol = resolveName(name, (name).text, meaning, Diagnostics.Cannot_find_name_0, name); + if (!symbol) { + return undefined; + } + } + else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) { + let left = name.kind === SyntaxKind.QualifiedName ? (name).left : (name).expression; + let right = name.kind === SyntaxKind.QualifiedName ? (name).right : (name).name; + + let namespace = resolveEntityName(left, SymbolFlags.Namespace); + if (!namespace || namespace === unknownSymbol || nodeIsMissing(right)) { + return undefined; + } + symbol = getSymbol(getExportsOfSymbol(namespace), right.text, meaning); + if (!symbol) { + error(right, Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(namespace), declarationNameToString(right)); + return undefined; + } + } + else { + Debug.fail("Unknown entity name kind."); + } + Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); + return symbol.flags & meaning ? symbol : resolveAlias(symbol); + } + + function isExternalModuleNameRelative(moduleName: string): boolean { + // TypeScript 1.0 spec (April 2014): 11.2.1 + // An external module name is "relative" if the first term is "." or "..". + return moduleName.substr(0, 2) === "./" || moduleName.substr(0, 3) === "../" || moduleName.substr(0, 2) === ".\\" || moduleName.substr(0, 3) === "..\\"; + } + + function resolveExternalModuleName(location: Node, moduleReferenceExpression: Expression): Symbol { + if (moduleReferenceExpression.kind !== SyntaxKind.StringLiteral) { + return; + } + + let moduleReferenceLiteral = moduleReferenceExpression; + let searchPath = getDirectoryPath(getSourceFile(location).fileName); + + // Module names are escaped in our symbol table. However, string literal values aren't. + // Escape the name in the "require(...)" clause to ensure we find the right symbol. + let moduleName = escapeIdentifier(moduleReferenceLiteral.text); + + if (!moduleName) return; + let isRelative = isExternalModuleNameRelative(moduleName); + if (!isRelative) { + let symbol = getSymbol(globals, '"' + moduleName + '"', SymbolFlags.ValueModule); + if (symbol) { + return symbol; + } + } + let sourceFile: SourceFile; + while (true) { + let fileName = normalizePath(combinePaths(searchPath, moduleName)); + sourceFile = host.getSourceFile(fileName + ".ts") || host.getSourceFile(fileName + ".d.ts"); + if (sourceFile || isRelative) { + break; + } + let parentPath = getDirectoryPath(searchPath); + if (parentPath === searchPath) { + break; + } + searchPath = parentPath; + } + if (sourceFile) { + if (sourceFile.symbol) { + return sourceFile.symbol; + } + error(moduleReferenceLiteral, Diagnostics.File_0_is_not_an_external_module, sourceFile.fileName); + return; + } + error(moduleReferenceLiteral, Diagnostics.Cannot_find_external_module_0, moduleName); + } + + // An external module with an 'export =' declaration resolves to the target of the 'export =' declaration, + // and an external module with no 'export =' declaration resolves to the module itself. + function resolveExternalModuleSymbol(moduleSymbol: Symbol): Symbol { + return moduleSymbol && resolveSymbol(moduleSymbol.exports["export="]) || moduleSymbol; + } + + // An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export =' + // references a symbol that is at least declared as a module or a variable. The target of the 'export =' may + // combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable). + function resolveESModuleSymbol(moduleSymbol: Symbol, moduleReferenceExpression: Expression): Symbol { + let symbol = resolveExternalModuleSymbol(moduleSymbol); + if (symbol && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable))) { + error(moduleReferenceExpression, Diagnostics.External_module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct, symbolToString(moduleSymbol)); + symbol = undefined; + } + return symbol; + } + + function getExportAssignmentSymbol(moduleSymbol: Symbol): Symbol { + return moduleSymbol.exports["export="]; + } + + function getExportsOfModuleAsArray(moduleSymbol: Symbol): Symbol[] { + return symbolsToArray(getExportsOfModule(moduleSymbol)); + } + + function getExportsOfSymbol(symbol: Symbol): SymbolTable { + return symbol.flags & SymbolFlags.Module ? getExportsOfModule(symbol) : symbol.exports || emptySymbols; + } + + function getExportsOfModule(moduleSymbol: Symbol): SymbolTable { + let links = getSymbolLinks(moduleSymbol); + return links.resolvedExports || (links.resolvedExports = getExportsForModule(moduleSymbol)); + } + + function extendExportSymbols(target: SymbolTable, source: SymbolTable) { + for (let id in source) { + if (id !== "default" && !hasProperty(target, id)) { + target[id] = source[id]; + } + } + } + + function getExportsForModule(moduleSymbol: Symbol): SymbolTable { + let result: SymbolTable; + let visitedSymbols: Symbol[] = []; + visit(moduleSymbol); + return result || moduleSymbol.exports; + + // The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example, + // module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error. + function visit(symbol: Symbol) { + if (symbol && symbol.flags & SymbolFlags.HasExports && !contains(visitedSymbols, symbol)) { + visitedSymbols.push(symbol); + if (symbol !== moduleSymbol) { + if (!result) { + result = cloneSymbolTable(moduleSymbol.exports); + } + extendExportSymbols(result, symbol.exports); + } + // All export * declarations are collected in an __export symbol by the binder + let exportStars = symbol.exports["__export"]; + if (exportStars) { + for (let node of exportStars.declarations) { + visit(resolveExternalModuleName(node, (node).moduleSpecifier)); + } + } + } + } + } + + function getMergedSymbol(symbol: Symbol): Symbol { + let merged: Symbol; + return symbol && symbol.mergeId && (merged = mergedSymbols[symbol.mergeId]) ? merged : symbol; + } + + function getSymbolOfNode(node: Node): Symbol { + return getMergedSymbol(node.symbol); + } + + function getParentOfSymbol(symbol: Symbol): Symbol { + return getMergedSymbol(symbol.parent); + } + + function getExportSymbolOfValueSymbolIfExported(symbol: Symbol): Symbol { + return symbol && (symbol.flags & SymbolFlags.ExportValue) !== 0 + ? getMergedSymbol(symbol.exportSymbol) + : symbol; + } + + function symbolIsValue(symbol: Symbol): boolean { + // If it is an instantiated symbol, then it is a value if the symbol it is an + // instantiation of is a value. + if (symbol.flags & SymbolFlags.Instantiated) { + return symbolIsValue(getSymbolLinks(symbol).target); + } + + // If the symbol has the value flag, it is trivially a value. + if (symbol.flags & SymbolFlags.Value) { + return true; + } + + // If it is an alias, then it is a value if the symbol it resolves to is a value. + if (symbol.flags & SymbolFlags.Alias) { + return (resolveAlias(symbol).flags & SymbolFlags.Value) !== 0; + } + + return false; + } + + function findConstructorDeclaration(node: ClassDeclaration): ConstructorDeclaration { + let members = node.members; + for (let member of members) { + if (member.kind === SyntaxKind.Constructor && nodeIsPresent((member).body)) { + return member; + } + } + } + + function createType(flags: TypeFlags): Type { + let result = new Type(checker, flags); + result.id = typeCount++; + return result; + } + + function createIntrinsicType(kind: TypeFlags, intrinsicName: string): IntrinsicType { + let type = createType(kind); + type.intrinsicName = intrinsicName; + return type; + } + + function createObjectType(kind: TypeFlags, symbol?: Symbol): ObjectType { + let type = createType(kind); + type.symbol = symbol; + return type; + } + + // A reserved member name starts with two underscores, but the third character cannot be an underscore + // or the @ symbol. A third underscore indicates an escaped form of an identifer that started + // with at least two underscores. The @ character indicates that the name is denoted by a well known ES + // Symbol instance. + function isReservedMemberName(name: string) { + return name.charCodeAt(0) === CharacterCodes._ && + name.charCodeAt(1) === CharacterCodes._ && + name.charCodeAt(2) !== CharacterCodes._ && + name.charCodeAt(2) !== CharacterCodes.at; + } + + function getNamedMembers(members: SymbolTable): Symbol[] { + let result: Symbol[]; + for (let id in members) { + if (hasProperty(members, id)) { + if (!isReservedMemberName(id)) { + if (!result) result = []; + let symbol = members[id]; + if (symbolIsValue(symbol)) { + result.push(symbol); + } + } + } + } + return result || emptyArray; + } + + function setObjectTypeMembers(type: ObjectType, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexType: Type, numberIndexType: Type): ResolvedType { + (type).members = members; + (type).properties = getNamedMembers(members); + (type).callSignatures = callSignatures; + (type).constructSignatures = constructSignatures; + if (stringIndexType) (type).stringIndexType = stringIndexType; + if (numberIndexType) (type).numberIndexType = numberIndexType; + return type; + } + + function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexType: Type, numberIndexType: Type): ResolvedType { + return setObjectTypeMembers(createObjectType(TypeFlags.Anonymous, symbol), + members, callSignatures, constructSignatures, stringIndexType, numberIndexType); + } + + function forEachSymbolTableInScope(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T { + let result: T; + for (let location = enclosingDeclaration; location; location = location.parent) { + // Locals of a source file are not in scope (because they get merged into the global symbol table) + if (location.locals && !isGlobalSourceFile(location)) { + if (result = callback(location.locals)) { + return result; + } + } + switch (location.kind) { + case SyntaxKind.SourceFile: + if (!isExternalModule(location)) { + break; + } + case SyntaxKind.ModuleDeclaration: + if (result = callback(getSymbolOfNode(location).exports)) { + return result; + } + break; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + if (result = callback(getSymbolOfNode(location).members)) { + return result; + } + break; + } + } + + return callback(globals); + } + + function getQualifiedLeftMeaning(rightMeaning: SymbolFlags) { + // If we are looking in value space, the parent meaning is value, other wise it is namespace + return rightMeaning === SymbolFlags.Value ? SymbolFlags.Value : SymbolFlags.Namespace; + } + + function getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] { + function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable): Symbol[] { + function canQualifySymbol(symbolFromSymbolTable: Symbol, meaning: SymbolFlags) { + // If the symbol is equivalent and doesn't need further qualification, this symbol is accessible + if (!needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning)) { + return true; + } + + // If symbol needs qualification, make sure that parent is accessible, if it is then this symbol is accessible too + let accessibleParent = getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing); + return !!accessibleParent; + } + + function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol) { + if (symbol === (resolvedAliasSymbol || symbolFromSymbolTable)) { + // if the symbolFromSymbolTable is not external module (it could be if it was determined as ambient external module and would be in globals table) + // and if symbolfrom symbolTable or alias resolution matches the symbol, + // check the symbol can be qualified, it is only then this symbol is accessible + return !forEach(symbolFromSymbolTable.declarations, hasExternalModuleSymbol) && + canQualifySymbol(symbolFromSymbolTable, meaning); + } + } + + // If symbol is directly available by its name in the symbol table + if (isAccessible(lookUp(symbols, symbol.name))) { + return [symbol]; + } + + // Check if symbol is any of the alias + return forEachValue(symbols, symbolFromSymbolTable => { + if (symbolFromSymbolTable.flags & SymbolFlags.Alias && symbolFromSymbolTable.name !== "export=") { + if (!useOnlyExternalAliasing || // We can use any type of alias to get the name + // Is this external alias, then use it to name + ts.forEach(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration)) { + + let resolvedImportedSymbol = resolveAlias(symbolFromSymbolTable); + if (isAccessible(symbolFromSymbolTable, resolveAlias(symbolFromSymbolTable))) { + return [symbolFromSymbolTable]; + } + + // Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain + // but only if the symbolFromSymbolTable can be qualified + let accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTable(resolvedImportedSymbol.exports) : undefined; + if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) { + return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports); + } + } + } + }); + } + + if (symbol) { + return forEachSymbolTableInScope(enclosingDeclaration, getAccessibleSymbolChainFromSymbolTable); + } + } + + function needsQualification(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) { + let qualify = false; + forEachSymbolTableInScope(enclosingDeclaration, symbolTable => { + // If symbol of this name is not available in the symbol table we are ok + if (!hasProperty(symbolTable, symbol.name)) { + // Continue to the next symbol table + return false; + } + // If the symbol with this name is present it should refer to the symbol + let symbolFromSymbolTable = symbolTable[symbol.name]; + if (symbolFromSymbolTable === symbol) { + // No need to qualify + return true; + } + + // Qualify if the symbol from symbol table has same meaning as expected + symbolFromSymbolTable = (symbolFromSymbolTable.flags & SymbolFlags.Alias) ? resolveAlias(symbolFromSymbolTable) : symbolFromSymbolTable; + if (symbolFromSymbolTable.flags & meaning) { + qualify = true; + return true; + } + + // Continue to the next symbol table + return false; + }); + + return qualify; + } + + function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult { + if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) { + let initialSymbol = symbol; + let meaningToLook = meaning; + while (symbol) { + // Symbol is accessible if it by itself is accessible + let accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook, /*useOnlyExternalAliasing*/ false); + if (accessibleSymbolChain) { + let hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0]); + if (!hasAccessibleDeclarations) { + return { + accessibility: SymbolAccessibility.NotAccessible, + errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), + errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined, + }; + } + return hasAccessibleDeclarations; + } + + // If we haven't got the accessible symbol, it doesn't mean the symbol is actually inaccessible. + // It could be a qualified symbol and hence verify the path + // e.g.: + // module m { + // export class c { + // } + // } + // let x: typeof m.c + // In the above example when we start with checking if typeof m.c symbol is accessible, + // we are going to see if c can be accessed in scope directly. + // But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible + // It is accessible if the parent m is accessible because then m.c can be accessed through qualification + meaningToLook = getQualifiedLeftMeaning(meaning); + symbol = getParentOfSymbol(symbol); + } + + // This could be a symbol that is not exported in the external module + // or it could be a symbol from different external module that is not aliased and hence cannot be named + let symbolExternalModule = forEach(initialSymbol.declarations, getExternalModuleContainer); + if (symbolExternalModule) { + let enclosingExternalModule = getExternalModuleContainer(enclosingDeclaration); + if (symbolExternalModule !== enclosingExternalModule) { + // name from different external module that is not visible + return { + accessibility: SymbolAccessibility.CannotBeNamed, + errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), + errorModuleName: symbolToString(symbolExternalModule) + }; + } + } + + // Just a local name that is not accessible + return { + accessibility: SymbolAccessibility.NotAccessible, + errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), + }; + } + + return { accessibility: SymbolAccessibility.Accessible }; + + function getExternalModuleContainer(declaration: Node) { + for (; declaration; declaration = declaration.parent) { + if (hasExternalModuleSymbol(declaration)) { + return getSymbolOfNode(declaration); + } + } + } + } + + function hasExternalModuleSymbol(declaration: Node) { + return (declaration.kind === SyntaxKind.ModuleDeclaration && (declaration).name.kind === SyntaxKind.StringLiteral) || + (declaration.kind === SyntaxKind.SourceFile && isExternalModule(declaration)); + } + + function hasVisibleDeclarations(symbol: Symbol): SymbolVisibilityResult { + let aliasesToMakeVisible: AnyImportSyntax[]; + if (forEach(symbol.declarations, declaration => !getIsDeclarationVisible(declaration))) { + return undefined; + } + return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible }; + + function getIsDeclarationVisible(declaration: Declaration) { + if (!isDeclarationVisible(declaration)) { + // Mark the unexported alias as visible if its parent is visible + // because these kind of aliases can be used to name types in declaration file + + var anyImportSyntax = getAnyImportSyntax(declaration); + if (anyImportSyntax && + !(anyImportSyntax.flags & NodeFlags.Export) && // import clause without export + isDeclarationVisible(anyImportSyntax.parent)) { + getNodeLinks(declaration).isVisible = true; + if (aliasesToMakeVisible) { + if (!contains(aliasesToMakeVisible, anyImportSyntax)) { + aliasesToMakeVisible.push(anyImportSyntax); + } + } + else { + aliasesToMakeVisible = [anyImportSyntax]; + } + return true; + } + + // Declaration is not visible + return false; + } + + return true; + } + } + + function isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult { + // get symbol of the first identifier of the entityName + let meaning: SymbolFlags; + if (entityName.parent.kind === SyntaxKind.TypeQuery) { + // Typeof value + meaning = SymbolFlags.Value | SymbolFlags.ExportValue; + } + else if (entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccessExpression || + entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration) { + // Left identifier from type reference or TypeAlias + // Entity name of the import declaration + meaning = SymbolFlags.Namespace; + } + else { + // Type Reference or TypeAlias entity = Identifier + meaning = SymbolFlags.Type; + } + + let firstIdentifier = getFirstIdentifier(entityName); + let symbol = resolveName(enclosingDeclaration, (firstIdentifier).text, meaning, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined); + + // Verify if the symbol is accessible + return (symbol && hasVisibleDeclarations(symbol)) || { + accessibility: SymbolAccessibility.NotAccessible, + errorSymbolName: getTextOfNode(firstIdentifier), + errorNode: firstIdentifier + }; + } + + function writeKeyword(writer: SymbolWriter, kind: SyntaxKind) { + writer.writeKeyword(tokenToString(kind)); + } + + function writePunctuation(writer: SymbolWriter, kind: SyntaxKind) { + writer.writePunctuation(tokenToString(kind)); + } + + function writeSpace(writer: SymbolWriter) { + writer.writeSpace(" "); + } + + function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string { + let writer = getSingleLineStringWriter(); + getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning); + + let result = writer.string(); + releaseStringWriter(writer); + + return result; + } + + function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { + let writer = getSingleLineStringWriter(); + getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); + + let result = writer.string(); + releaseStringWriter(writer); + + let maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100; + if (maxLength && result.length >= maxLength) { + result = result.substr(0, maxLength - "...".length) + "..."; + } + + return result; + } + + function getTypeAliasForTypeLiteral(type: Type): Symbol { + if (type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral) { + let node = type.symbol.declarations[0].parent; + while (node.kind === SyntaxKind.ParenthesizedType) { + node = node.parent; + } + if (node.kind === SyntaxKind.TypeAliasDeclaration) { + return getSymbolOfNode(node); + } + } + return undefined; + } + + // This is for caching the result of getSymbolDisplayBuilder. Do not access directly. + let _displayBuilder: SymbolDisplayBuilder; + function getSymbolDisplayBuilder(): SymbolDisplayBuilder { + /** + * Writes only the name of the symbol out to the writer. Uses the original source text + * for the name of the symbol if it is available to match how the user inputted the name. + */ + function appendSymbolNameOnly(symbol: Symbol, writer: SymbolWriter): void { + if (symbol.declarations && symbol.declarations.length > 0) { + let declaration = symbol.declarations[0]; + if (declaration.name) { + writer.writeSymbol(declarationNameToString(declaration.name), symbol); + return; + } + } + + writer.writeSymbol(symbol.name, symbol); + } + + /** + * Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope + * Meaning needs to be specified if the enclosing declaration is given + */ + function buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags, typeFlags?: TypeFormatFlags): void { + let parentSymbol: Symbol; + function appendParentTypeArgumentsAndSymbolName(symbol: Symbol): void { + if (parentSymbol) { + // Write type arguments of instantiated class/interface here + if (flags & SymbolFormatFlags.WriteTypeParametersOrArguments) { + if (symbol.flags & SymbolFlags.Instantiated) { + buildDisplayForTypeArgumentsAndDelimiters(getTypeParametersOfClassOrInterface(parentSymbol), + (symbol).mapper, writer, enclosingDeclaration); + } + else { + buildTypeParameterDisplayFromSymbol(parentSymbol, writer, enclosingDeclaration); + } + } + writePunctuation(writer, SyntaxKind.DotToken); + } + parentSymbol = symbol; + appendSymbolNameOnly(symbol, writer); + } + + // Let the writer know we just wrote out a symbol. The declaration emitter writer uses + // this to determine if an import it has previously seen (and not written out) needs + // to be written to the file once the walk of the tree is complete. + // + // NOTE(cyrusn): This approach feels somewhat unfortunate. A simple pass over the tree + // up front (for example, during checking) could determine if we need to emit the imports + // and we could then access that data during declaration emit. + writer.trackSymbol(symbol, enclosingDeclaration, meaning); + function walkSymbol(symbol: Symbol, meaning: SymbolFlags): void { + if (symbol) { + let accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, !!(flags & SymbolFormatFlags.UseOnlyExternalAliasing)); + + if (!accessibleSymbolChain || + needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) { + + // Go up and add our parent. + walkSymbol( + getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol), + getQualifiedLeftMeaning(meaning)); + } + + if (accessibleSymbolChain) { + for (let accessibleSymbol of accessibleSymbolChain) { + appendParentTypeArgumentsAndSymbolName(accessibleSymbol); + } + } + else { + // If we didn't find accessible symbol chain for this symbol, break if this is external module + if (!parentSymbol && ts.forEach(symbol.declarations, hasExternalModuleSymbol)) { + return; + } + + // if this is anonymous type break + if (symbol.flags & SymbolFlags.TypeLiteral || symbol.flags & SymbolFlags.ObjectLiteral) { + return; + } + + appendParentTypeArgumentsAndSymbolName(symbol); + } + } + } + + // Get qualified name if the symbol is not a type parameter + // and there is an enclosing declaration or we specifically + // asked for it + let isTypeParameter = symbol.flags & SymbolFlags.TypeParameter; + let typeFormatFlag = TypeFormatFlags.UseFullyQualifiedType & typeFlags; + if (!isTypeParameter && (enclosingDeclaration || typeFormatFlag)) { + walkSymbol(symbol, meaning); + return; + } + + return appendParentTypeArgumentsAndSymbolName(symbol); + } + + function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, typeStack?: Type[]) { + let globalFlagsToPass = globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike; + return writeType(type, globalFlags); + + function writeType(type: Type, flags: TypeFormatFlags) { + // Write undefined/null type as any + if (type.flags & TypeFlags.Intrinsic) { + // Special handling for unknown / resolving types, they should show up as any and not unknown or __resolving + writer.writeKeyword(!(globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike) && + (type.flags & TypeFlags.Any) ? "any" : (type).intrinsicName); + } + else if (type.flags & TypeFlags.Reference) { + writeTypeReference(type, flags); + } + else if (type.flags & (TypeFlags.Class | TypeFlags.Interface | TypeFlags.Enum | TypeFlags.TypeParameter)) { + // The specified symbol flags need to be reinterpreted as type flags + buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags); + } + else if (type.flags & TypeFlags.Tuple) { + writeTupleType(type); + } + else if (type.flags & TypeFlags.Union) { + writeUnionType(type, flags); + } + else if (type.flags & TypeFlags.Anonymous) { + writeAnonymousType(type, flags); + } + else if (type.flags & TypeFlags.StringLiteral) { + writer.writeStringLiteral((type).text); + } + else { + // Should never get here + // { ... } + writePunctuation(writer, SyntaxKind.OpenBraceToken); + writeSpace(writer); + writePunctuation(writer, SyntaxKind.DotDotDotToken); + writeSpace(writer); + writePunctuation(writer, SyntaxKind.CloseBraceToken); + } + } + + function writeTypeList(types: Type[], union: boolean) { + for (let i = 0; i < types.length; i++) { + if (i > 0) { + if (union) { + writeSpace(writer); + } + writePunctuation(writer, union ? SyntaxKind.BarToken : SyntaxKind.CommaToken); + writeSpace(writer); + } + writeType(types[i], union ? TypeFormatFlags.InElementType : TypeFormatFlags.None); + } + } + + function writeTypeReference(type: TypeReference, flags: TypeFormatFlags) { + if (type.target === globalArrayType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) { + writeType(type.typeArguments[0], TypeFormatFlags.InElementType); + writePunctuation(writer, SyntaxKind.OpenBracketToken); + writePunctuation(writer, SyntaxKind.CloseBracketToken); + } + else { + buildSymbolDisplay(type.target.symbol, writer, enclosingDeclaration, SymbolFlags.Type); + writePunctuation(writer, SyntaxKind.LessThanToken); + writeTypeList(type.typeArguments, /*union*/ false); + writePunctuation(writer, SyntaxKind.GreaterThanToken); + } + } + + function writeTupleType(type: TupleType) { + writePunctuation(writer, SyntaxKind.OpenBracketToken); + writeTypeList(type.elementTypes, /*union*/ false); + writePunctuation(writer, SyntaxKind.CloseBracketToken); + } + + function writeUnionType(type: UnionType, flags: TypeFormatFlags) { + if (flags & TypeFormatFlags.InElementType) { + writePunctuation(writer, SyntaxKind.OpenParenToken); + } + writeTypeList(type.types, /*union*/ true); + if (flags & TypeFormatFlags.InElementType) { + writePunctuation(writer, SyntaxKind.CloseParenToken); + } + } + + function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) { + // Always use 'typeof T' for type of class, enum, and module objects + if (type.symbol && type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { + writeTypeofSymbol(type, flags); + } + // Use 'typeof T' for types of functions and methods that circularly reference themselves + else if (shouldWriteTypeOfFunctionSymbol()) { + writeTypeofSymbol(type, flags); + } + else if (typeStack && contains(typeStack, type)) { + // If type is an anonymous type literal in a type alias declaration, use type alias name + let typeAlias = getTypeAliasForTypeLiteral(type); + if (typeAlias) { + // The specified symbol flags need to be reinterpreted as type flags + buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags); + } + else { + // Recursive usage, use any + writeKeyword(writer, SyntaxKind.AnyKeyword); + } + } + else { + if (!typeStack) { + typeStack = []; + } + typeStack.push(type); + writeLiteralType(type, flags); + typeStack.pop(); + } + + function shouldWriteTypeOfFunctionSymbol() { + if (type.symbol) { + let isStaticMethodSymbol = !!(type.symbol.flags & SymbolFlags.Method && // typeof static method + ts.forEach(type.symbol.declarations, declaration => declaration.flags & NodeFlags.Static)); + let isNonLocalFunctionSymbol = !!(type.symbol.flags & SymbolFlags.Function) && + (type.symbol.parent || // is exported function symbol + ts.forEach(type.symbol.declarations, declaration => + declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock)); + + if (isStaticMethodSymbol || isNonLocalFunctionSymbol) { + // typeof is allowed only for static/non local functions + return !!(flags & TypeFormatFlags.UseTypeOfFunction) || // use typeof if format flags specify it + (typeStack && contains(typeStack, type)); // it is type of the symbol uses itself recursively + } + } + } + } + + function writeTypeofSymbol(type: ObjectType, typeFormatFlags?: TypeFormatFlags) { + writeKeyword(writer, SyntaxKind.TypeOfKeyword); + writeSpace(writer); + buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value, SymbolFormatFlags.None, typeFormatFlags); + } + + function getIndexerParameterName(type: ObjectType, indexKind: IndexKind, fallbackName: string): string { + let declaration = getIndexDeclarationOfSymbol(type.symbol, indexKind); + if (!declaration) { + // declaration might not be found if indexer was added from the contextual type. + // in this case use fallback name + return fallbackName; + } + Debug.assert(declaration.parameters.length !== 0); + return declarationNameToString(declaration.parameters[0].name); + } + + function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) { + let resolved = resolveObjectOrUnionTypeMembers(type); + if (!resolved.properties.length && !resolved.stringIndexType && !resolved.numberIndexType) { + if (!resolved.callSignatures.length && !resolved.constructSignatures.length) { + writePunctuation(writer, SyntaxKind.OpenBraceToken); + writePunctuation(writer, SyntaxKind.CloseBraceToken); + return; + } + + if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { + if (flags & TypeFormatFlags.InElementType) { + writePunctuation(writer, SyntaxKind.OpenParenToken); + } + buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, typeStack); + if (flags & TypeFormatFlags.InElementType) { + writePunctuation(writer, SyntaxKind.CloseParenToken); + } + return; + } + if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { + if (flags & TypeFormatFlags.InElementType) { + writePunctuation(writer, SyntaxKind.OpenParenToken); + } + writeKeyword(writer, SyntaxKind.NewKeyword); + writeSpace(writer); + buildSignatureDisplay(resolved.constructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, typeStack); + if (flags & TypeFormatFlags.InElementType) { + writePunctuation(writer, SyntaxKind.CloseParenToken); + } + return; + } + } + + writePunctuation(writer, SyntaxKind.OpenBraceToken); + writer.writeLine(); + writer.increaseIndent(); + for (let signature of resolved.callSignatures) { + buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack); + writePunctuation(writer, SyntaxKind.SemicolonToken); + writer.writeLine(); + } + for (let signature of resolved.constructSignatures) { + writeKeyword(writer, SyntaxKind.NewKeyword); + writeSpace(writer); + + buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack); + writePunctuation(writer, SyntaxKind.SemicolonToken); + writer.writeLine(); + } + if (resolved.stringIndexType) { + // [x: string]: + writePunctuation(writer, SyntaxKind.OpenBracketToken); + writer.writeParameter(getIndexerParameterName(resolved, IndexKind.String, /*fallbackName*/"x")); + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); + writeKeyword(writer, SyntaxKind.StringKeyword); + writePunctuation(writer, SyntaxKind.CloseBracketToken); + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); + writeType(resolved.stringIndexType, TypeFormatFlags.None); + writePunctuation(writer, SyntaxKind.SemicolonToken); + writer.writeLine(); + } + if (resolved.numberIndexType) { + // [x: number]: + writePunctuation(writer, SyntaxKind.OpenBracketToken); + writer.writeParameter(getIndexerParameterName(resolved, IndexKind.Number, /*fallbackName*/"x")); + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); + writeKeyword(writer, SyntaxKind.NumberKeyword); + writePunctuation(writer, SyntaxKind.CloseBracketToken); + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); + writeType(resolved.numberIndexType, TypeFormatFlags.None); + writePunctuation(writer, SyntaxKind.SemicolonToken); + writer.writeLine(); + } + for (let p of resolved.properties) { + let t = getTypeOfSymbol(p); + if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(t).length) { + let signatures = getSignaturesOfType(t, SignatureKind.Call); + for (let signature of signatures) { + buildSymbolDisplay(p, writer); + if (p.flags & SymbolFlags.Optional) { + writePunctuation(writer, SyntaxKind.QuestionToken); + } + buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack); + writePunctuation(writer, SyntaxKind.SemicolonToken); + writer.writeLine(); + } + } + else { + buildSymbolDisplay(p, writer); + if (p.flags & SymbolFlags.Optional) { + writePunctuation(writer, SyntaxKind.QuestionToken); + } + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); + writeType(t, TypeFormatFlags.None); + writePunctuation(writer, SyntaxKind.SemicolonToken); + writer.writeLine(); + } + } + writer.decreaseIndent(); + writePunctuation(writer, SyntaxKind.CloseBraceToken); + } + } + + function buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags) { + let targetSymbol = getTargetSymbol(symbol); + if (targetSymbol.flags & SymbolFlags.Class || targetSymbol.flags & SymbolFlags.Interface) { + buildDisplayForTypeParametersAndDelimiters(getTypeParametersOfClassOrInterface(symbol), writer, enclosingDeclaraiton, flags); + } + } + + function buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + appendSymbolNameOnly(tp.symbol, writer); + let constraint = getConstraintOfTypeParameter(tp); + if (constraint) { + writeSpace(writer); + writeKeyword(writer, SyntaxKind.ExtendsKeyword); + writeSpace(writer); + buildTypeDisplay(constraint, writer, enclosingDeclaration, flags, typeStack); + } + } + + function buildParameterDisplay(p: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + if (hasDotDotDotToken(p.valueDeclaration)) { + writePunctuation(writer, SyntaxKind.DotDotDotToken); + } + appendSymbolNameOnly(p, writer); + if (hasQuestionToken(p.valueDeclaration) || (p.valueDeclaration).initializer) { + writePunctuation(writer, SyntaxKind.QuestionToken); + } + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); + + buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, typeStack); + } + + function buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + if (typeParameters && typeParameters.length) { + writePunctuation(writer, SyntaxKind.LessThanToken); + for (let i = 0; i < typeParameters.length; i++) { + if (i > 0) { + writePunctuation(writer, SyntaxKind.CommaToken); + writeSpace(writer); + } + buildTypeParameterDisplay(typeParameters[i], writer, enclosingDeclaration, flags, typeStack); + } + writePunctuation(writer, SyntaxKind.GreaterThanToken); + } + } + + function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + if (typeParameters && typeParameters.length) { + writePunctuation(writer, SyntaxKind.LessThanToken); + for (let i = 0; i < typeParameters.length; i++) { + if (i > 0) { + writePunctuation(writer, SyntaxKind.CommaToken); + writeSpace(writer); + } + buildTypeDisplay(mapper(typeParameters[i]), writer, enclosingDeclaration, TypeFormatFlags.None); + } + writePunctuation(writer, SyntaxKind.GreaterThanToken); + } + } + + function buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + writePunctuation(writer, SyntaxKind.OpenParenToken); + for (let i = 0; i < parameters.length; i++) { + if (i > 0) { + writePunctuation(writer, SyntaxKind.CommaToken); + writeSpace(writer); + } + buildParameterDisplay(parameters[i], writer, enclosingDeclaration, flags, typeStack); + } + writePunctuation(writer, SyntaxKind.CloseParenToken); + } + + function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + if (flags & TypeFormatFlags.WriteArrowStyleSignature) { + writeSpace(writer); + writePunctuation(writer, SyntaxKind.EqualsGreaterThanToken); + } + else { + writePunctuation(writer, SyntaxKind.ColonToken); + } + writeSpace(writer); + buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags, typeStack); + } + + function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { + if (signature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature)) { + // Instantiated signature, write type arguments instead + // This is achieved by passing in the mapper separately + buildDisplayForTypeArgumentsAndDelimiters(signature.target.typeParameters, signature.mapper, writer, enclosingDeclaration); + } + else { + buildDisplayForTypeParametersAndDelimiters(signature.typeParameters, writer, enclosingDeclaration, flags, typeStack); + } + + buildDisplayForParametersAndDelimiters(signature.parameters, writer, enclosingDeclaration, flags, typeStack); + buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, typeStack); + } + + return _displayBuilder || (_displayBuilder = { + symbolToString: symbolToString, + typeToString: typeToString, + buildSymbolDisplay: buildSymbolDisplay, + buildTypeDisplay: buildTypeDisplay, + buildTypeParameterDisplay: buildTypeParameterDisplay, + buildParameterDisplay: buildParameterDisplay, + buildDisplayForParametersAndDelimiters: buildDisplayForParametersAndDelimiters, + buildDisplayForTypeParametersAndDelimiters: buildDisplayForTypeParametersAndDelimiters, + buildDisplayForTypeArgumentsAndDelimiters: buildDisplayForTypeArgumentsAndDelimiters, + buildTypeParameterDisplayFromSymbol: buildTypeParameterDisplayFromSymbol, + buildSignatureDisplay: buildSignatureDisplay, + buildReturnTypeDisplay: buildReturnTypeDisplay + }); + } + + function isDeclarationVisible(node: Declaration): boolean { + function getContainingExternalModule(node: Node) { + for (; node; node = node.parent) { + if (node.kind === SyntaxKind.ModuleDeclaration) { + if ((node).name.kind === SyntaxKind.StringLiteral) { + return node; + } + } + else if (node.kind === SyntaxKind.SourceFile) { + return isExternalModule(node) ? node : undefined; + } + } + Debug.fail("getContainingModule cant reach here"); + } + + function isUsedInExportAssignment(node: Node) { + // Get source File and see if it is external module and has export assigned symbol + let externalModule = getContainingExternalModule(node); + let exportAssignmentSymbol: Symbol; + let resolvedExportSymbol: Symbol; + if (externalModule) { + // This is export assigned symbol node + let externalModuleSymbol = getSymbolOfNode(externalModule); + exportAssignmentSymbol = getExportAssignmentSymbol(externalModuleSymbol); + let symbolOfNode = getSymbolOfNode(node); + if (isSymbolUsedInExportAssignment(symbolOfNode)) { + return true; + } + + // if symbolOfNode is alias declaration, resolve the symbol declaration and check + if (symbolOfNode.flags & SymbolFlags.Alias) { + return isSymbolUsedInExportAssignment(resolveAlias(symbolOfNode)); + } + } + + // Check if the symbol is used in export assignment + function isSymbolUsedInExportAssignment(symbol: Symbol) { + if (exportAssignmentSymbol === symbol) { + return true; + } + + if (exportAssignmentSymbol && !!(exportAssignmentSymbol.flags & SymbolFlags.Alias)) { + // if export assigned symbol is alias declaration, resolve the alias + resolvedExportSymbol = resolvedExportSymbol || resolveAlias(exportAssignmentSymbol); + if (resolvedExportSymbol === symbol) { + return true; + } + + // Container of resolvedExportSymbol is visible + return forEach(resolvedExportSymbol.declarations, (current: Node) => { + while (current) { + if (current === node) { + return true; + } + current = current.parent; + } + }); + } + } + } + + function determineIfDeclarationIsVisible() { + switch (node.kind) { + case SyntaxKind.BindingElement: + return isDeclarationVisible(node.parent.parent); + case SyntaxKind.VariableDeclaration: + if (isBindingPattern(node.name) && + !(node.name).elements.length) { + // If the binding pattern is empty, this variable declaration is not visible + return false; + } + // Otherwise fall through + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + let parent = getDeclarationContainer(node); + // If the node is not exported or it is not ambient module element (except import declaration) + if (!(getCombinedNodeFlags(node) & NodeFlags.Export) && + !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && isInAmbientContext(parent))) { + return isGlobalSourceFile(parent); + } + // Exported members/ambient module elements (exception import declaration) are visible if parent is visible + return isDeclarationVisible(parent); + + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + if (node.flags & (NodeFlags.Private | NodeFlags.Protected)) { + // Private/protected properties/methods are not visible + return false; + } + // Public properties/methods are visible if its parents are visible, so let it fall into next case statement + + case SyntaxKind.Constructor: + case SyntaxKind.ConstructSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.Parameter: + case SyntaxKind.ModuleBlock: + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.TypeLiteral: + case SyntaxKind.TypeReference: + case SyntaxKind.ArrayType: + case SyntaxKind.TupleType: + case SyntaxKind.UnionType: + case SyntaxKind.ParenthesizedType: + return isDeclarationVisible(node.parent); + + // Default binding, import specifier and namespace import is visible + // only on demand so by default it is not visible + case SyntaxKind.ImportClause: + case SyntaxKind.NamespaceImport: + case SyntaxKind.ImportSpecifier: + return false; + + // Type parameters are always visible + case SyntaxKind.TypeParameter: + // Source file is always visible + case SyntaxKind.SourceFile: + return true; + + // Export assignements do not create name bindings outside the module + case SyntaxKind.ExportAssignment: + return false; + + default: + Debug.fail("isDeclarationVisible unknown: SyntaxKind: " + node.kind); + } + } + + if (node) { + let links = getNodeLinks(node); + if (links.isVisible === undefined) { + links.isVisible = !!determineIfDeclarationIsVisible(); + } + return links.isVisible; + } + } + + function collectLinkedAliases(node: Identifier): Node[]{ + var exportSymbol: Symbol; + if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) { + exportSymbol = resolveName(node.parent, node.text, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, Diagnostics.Cannot_find_name_0, node); + } + else if (node.parent.kind === SyntaxKind.ExportSpecifier) { + exportSymbol = getTargetOfExportSpecifier(node.parent); + } + var result: Node[] = []; + if (exportSymbol) { + buildVisibleNodeList(exportSymbol.declarations); + } + return result; + + function buildVisibleNodeList(declarations: Declaration[]) { + forEach(declarations, declaration => { + getNodeLinks(declaration).isVisible = true; + var resultNode = getAnyImportSyntax(declaration) || declaration; + if (!contains(result, resultNode)) { + result.push(resultNode); + } + + if (isInternalModuleImportEqualsDeclaration(declaration)) { + // Add the referenced top container visible + var internalModuleReference = (declaration).moduleReference; + var firstIdentifier = getFirstIdentifier(internalModuleReference); + var importSymbol = resolveName(declaration, firstIdentifier.text, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + Diagnostics.Cannot_find_name_0, firstIdentifier); + buildVisibleNodeList(importSymbol.declarations); + } + }); + } + } + + function getRootDeclaration(node: Node): Node { + while (node.kind === SyntaxKind.BindingElement) { + node = node.parent.parent; + } + return node; + } + + function getDeclarationContainer(node: Node): Node { + node = getRootDeclaration(node); + + // Parent chain: + // VaribleDeclaration -> VariableDeclarationList -> VariableStatement -> 'Declaration Container' + return node.kind === SyntaxKind.VariableDeclaration ? node.parent.parent.parent : node.parent; + } + + function getTypeOfPrototypeProperty(prototype: Symbol): Type { + // TypeScript 1.0 spec (April 2014): 8.4 + // Every class automatically contains a static property member named 'prototype', + // the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter. + // It is an error to explicitly declare a static property member with the name 'prototype'. + let classType = getDeclaredTypeOfSymbol(prototype.parent); + return classType.typeParameters ? createTypeReference(classType, map(classType.typeParameters, _ => anyType)) : classType; + } + + // Return the type of the given property in the given type, or undefined if no such property exists + function getTypeOfPropertyOfType(type: Type, name: string): Type { + let prop = getPropertyOfType(type, name); + return prop ? getTypeOfSymbol(prop) : undefined; + } + + // Return the inferred type for a binding element + function getTypeForBindingElement(declaration: BindingElement): Type { + let pattern = declaration.parent; + let parentType = getTypeForVariableLikeDeclaration(pattern.parent); + // If parent has the unknown (error) type, then so does this binding element + if (parentType === unknownType) { + return unknownType; + } + // If no type was specified or inferred for parent, or if the specified or inferred type is any, + // infer from the initializer of the binding element if one is present. Otherwise, go with the + // undefined or any type of the parent. + if (!parentType || parentType === anyType) { + if (declaration.initializer) { + return checkExpressionCached(declaration.initializer); + } + return parentType; + } + + let type: Type; + if (pattern.kind === SyntaxKind.ObjectBindingPattern) { + // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) + let name = declaration.propertyName || declaration.name; + // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature, + // or otherwise the type of the string index signature. + type = getTypeOfPropertyOfType(parentType, name.text) || + isNumericLiteralName(name.text) && getIndexTypeOfType(parentType, IndexKind.Number) || + getIndexTypeOfType(parentType, IndexKind.String); + if (!type) { + error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name)); + return unknownType; + } + } + else { + // This elementType will be used if the specific property corresponding to this index is not + // present (aka the tuple element property). This call also checks that the parentType is in + // fact an iterable or array (depending on target language). + let elementType = checkIteratedTypeOrElementType(parentType, pattern, /*allowStringInput*/ false); + if (!declaration.dotDotDotToken) { + if (elementType.flags & TypeFlags.Any) { + return elementType; + } + + // Use specific property type when parent is a tuple or numeric index type when parent is an array + let propName = "" + indexOf(pattern.elements, declaration); + type = isTupleLikeType(parentType) + ? getTypeOfPropertyOfType(parentType, propName) + : elementType; + if (!type) { + if (isTupleType(parentType)) { + error(declaration, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(parentType), (parentType).elementTypes.length, pattern.elements.length); + } + else { + error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName); + } + return unknownType; + } + } + else { + // Rest element has an array type with the same element type as the parent type + type = createArrayType(elementType); + } + } + return type; + } + + // Return the inferred type for a variable, parameter, or property declaration + function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type { + // A variable declared in a for..in statement is always of type any + if (declaration.parent.parent.kind === SyntaxKind.ForInStatement) { + return anyType; + } + if (declaration.parent.parent.kind === SyntaxKind.ForOfStatement) { + // checkRightHandSideOfForOf will return undefined if the for-of expression type was + // missing properties/signatures required to get its iteratedType (like + // [Symbol.iterator] or next). This may be because we accessed properties from anyType, + // or it may have led to an error inside getIteratedType. + return checkRightHandSideOfForOf((declaration.parent.parent).expression) || anyType; + } + if (isBindingPattern(declaration.parent)) { + return getTypeForBindingElement(declaration); + } + // Use type from type annotation if one is present + if (declaration.type) { + return getTypeFromTypeNode(declaration.type); + } + if (declaration.kind === SyntaxKind.Parameter) { + let func = declaration.parent; + // For a parameter of a set accessor, use the type of the get accessor if one is present + if (func.kind === SyntaxKind.SetAccessor && !hasDynamicName(func)) { + let getter = getDeclarationOfKind(declaration.parent.symbol, SyntaxKind.GetAccessor); + if (getter) { + return getReturnTypeOfSignature(getSignatureFromDeclaration(getter)); + } + } + // Use contextual parameter type if one is available + let type = getContextuallyTypedParameterType(declaration); + if (type) { + return type; + } + } + // Use the type of the initializer expression if one is present + if (declaration.initializer) { + return checkExpressionCached(declaration.initializer); + } + // If it is a short-hand property assignment, use the type of the identifier + if (declaration.kind === SyntaxKind.ShorthandPropertyAssignment) { + return checkIdentifier(declaration.name); + } + // No type specified and nothing can be inferred + return undefined; + } + + // Return the type implied by a binding pattern element. This is the type of the initializer of the element if + // one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding + // pattern. Otherwise, it is the type any. + function getTypeFromBindingElement(element: BindingElement): Type { + if (element.initializer) { + return getWidenedType(checkExpressionCached(element.initializer)); + } + if (isBindingPattern(element.name)) { + return getTypeFromBindingPattern(element.name); + } + return anyType; + } + + // Return the type implied by an object binding pattern + function getTypeFromObjectBindingPattern(pattern: BindingPattern): Type { + let members: SymbolTable = {}; + forEach(pattern.elements, e => { + let flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0); + let name = e.propertyName || e.name; + let symbol = createSymbol(flags, name.text); + symbol.type = getTypeFromBindingElement(e); + members[symbol.name] = symbol; + }); + return createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined); + } + + // Return the type implied by an array binding pattern + function getTypeFromArrayBindingPattern(pattern: BindingPattern): Type { + let hasSpreadElement: boolean = false; + let elementTypes: Type[] = []; + forEach(pattern.elements, e => { + elementTypes.push(e.kind === SyntaxKind.OmittedExpression || e.dotDotDotToken ? anyType : getTypeFromBindingElement(e)); + if (e.dotDotDotToken) { + hasSpreadElement = true; + } + }); + if (!elementTypes.length) { + return languageVersion >= ScriptTarget.ES6 ? createIterableType(anyType) : anyArrayType; + } + else if (hasSpreadElement) { + let unionOfElements = getUnionType(elementTypes); + return languageVersion >= ScriptTarget.ES6 ? createIterableType(unionOfElements) : createArrayType(unionOfElements); + } + + // If the pattern has at least one element, and no rest element, then it should imply a tuple type. + return createTupleType(elementTypes); + } + + // Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself + // and without regard to its context (i.e. without regard any type annotation or initializer associated with the + // declaration in which the binding pattern is contained). For example, the implied type of [x, y] is [any, any] + // and the implied type of { x, y: z = 1 } is { x: any; y: number; }. The type implied by a binding pattern is + // used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring + // parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of + // the parameter. + function getTypeFromBindingPattern(pattern: BindingPattern): Type { + return pattern.kind === SyntaxKind.ObjectBindingPattern + ? getTypeFromObjectBindingPattern(pattern) + : getTypeFromArrayBindingPattern(pattern); + } + + // Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type + // specified in a type annotation or inferred from an initializer. However, in the case of a destructuring declaration it + // is a bit more involved. For example: + // + // var [x, s = ""] = [1, "one"]; + // + // Here, the array literal [1, "one"] is contextually typed by the type [any, string], which is the implied type of the + // binding pattern [x, s = ""]. Because the contextual type is a tuple type, the resulting type of [1, "one"] is the + // tuple type [number, string]. Thus, the type inferred for 'x' is number and the type inferred for 's' is string. + function getWidenedTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, reportErrors?: boolean): Type { + let type = getTypeForVariableLikeDeclaration(declaration); + if (type) { + if (reportErrors) { + reportErrorsFromWidening(declaration, type); + } + // During a normal type check we'll never get to here with a property assignment (the check of the containing + // object literal uses a different path). We exclude widening only so that language services and type verification + // tools see the actual type. + return declaration.kind !== SyntaxKind.PropertyAssignment ? getWidenedType(type) : type; + } + // If no type was specified and nothing could be inferred, and if the declaration specifies a binding pattern, use + // the type implied by the binding pattern + if (isBindingPattern(declaration.name)) { + return getTypeFromBindingPattern(declaration.name); + } + // Rest parameters default to type any[], other parameters default to type any + type = declaration.dotDotDotToken ? anyArrayType : anyType; + // Report implicit any errors unless this is a private property within an ambient declaration + if (reportErrors && compilerOptions.noImplicitAny) { + let root = getRootDeclaration(declaration); + if (!isPrivateWithinAmbient(root) && !(root.kind === SyntaxKind.Parameter && isPrivateWithinAmbient(root.parent))) { + reportImplicitAnyError(declaration, type); + } + } + return type; + } + + function getTypeOfVariableOrParameterOrProperty(symbol: Symbol): Type { + let links = getSymbolLinks(symbol); + if (!links.type) { + // Handle prototype property + if (symbol.flags & SymbolFlags.Prototype) { + return links.type = getTypeOfPrototypeProperty(symbol); + } + // Handle catch clause variables + let declaration = symbol.valueDeclaration; + if (declaration.parent.kind === SyntaxKind.CatchClause) { + return links.type = anyType; + } + // Handle export default expressions + if (declaration.kind === SyntaxKind.ExportAssignment) { + return links.type = checkExpression((declaration).expression); + } + // Handle variable, parameter or property + links.type = resolvingType; + let type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true); + if (links.type === resolvingType) { + links.type = type; + } + } + else if (links.type === resolvingType) { + links.type = anyType; + if (compilerOptions.noImplicitAny) { + let diagnostic = (symbol.valueDeclaration).type ? + Diagnostics._0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation : + Diagnostics._0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer; + error(symbol.valueDeclaration, diagnostic, symbolToString(symbol)); + } + } + return links.type; + } + + function getSetAccessorTypeAnnotationNode(accessor: AccessorDeclaration): TypeNode { + return accessor && accessor.parameters.length > 0 && accessor.parameters[0].type; + } + + function getAnnotatedAccessorType(accessor: AccessorDeclaration): Type { + if (accessor) { + if (accessor.kind === SyntaxKind.GetAccessor) { + return accessor.type && getTypeFromTypeNode(accessor.type); + } + else { + let setterTypeAnnotation = getSetAccessorTypeAnnotationNode(accessor); + return setterTypeAnnotation && getTypeFromTypeNode(setterTypeAnnotation); + } + } + return undefined; + } + + function getTypeOfAccessors(symbol: Symbol): Type { + let links = getSymbolLinks(symbol); + checkAndStoreTypeOfAccessors(symbol, links); + return links.type; + } + + function checkAndStoreTypeOfAccessors(symbol: Symbol, links?: SymbolLinks) { + links = links || getSymbolLinks(symbol); + if (!links.type) { + links.type = resolvingType; + let getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); + let setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor); + + let type: Type; + + // First try to see if the user specified a return type on the get-accessor. + let getterReturnType = getAnnotatedAccessorType(getter); + if (getterReturnType) { + type = getterReturnType; + } + else { + // If the user didn't specify a return type, try to use the set-accessor's parameter type. + let setterParameterType = getAnnotatedAccessorType(setter); + if (setterParameterType) { + type = setterParameterType; + } + else { + // If there are no specified types, try to infer it from the body of the get accessor if it exists. + if (getter && getter.body) { + type = getReturnTypeFromBody(getter); + } + // Otherwise, fall back to 'any'. + else { + if (compilerOptions.noImplicitAny) { + error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbolToString(symbol)); + } + + type = anyType; + } + } + } + + if (links.type === resolvingType) { + links.type = type; + } + } + else if (links.type === resolvingType) { + links.type = anyType; + if (compilerOptions.noImplicitAny) { + let getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); + error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol)); + } + } + } + + function getTypeOfFuncClassEnumModule(symbol: Symbol): Type { + let links = getSymbolLinks(symbol); + if (!links.type) { + links.type = createObjectType(TypeFlags.Anonymous, symbol); + } + return links.type; + } + + function getTypeOfEnumMember(symbol: Symbol): Type { + let links = getSymbolLinks(symbol); + if (!links.type) { + links.type = getDeclaredTypeOfEnum(getParentOfSymbol(symbol)); + } + return links.type; + } + + function getTypeOfAlias(symbol: Symbol): Type { + let links = getSymbolLinks(symbol); + if (!links.type) { + links.type = getTypeOfSymbol(resolveAlias(symbol)); + } + return links.type; + } + + function getTypeOfInstantiatedSymbol(symbol: Symbol): Type { + let links = getSymbolLinks(symbol); + if (!links.type) { + links.type = instantiateType(getTypeOfSymbol(links.target), links.mapper); + } + return links.type; + } + + function getTypeOfSymbol(symbol: Symbol): Type { + if (symbol.flags & SymbolFlags.Instantiated) { + return getTypeOfInstantiatedSymbol(symbol); + } + if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { + return getTypeOfVariableOrParameterOrProperty(symbol); + } + if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { + return getTypeOfFuncClassEnumModule(symbol); + } + if (symbol.flags & SymbolFlags.EnumMember) { + return getTypeOfEnumMember(symbol); + } + if (symbol.flags & SymbolFlags.Accessor) { + return getTypeOfAccessors(symbol); + } + if (symbol.flags & SymbolFlags.Alias) { + return getTypeOfAlias(symbol); + } + return unknownType; + } + + function getTargetType(type: ObjectType): Type { + return type.flags & TypeFlags.Reference ? (type).target : type; + } + + function hasBaseType(type: InterfaceType, checkBase: InterfaceType) { + return check(type); + function check(type: InterfaceType): boolean { + let target = getTargetType(type); + return target === checkBase || forEach(getBaseTypes(target), check); + } + } + + // Return combined list of type parameters from all declarations of a class or interface. Elsewhere we check they're all + // the same, but even if they're not we still need the complete list to ensure instantiations supply type arguments + // for all type parameters. + function getTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] { + let result: TypeParameter[]; + forEach(symbol.declarations, node => { + if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration) { + let declaration = node; + if (declaration.typeParameters && declaration.typeParameters.length) { + forEach(declaration.typeParameters, node => { + let tp = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node)); + if (!result) { + result = [tp]; + } + else if (!contains(result, tp)) { + result.push(tp); + } + }); + } + } + }); + return result; + } + + function getBaseTypes(type: InterfaceType): ObjectType[]{ + let typeWithBaseTypes = type; + if (!typeWithBaseTypes.baseTypes) { + if (type.symbol.flags & SymbolFlags.Class) { + resolveBaseTypesOfClass(typeWithBaseTypes); + } + else if (type.symbol.flags & SymbolFlags.Interface) { + resolveBaseTypesOfInterface(typeWithBaseTypes); + } + else { + Debug.fail("type must be class or interface"); + } + } + + return typeWithBaseTypes.baseTypes; + } + + function resolveBaseTypesOfClass(type: InterfaceTypeWithBaseTypes): void { + type.baseTypes = []; + let declaration = getDeclarationOfKind(type.symbol, SyntaxKind.ClassDeclaration); + let baseTypeNode = getClassExtendsHeritageClauseElement(declaration); + if (baseTypeNode) { + let baseType = getTypeFromHeritageClauseElement(baseTypeNode); + if (baseType !== unknownType) { + if (getTargetType(baseType).flags & TypeFlags.Class) { + if (type !== baseType && !hasBaseType(baseType, type)) { + type.baseTypes.push(baseType); + } + else { + error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); + } + } + else { + error(baseTypeNode, Diagnostics.A_class_may_only_extend_another_class); + } + } + } + } + + function resolveBaseTypesOfInterface(type: InterfaceTypeWithBaseTypes): void { + type.baseTypes = []; + for (let declaration of type.symbol.declarations) { + if (declaration.kind === SyntaxKind.InterfaceDeclaration && getInterfaceBaseTypeNodes(declaration)) { + for (let node of getInterfaceBaseTypeNodes(declaration)) { + let baseType = getTypeFromHeritageClauseElement(node); + + if (baseType !== unknownType) { + if (getTargetType(baseType).flags & (TypeFlags.Class | TypeFlags.Interface)) { + if (type !== baseType && !hasBaseType(baseType, type)) { + type.baseTypes.push(baseType); + } + else { + error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); + } + } + else { + error(node, Diagnostics.An_interface_may_only_extend_a_class_or_another_interface); + } + } + } + } + } + } + + function getDeclaredTypeOfClassOrInterface(symbol: Symbol): InterfaceType { + let links = getSymbolLinks(symbol); + if (!links.declaredType) { + let kind = symbol.flags & SymbolFlags.Class ? TypeFlags.Class : TypeFlags.Interface; + let type = links.declaredType = createObjectType(kind, symbol); + let typeParameters = getTypeParametersOfClassOrInterface(symbol); + if (typeParameters) { + type.flags |= TypeFlags.Reference; + type.typeParameters = typeParameters; + (type).instantiations = {}; + (type).instantiations[getTypeListId(type.typeParameters)] = type; + (type).target = type; + (type).typeArguments = type.typeParameters; + } + } + return links.declaredType; + } + + function getDeclaredTypeOfTypeAlias(symbol: Symbol): Type { + let links = getSymbolLinks(symbol); + if (!links.declaredType) { + links.declaredType = resolvingType; + let declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); + let type = getTypeFromTypeNode(declaration.type); + if (links.declaredType === resolvingType) { + links.declaredType = type; + } + } + else if (links.declaredType === resolvingType) { + links.declaredType = unknownType; + let declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); + error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); + } + return links.declaredType; + } + + function getDeclaredTypeOfEnum(symbol: Symbol): Type { + let links = getSymbolLinks(symbol); + if (!links.declaredType) { + let type = createType(TypeFlags.Enum); + type.symbol = symbol; + links.declaredType = type; + } + return links.declaredType; + } + + function getDeclaredTypeOfTypeParameter(symbol: Symbol): TypeParameter { + let links = getSymbolLinks(symbol); + if (!links.declaredType) { + let type = createType(TypeFlags.TypeParameter); + type.symbol = symbol; + if (!(getDeclarationOfKind(symbol, SyntaxKind.TypeParameter)).constraint) { + type.constraint = noConstraintType; + } + links.declaredType = type; + } + return links.declaredType; + } + + function getDeclaredTypeOfAlias(symbol: Symbol): Type { + let links = getSymbolLinks(symbol); + if (!links.declaredType) { + links.declaredType = getDeclaredTypeOfSymbol(resolveAlias(symbol)); + } + return links.declaredType; + } + + function getDeclaredTypeOfSymbol(symbol: Symbol): Type { + Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0); + if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { + return getDeclaredTypeOfClassOrInterface(symbol); + } + if (symbol.flags & SymbolFlags.TypeAlias) { + return getDeclaredTypeOfTypeAlias(symbol); + } + if (symbol.flags & SymbolFlags.Enum) { + return getDeclaredTypeOfEnum(symbol); + } + if (symbol.flags & SymbolFlags.TypeParameter) { + return getDeclaredTypeOfTypeParameter(symbol); + } + if (symbol.flags & SymbolFlags.Alias) { + return getDeclaredTypeOfAlias(symbol); + } + return unknownType; + } + + function createSymbolTable(symbols: Symbol[]): SymbolTable { + let result: SymbolTable = {}; + for (let symbol of symbols) { + result[symbol.name] = symbol; + } + return result; + } + + function createInstantiatedSymbolTable(symbols: Symbol[], mapper: TypeMapper): SymbolTable { + let result: SymbolTable = {}; + for (let symbol of symbols) { + result[symbol.name] = instantiateSymbol(symbol, mapper); + } + return result; + } + + function addInheritedMembers(symbols: SymbolTable, baseSymbols: Symbol[]) { + for (let s of baseSymbols) { + if (!hasProperty(symbols, s.name)) { + symbols[s.name] = s; + } + } + } + + function addInheritedSignatures(signatures: Signature[], baseSignatures: Signature[]) { + if (baseSignatures) { + for (let signature of baseSignatures) { + signatures.push(signature); + } + } + } + + function resolveDeclaredMembers(type: InterfaceType): InterfaceTypeWithDeclaredMembers { + if (!(type).declaredProperties) { + var symbol = type.symbol; + (type).declaredProperties = getNamedMembers(symbol.members); + (type).declaredCallSignatures = getSignaturesOfSymbol(symbol.members["__call"]); + (type).declaredConstructSignatures = getSignaturesOfSymbol(symbol.members["__new"]); + (type).declaredStringIndexType = getIndexTypeOfSymbol(symbol, IndexKind.String); + (type).declaredNumberIndexType = getIndexTypeOfSymbol(symbol, IndexKind.Number); + } + return type; + } + + function resolveClassOrInterfaceMembers(type: InterfaceType): void { + let target = resolveDeclaredMembers(type); + let members = target.symbol.members; + let callSignatures = target.declaredCallSignatures; + let constructSignatures = target.declaredConstructSignatures; + let stringIndexType = target.declaredStringIndexType; + let numberIndexType = target.declaredNumberIndexType; + let baseTypes = getBaseTypes(target); + if (baseTypes.length) { + members = createSymbolTable(target.declaredProperties); + for (let baseType of baseTypes) { + addInheritedMembers(members, getPropertiesOfObjectType(baseType)); + callSignatures = concatenate(callSignatures, getSignaturesOfType(baseType, SignatureKind.Call)); + constructSignatures = concatenate(constructSignatures, getSignaturesOfType(baseType, SignatureKind.Construct)); + stringIndexType = stringIndexType || getIndexTypeOfType(baseType, IndexKind.String); + numberIndexType = numberIndexType || getIndexTypeOfType(baseType, IndexKind.Number); + } + } + setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType); + } + + function resolveTypeReferenceMembers(type: TypeReference): void { + let target = resolveDeclaredMembers(type.target); + let mapper = createTypeMapper(target.typeParameters, type.typeArguments); + let members = createInstantiatedSymbolTable(target.declaredProperties, mapper); + let callSignatures = instantiateList(target.declaredCallSignatures, mapper, instantiateSignature); + let constructSignatures = instantiateList(target.declaredConstructSignatures, mapper, instantiateSignature); + let stringIndexType = target.declaredStringIndexType ? instantiateType(target.declaredStringIndexType, mapper) : undefined; + let numberIndexType = target.declaredNumberIndexType ? instantiateType(target.declaredNumberIndexType, mapper) : undefined; + forEach(getBaseTypes(target), baseType => { + let instantiatedBaseType = instantiateType(baseType, mapper); + addInheritedMembers(members, getPropertiesOfObjectType(instantiatedBaseType)); + callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call)); + constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct)); + stringIndexType = stringIndexType || getIndexTypeOfType(instantiatedBaseType, IndexKind.String); + numberIndexType = numberIndexType || getIndexTypeOfType(instantiatedBaseType, IndexKind.Number); + }); + setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType); + } + + function createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], parameters: Symbol[], + resolvedReturnType: Type, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature { + let sig = new Signature(checker); + sig.declaration = declaration; + sig.typeParameters = typeParameters; + sig.parameters = parameters; + sig.resolvedReturnType = resolvedReturnType; + sig.minArgumentCount = minArgumentCount; + sig.hasRestParameter = hasRestParameter; + sig.hasStringLiterals = hasStringLiterals; + return sig; + } + + function cloneSignature(sig: Signature): Signature { + return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType, + sig.minArgumentCount, sig.hasRestParameter, sig.hasStringLiterals); + } + + function getDefaultConstructSignatures(classType: InterfaceType): Signature[]{ + let baseTypes = getBaseTypes(classType); + if (baseTypes.length) { + let baseType = baseTypes[0]; + let baseSignatures = getSignaturesOfType(getTypeOfSymbol(baseType.symbol), SignatureKind.Construct); + return map(baseSignatures, baseSignature => { + let signature = baseType.flags & TypeFlags.Reference ? + getSignatureInstantiation(baseSignature, (baseType).typeArguments) : cloneSignature(baseSignature); + signature.typeParameters = classType.typeParameters; + signature.resolvedReturnType = classType; + return signature; + }); + } + return [createSignature(undefined, classType.typeParameters, emptyArray, classType, 0, false, false)]; + } + + function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable { + let members: SymbolTable = {}; + for (let i = 0; i < memberTypes.length; i++) { + let symbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "" + i); + symbol.type = memberTypes[i]; + members[i] = symbol; + } + return members; + } + + function resolveTupleTypeMembers(type: TupleType) { + let arrayType = resolveObjectOrUnionTypeMembers(createArrayType(getUnionType(type.elementTypes))); + let members = createTupleTypeMemberSymbols(type.elementTypes); + addInheritedMembers(members, arrayType.properties); + setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexType, arrayType.numberIndexType); + } + + function signatureListsIdentical(s: Signature[], t: Signature[]): boolean { + if (s.length !== t.length) { + return false; + } + for (let i = 0; i < s.length; i++) { + if (!compareSignatures(s[i], t[i], /*compareReturnTypes*/ false, compareTypes)) { + return false; + } + } + return true; + } + + // If the lists of call or construct signatures in the given types are all identical except for return types, + // and if none of the signatures are generic, return a list of signatures that has substitutes a union of the + // return types of the corresponding signatures in each resulting signature. + function getUnionSignatures(types: Type[], kind: SignatureKind): Signature[] { + let signatureLists = map(types, t => getSignaturesOfType(t, kind)); + let signatures = signatureLists[0]; + for (let signature of signatures) { + if (signature.typeParameters) { + return emptyArray; + } + } + for (let i = 1; i < signatureLists.length; i++) { + if (!signatureListsIdentical(signatures, signatureLists[i])) { + return emptyArray; + } + } + let result = map(signatures, cloneSignature); + for (var i = 0; i < result.length; i++) { + let s = result[i]; + // Clear resolved return type we possibly got from cloneSignature + s.resolvedReturnType = undefined; + s.unionSignatures = map(signatureLists, signatures => signatures[i]); + } + return result; + } + + function getUnionIndexType(types: Type[], kind: IndexKind): Type { + let indexTypes: Type[] = []; + for (let type of types) { + let indexType = getIndexTypeOfType(type, kind); + if (!indexType) { + return undefined; + } + indexTypes.push(indexType); + } + return getUnionType(indexTypes); + } + + function resolveUnionTypeMembers(type: UnionType) { + // The members and properties collections are empty for union types. To get all properties of a union + // type use getPropertiesOfType (only the language service uses this). + let callSignatures = getUnionSignatures(type.types, SignatureKind.Call); + let constructSignatures = getUnionSignatures(type.types, SignatureKind.Construct); + let stringIndexType = getUnionIndexType(type.types, IndexKind.String); + let numberIndexType = getUnionIndexType(type.types, IndexKind.Number); + setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexType, numberIndexType); + } + + function resolveAnonymousTypeMembers(type: ObjectType) { + let symbol = type.symbol; + let members: SymbolTable; + let callSignatures: Signature[]; + let constructSignatures: Signature[]; + let stringIndexType: Type; + let numberIndexType: Type; + + if (symbol.flags & SymbolFlags.TypeLiteral) { + members = symbol.members; + callSignatures = getSignaturesOfSymbol(members["__call"]); + constructSignatures = getSignaturesOfSymbol(members["__new"]); + stringIndexType = getIndexTypeOfSymbol(symbol, IndexKind.String); + numberIndexType = getIndexTypeOfSymbol(symbol, IndexKind.Number); + } + else { + // Combinations of function, class, enum and module + members = emptySymbols; + callSignatures = emptyArray; + constructSignatures = emptyArray; + if (symbol.flags & SymbolFlags.HasExports) { + members = getExportsOfSymbol(symbol); + } + if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) { + callSignatures = getSignaturesOfSymbol(symbol); + } + if (symbol.flags & SymbolFlags.Class) { + let classType = getDeclaredTypeOfClassOrInterface(symbol); + constructSignatures = getSignaturesOfSymbol(symbol.members["__constructor"]); + if (!constructSignatures.length) { + constructSignatures = getDefaultConstructSignatures(classType); + } + let baseTypes = getBaseTypes(classType); + if (baseTypes.length) { + members = createSymbolTable(getNamedMembers(members)); + addInheritedMembers(members, getPropertiesOfObjectType(getTypeOfSymbol(baseTypes[0].symbol))); + } + } + stringIndexType = undefined; + numberIndexType = (symbol.flags & SymbolFlags.Enum) ? stringType : undefined; + } + setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType); + } + + function resolveObjectOrUnionTypeMembers(type: ObjectType): ResolvedType { + if (!(type).members) { + if (type.flags & (TypeFlags.Class | TypeFlags.Interface)) { + resolveClassOrInterfaceMembers(type); + } + else if (type.flags & TypeFlags.Anonymous) { + resolveAnonymousTypeMembers(type); + } + else if (type.flags & TypeFlags.Tuple) { + resolveTupleTypeMembers(type); + } + else if (type.flags & TypeFlags.Union) { + resolveUnionTypeMembers(type); + } + else { + resolveTypeReferenceMembers(type); + } + } + return type; + } + + // Return properties of an object type or an empty array for other types + function getPropertiesOfObjectType(type: Type): Symbol[] { + if (type.flags & TypeFlags.ObjectType) { + return resolveObjectOrUnionTypeMembers(type).properties; + } + return emptyArray; + } + + // If the given type is an object type and that type has a property by the given name, return + // the symbol for that property. Otherwise return undefined. + function getPropertyOfObjectType(type: Type, name: string): Symbol { + if (type.flags & TypeFlags.ObjectType) { + let resolved = resolveObjectOrUnionTypeMembers(type); + if (hasProperty(resolved.members, name)) { + let symbol = resolved.members[name]; + if (symbolIsValue(symbol)) { + return symbol; + } + } + } + } + + function getPropertiesOfUnionType(type: UnionType): Symbol[] { + let result: Symbol[] = []; + forEach(getPropertiesOfType(type.types[0]), prop => { + let unionProp = getPropertyOfUnionType(type, prop.name); + if (unionProp) { + result.push(unionProp); + } + }); + return result; + } + + function getPropertiesOfType(type: Type): Symbol[] { + type = getApparentType(type); + return type.flags & TypeFlags.Union ? getPropertiesOfUnionType(type) : getPropertiesOfObjectType(type); + } + + // For a type parameter, return the base constraint of the type parameter. For the string, number, + // boolean, and symbol primitive types, return the corresponding object types. Otherwise return the + // type itself. Note that the apparent type of a union type is the union type itself. + function getApparentType(type: Type): Type { + if (type.flags & TypeFlags.Union) { + type = getReducedTypeOfUnionType(type); + } + if (type.flags & TypeFlags.TypeParameter) { + do { + type = getConstraintOfTypeParameter(type); + } while (type && type.flags & TypeFlags.TypeParameter); + if (!type) { + type = emptyObjectType; + } + } + if (type.flags & TypeFlags.StringLike) { + type = globalStringType; + } + else if (type.flags & TypeFlags.NumberLike) { + type = globalNumberType; + } + else if (type.flags & TypeFlags.Boolean) { + type = globalBooleanType; + } + else if (type.flags & TypeFlags.ESSymbol) { + type = globalESSymbolType; + } + return type; + } + + function createUnionProperty(unionType: UnionType, name: string): Symbol { + let types = unionType.types; + let props: Symbol[]; + for (let current of types) { + let type = getApparentType(current); + if (type !== unknownType) { + let prop = getPropertyOfType(type, name); + if (!prop || getDeclarationFlagsFromSymbol(prop) & (NodeFlags.Private | NodeFlags.Protected)) { + return undefined; + } + if (!props) { + props = [prop]; + } + else { + props.push(prop); + } + } + } + let propTypes: Type[] = []; + let declarations: Declaration[] = []; + for (let prop of props) { + if (prop.declarations) { + declarations.push.apply(declarations, prop.declarations); + } + propTypes.push(getTypeOfSymbol(prop)); + } + let result = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.UnionProperty, name); + result.unionType = unionType; + result.declarations = declarations; + result.type = getUnionType(propTypes); + return result; + } + + function getPropertyOfUnionType(type: UnionType, name: string): Symbol { + let properties = type.resolvedProperties || (type.resolvedProperties = {}); + if (hasProperty(properties, name)) { + return properties[name]; + } + let property = createUnionProperty(type, name); + if (property) { + properties[name] = property; + } + return property; + } + + // Return the symbol for the property with the given name in the given type. Creates synthetic union properties when + // necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from + // Object and Function as appropriate. + function getPropertyOfType(type: Type, name: string): Symbol { + type = getApparentType(type); + if (type.flags & TypeFlags.ObjectType) { + let resolved = resolveObjectOrUnionTypeMembers(type); + if (hasProperty(resolved.members, name)) { + let symbol = resolved.members[name]; + if (symbolIsValue(symbol)) { + return symbol; + } + } + if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) { + let symbol = getPropertyOfObjectType(globalFunctionType, name); + if (symbol) { + return symbol; + } + } + return getPropertyOfObjectType(globalObjectType, name); + } + if (type.flags & TypeFlags.Union) { + return getPropertyOfUnionType(type, name); + } + return undefined; + } + + function getSignaturesOfObjectOrUnionType(type: Type, kind: SignatureKind): Signature[] { + if (type.flags & (TypeFlags.ObjectType | TypeFlags.Union)) { + let resolved = resolveObjectOrUnionTypeMembers(type); + return kind === SignatureKind.Call ? resolved.callSignatures : resolved.constructSignatures; + } + return emptyArray; + } + + // Return the signatures of the given kind in the given type. Creates synthetic union signatures when necessary and + // maps primitive types and type parameters are to their apparent types. + function getSignaturesOfType(type: Type, kind: SignatureKind): Signature[] { + return getSignaturesOfObjectOrUnionType(getApparentType(type), kind); + } + + function typeHasCallOrConstructSignatures(type: Type): boolean { + let apparentType = getApparentType(type); + if (apparentType.flags & (TypeFlags.ObjectType | TypeFlags.Union)) { + let resolved = resolveObjectOrUnionTypeMembers(type); + return resolved.callSignatures.length > 0 + || resolved.constructSignatures.length > 0; + } + return false; + } + + function getIndexTypeOfObjectOrUnionType(type: Type, kind: IndexKind): Type { + if (type.flags & (TypeFlags.ObjectType | TypeFlags.Union)) { + let resolved = resolveObjectOrUnionTypeMembers(type); + return kind === IndexKind.String ? resolved.stringIndexType : resolved.numberIndexType; + } + } + + // Return the index type of the given kind in the given type. Creates synthetic union index types when necessary and + // maps primitive types and type parameters are to their apparent types. + function getIndexTypeOfType(type: Type, kind: IndexKind): Type { + return getIndexTypeOfObjectOrUnionType(getApparentType(type), kind); + } + + // Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual + // type checking functions). + function getTypeParametersFromDeclaration(typeParameterDeclarations: TypeParameterDeclaration[]): TypeParameter[] { + let result: TypeParameter[] = []; + forEach(typeParameterDeclarations, node => { + let tp = getDeclaredTypeOfTypeParameter(node.symbol); + if (!contains(result, tp)) { + result.push(tp); + } + }); + return result; + } + + function symbolsToArray(symbols: SymbolTable): Symbol[] { + let result: Symbol[] = []; + for (let id in symbols) { + if (!isReservedMemberName(id)) { + result.push(symbols[id]); + } + } + return result; + } + + function getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature { + let links = getNodeLinks(declaration); + if (!links.resolvedSignature) { + let classType = declaration.kind === SyntaxKind.Constructor ? getDeclaredTypeOfClassOrInterface((declaration.parent).symbol) : undefined; + let typeParameters = classType ? classType.typeParameters : + declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) : undefined; + let parameters: Symbol[] = []; + let hasStringLiterals = false; + let minArgumentCount = -1; + for (let i = 0, n = declaration.parameters.length; i < n; i++) { + let param = declaration.parameters[i]; + parameters.push(param.symbol); + if (param.type && param.type.kind === SyntaxKind.StringLiteral) { + hasStringLiterals = true; + } + if (minArgumentCount < 0) { + if (param.initializer || param.questionToken || param.dotDotDotToken) { + minArgumentCount = i; + } + } + } + + if (minArgumentCount < 0) { + minArgumentCount = declaration.parameters.length; + } + + let returnType: Type; + if (classType) { + returnType = classType; + } + else if (declaration.type) { + returnType = getTypeFromTypeNode(declaration.type); + } + else { + // TypeScript 1.0 spec (April 2014): + // If only one accessor includes a type annotation, the other behaves as if it had the same type annotation. + if (declaration.kind === SyntaxKind.GetAccessor && !hasDynamicName(declaration)) { + let setter = getDeclarationOfKind(declaration.symbol, SyntaxKind.SetAccessor); + returnType = getAnnotatedAccessorType(setter); + } + + if (!returnType && nodeIsMissing((declaration).body)) { + returnType = anyType; + } + } + + links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, + minArgumentCount, hasRestParameters(declaration), hasStringLiterals); + } + return links.resolvedSignature; + } + + function getSignaturesOfSymbol(symbol: Symbol): Signature[] { + if (!symbol) return emptyArray; + let result: Signature[] = []; + for (let i = 0, len = symbol.declarations.length; i < len; i++) { + let node = symbol.declarations[i]; + switch (node.kind) { + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + // Don't include signature if node is the implementation of an overloaded function. A node is considered + // an implementation node if it has a body and the previous node is of the same kind and immediately + // precedes the implementation node (i.e. has the same parent and ends where the implementation starts). + if (i > 0 && (node).body) { + let previous = symbol.declarations[i - 1]; + if (node.parent === previous.parent && node.kind === previous.kind && node.pos === previous.end) { + break; + } + } + result.push(getSignatureFromDeclaration(node)); + } + } + return result; + } + + function getReturnTypeOfSignature(signature: Signature): Type { + if (!signature.resolvedReturnType) { + signature.resolvedReturnType = resolvingType; + let type: Type; + if (signature.target) { + type = instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper); + } + else if (signature.unionSignatures) { + type = getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature)); + } + else { + type = getReturnTypeFromBody(signature.declaration); + } + if (signature.resolvedReturnType === resolvingType) { + signature.resolvedReturnType = type; + } + } + else if (signature.resolvedReturnType === resolvingType) { + signature.resolvedReturnType = anyType; + if (compilerOptions.noImplicitAny) { + let declaration = signature.declaration; + if (declaration.name) { + error(declaration.name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, declarationNameToString(declaration.name)); + } + else { + error(declaration, Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions); + } + } + } + return signature.resolvedReturnType; + } + + function getRestTypeOfSignature(signature: Signature): Type { + if (signature.hasRestParameter) { + let type = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); + if (type.flags & TypeFlags.Reference && (type).target === globalArrayType) { + return (type).typeArguments[0]; + } + } + return anyType; + } + + function getSignatureInstantiation(signature: Signature, typeArguments: Type[]): Signature { + return instantiateSignature(signature, createTypeMapper(signature.typeParameters, typeArguments), true); + } + + function getErasedSignature(signature: Signature): Signature { + if (!signature.typeParameters) return signature; + if (!signature.erasedSignatureCache) { + if (signature.target) { + signature.erasedSignatureCache = instantiateSignature(getErasedSignature(signature.target), signature.mapper); + } + else { + signature.erasedSignatureCache = instantiateSignature(signature, createTypeEraser(signature.typeParameters), true); + } + } + return signature.erasedSignatureCache; + } + + function getOrCreateTypeFromSignature(signature: Signature): ObjectType { + // There are two ways to declare a construct signature, one is by declaring a class constructor + // using the constructor keyword, and the other is declaring a bare construct signature in an + // object type literal or interface (using the new keyword). Each way of declaring a constructor + // will result in a different declaration kind. + if (!signature.isolatedSignatureType) { + let isConstructor = signature.declaration.kind === SyntaxKind.Constructor || signature.declaration.kind === SyntaxKind.ConstructSignature; + let type = createObjectType(TypeFlags.Anonymous | TypeFlags.FromSignature); + type.members = emptySymbols; + type.properties = emptyArray; + type.callSignatures = !isConstructor ? [signature] : emptyArray; + type.constructSignatures = isConstructor ? [signature] : emptyArray; + signature.isolatedSignatureType = type; + } + + return signature.isolatedSignatureType; + } + + function getIndexSymbol(symbol: Symbol): Symbol { + return symbol.members["__index"]; + } + + function getIndexDeclarationOfSymbol(symbol: Symbol, kind: IndexKind): SignatureDeclaration { + let syntaxKind = kind === IndexKind.Number ? SyntaxKind.NumberKeyword : SyntaxKind.StringKeyword; + let indexSymbol = getIndexSymbol(symbol); + if (indexSymbol) { + let len = indexSymbol.declarations.length; + for (let decl of indexSymbol.declarations) { + let node = decl; + if (node.parameters.length === 1) { + let parameter = node.parameters[0]; + if (parameter && parameter.type && parameter.type.kind === syntaxKind) { + return node; + } + } + } + } + + return undefined; + } + + function getIndexTypeOfSymbol(symbol: Symbol, kind: IndexKind): Type { + let declaration = getIndexDeclarationOfSymbol(symbol, kind); + return declaration + ? declaration.type ? getTypeFromTypeNode(declaration.type) : anyType + : undefined; + } + + function getConstraintOfTypeParameter(type: TypeParameter): Type { + if (!type.constraint) { + if (type.target) { + let targetConstraint = getConstraintOfTypeParameter(type.target); + type.constraint = targetConstraint ? instantiateType(targetConstraint, type.mapper) : noConstraintType; + } + else { + type.constraint = getTypeFromTypeNode((getDeclarationOfKind(type.symbol, SyntaxKind.TypeParameter)).constraint); + } + } + return type.constraint === noConstraintType ? undefined : type.constraint; + } + + function getTypeListId(types: Type[]) { + switch (types.length) { + case 1: + return "" + types[0].id; + case 2: + return types[0].id + "," + types[1].id; + default: + let result = ""; + for (let i = 0; i < types.length; i++) { + if (i > 0) { + result += ","; + } + + result += types[i].id; + } + return result; + } + } + + // This function is used to propagate widening flags when creating new object types references and union types. + // It is only necessary to do so if a constituent type might be the undefined type, the null type, or the type + // of an object literal (since those types have widening related information we need to track). + function getWideningFlagsOfTypes(types: Type[]): TypeFlags { + let result: TypeFlags = 0; + for (let type of types) { + result |= type.flags; + } + return result & TypeFlags.RequiresWidening; + } + + function createTypeReference(target: GenericType, typeArguments: Type[]): TypeReference { + let id = getTypeListId(typeArguments); + let type = target.instantiations[id]; + if (!type) { + let flags = TypeFlags.Reference | getWideningFlagsOfTypes(typeArguments); + type = target.instantiations[id] = createObjectType(flags, target.symbol); + type.target = target; + type.typeArguments = typeArguments; + } + return type; + } + + function isTypeParameterReferenceIllegalInConstraint(typeReferenceNode: TypeReferenceNode | HeritageClauseElement, typeParameterSymbol: Symbol): boolean { + let links = getNodeLinks(typeReferenceNode); + if (links.isIllegalTypeReferenceInConstraint !== undefined) { + return links.isIllegalTypeReferenceInConstraint; + } + + // bubble up to the declaration + let currentNode: Node = typeReferenceNode; + // forEach === exists + while (!forEach(typeParameterSymbol.declarations, d => d.parent === currentNode.parent)) { + currentNode = currentNode.parent; + } + // if last step was made from the type parameter this means that path has started somewhere in constraint which is illegal + links.isIllegalTypeReferenceInConstraint = currentNode.kind === SyntaxKind.TypeParameter; + return links.isIllegalTypeReferenceInConstraint; + } + + function checkTypeParameterHasIllegalReferencesInConstraint(typeParameter: TypeParameterDeclaration): void { + let typeParameterSymbol: Symbol; + function check(n: Node): void { + if (n.kind === SyntaxKind.TypeReference && (n).typeName.kind === SyntaxKind.Identifier) { + let links = getNodeLinks(n); + if (links.isIllegalTypeReferenceInConstraint === undefined) { + let symbol = resolveName(typeParameter, ((n).typeName).text, SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); + if (symbol && (symbol.flags & SymbolFlags.TypeParameter)) { + // TypeScript 1.0 spec (April 2014): 3.4.1 + // Type parameters declared in a particular type parameter list + // may not be referenced in constraints in that type parameter list + + // symbol.declaration.parent === typeParameter.parent + // -> typeParameter and symbol.declaration originate from the same type parameter list + // -> illegal for all declarations in symbol + // forEach === exists + links.isIllegalTypeReferenceInConstraint = forEach(symbol.declarations, d => d.parent == typeParameter.parent); + } + } + if (links.isIllegalTypeReferenceInConstraint) { + error(typeParameter, Diagnostics.Constraint_of_a_type_parameter_cannot_reference_any_type_parameter_from_the_same_type_parameter_list); + } + } + forEachChild(n, check); + } + + if (typeParameter.constraint) { + typeParameterSymbol = getSymbolOfNode(typeParameter); + check(typeParameter.constraint); + } + } + + function getTypeFromTypeReference(node: TypeReferenceNode): Type { + return getTypeFromTypeReferenceOrHeritageClauseElement(node); + } + + function getTypeFromHeritageClauseElement(node: HeritageClauseElement): Type { + return getTypeFromTypeReferenceOrHeritageClauseElement(node); + } + + function getTypeFromTypeReferenceOrHeritageClauseElement(node: TypeReferenceNode | HeritageClauseElement): Type { + let links = getNodeLinks(node); + if (!links.resolvedType) { + let type: Type; + + // We don't currently support heritage clauses with complex expressions in them. + // For these cases, we just set the type to be the unknownType. + if (node.kind !== SyntaxKind.HeritageClauseElement || isSupportedHeritageClauseElement(node)) { + let typeNameOrExpression = node.kind === SyntaxKind.TypeReference + ? (node).typeName + : (node).expression; + + let symbol = resolveEntityName(typeNameOrExpression, SymbolFlags.Type); + if (symbol) { + if ((symbol.flags & SymbolFlags.TypeParameter) && isTypeParameterReferenceIllegalInConstraint(node, symbol)) { + // TypeScript 1.0 spec (April 2014): 3.4.1 + // Type parameters declared in a particular type parameter list + // may not be referenced in constraints in that type parameter list + // Implementation: such type references are resolved to 'unknown' type that usually denotes error + type = unknownType; + } + else { + type = getDeclaredTypeOfSymbol(symbol); + if (type.flags & (TypeFlags.Class | TypeFlags.Interface) && type.flags & TypeFlags.Reference) { + let typeParameters = (type).typeParameters; + if (node.typeArguments && node.typeArguments.length === typeParameters.length) { + type = createTypeReference(type, map(node.typeArguments, getTypeFromTypeNode)); + } + else { + error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length); + type = undefined; + } + } + else { + if (node.typeArguments) { + error(node, Diagnostics.Type_0_is_not_generic, typeToString(type)); + type = undefined; + } + } + } + } + } + + links.resolvedType = type || unknownType; + } + return links.resolvedType; + } + + function getTypeFromTypeQueryNode(node: TypeQueryNode): Type { + let links = getNodeLinks(node); + if (!links.resolvedType) { + // TypeScript 1.0 spec (April 2014): 3.6.3 + // The expression is processed as an identifier expression (section 4.3) + // or property access expression(section 4.10), + // the widened type(section 3.9) of which becomes the result. + links.resolvedType = getWidenedType(checkExpressionOrQualifiedName(node.exprName)); + } + return links.resolvedType; + } + + function getTypeOfGlobalSymbol(symbol: Symbol, arity: number): ObjectType { + + function getTypeDeclaration(symbol: Symbol): Declaration { + let declarations = symbol.declarations; + for (let declaration of declarations) { + switch (declaration.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + return declaration; + } + } + } + + if (!symbol) { + return emptyObjectType; + } + let type = getDeclaredTypeOfSymbol(symbol); + if (!(type.flags & TypeFlags.ObjectType)) { + error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_be_a_class_or_interface_type, symbol.name); + return emptyObjectType; + } + if (((type).typeParameters ? (type).typeParameters.length : 0) !== arity) { + error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbol.name, arity); + return emptyObjectType; + } + return type; + } + + function getGlobalValueSymbol(name: string): Symbol { + return getGlobalSymbol(name, SymbolFlags.Value, Diagnostics.Cannot_find_global_value_0); + } + + function getGlobalTypeSymbol(name: string): Symbol { + return getGlobalSymbol(name, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0); + } + + function getGlobalSymbol(name: string, meaning: SymbolFlags, diagnostic: DiagnosticMessage): Symbol { + return resolveName(undefined, name, meaning, diagnostic, name); + } + + function getGlobalType(name: string, arity = 0): ObjectType { + return getTypeOfGlobalSymbol(getGlobalTypeSymbol(name), arity); + } + + function getGlobalESSymbolConstructorSymbol() { + return globalESSymbolConstructorSymbol || (globalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol")); + } + + function createIterableType(elementType: Type): Type { + return globalIterableType !== emptyObjectType ? createTypeReference(globalIterableType, [elementType]) : emptyObjectType; + } + + function createArrayType(elementType: Type): Type { + // globalArrayType will be undefined if we get here during creation of the Array type. This for example happens if + // user code augments the Array type with call or construct signatures that have an array type as the return type. + // We instead use globalArraySymbol to obtain the (not yet fully constructed) Array type. + let arrayType = globalArrayType || getDeclaredTypeOfSymbol(globalArraySymbol); + return arrayType !== emptyObjectType ? createTypeReference(arrayType, [elementType]) : emptyObjectType; + } + + function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type { + let links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = createArrayType(getTypeFromTypeNode(node.elementType)); + } + return links.resolvedType; + } + + function createTupleType(elementTypes: Type[]) { + let id = getTypeListId(elementTypes); + let type = tupleTypes[id]; + if (!type) { + type = tupleTypes[id] = createObjectType(TypeFlags.Tuple); + type.elementTypes = elementTypes; + } + return type; + } + + function getTypeFromTupleTypeNode(node: TupleTypeNode): Type { + let links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = createTupleType(map(node.elementTypes, getTypeFromTypeNode)); + } + return links.resolvedType; + } + + function addTypeToSortedSet(sortedSet: Type[], type: Type) { + if (type.flags & TypeFlags.Union) { + addTypesToSortedSet(sortedSet, (type).types); + } + else { + let i = 0; + let id = type.id; + while (i < sortedSet.length && sortedSet[i].id < id) { + i++; + } + if (i === sortedSet.length || sortedSet[i].id !== id) { + sortedSet.splice(i, 0, type); + } + } + } + + function addTypesToSortedSet(sortedTypes: Type[], types: Type[]) { + for (let type of types) { + addTypeToSortedSet(sortedTypes, type); + } + } + + function isSubtypeOfAny(candidate: Type, types: Type[]): boolean { + for (let type of types) { + if (candidate !== type && isTypeSubtypeOf(candidate, type)) { + return true; + } + } + return false; + } + + function removeSubtypes(types: Type[]) { + let i = types.length; + while (i > 0) { + i--; + if (isSubtypeOfAny(types[i], types)) { + types.splice(i, 1); + } + } + } + + function containsAnyType(types: Type[]) { + for (let type of types) { + if (type.flags & TypeFlags.Any) { + return true; + } + } + return false; + } + + function removeAllButLast(types: Type[], typeToRemove: Type) { + let i = types.length; + while (i > 0 && types.length > 1) { + i--; + if (types[i] === typeToRemove) { + types.splice(i, 1); + } + } + } + + // The noSubtypeReduction flag is there because it isn't possible to always do subtype reduction. The flag + // is true when creating a union type from a type node and when instantiating a union type. In both of those + // cases subtype reduction has to be deferred to properly support recursive union types. For example, a + // type alias of the form "type Item = string | (() => Item)" cannot be reduced during its declaration. + function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type { + if (types.length === 0) { + return emptyObjectType; + } + let sortedTypes: Type[] = []; + addTypesToSortedSet(sortedTypes, types); + if (noSubtypeReduction) { + if (containsAnyType(sortedTypes)) { + return anyType; + } + removeAllButLast(sortedTypes, undefinedType); + removeAllButLast(sortedTypes, nullType); + } + else { + removeSubtypes(sortedTypes); + } + if (sortedTypes.length === 1) { + return sortedTypes[0]; + } + let id = getTypeListId(sortedTypes); + let type = unionTypes[id]; + if (!type) { + type = unionTypes[id] = createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(sortedTypes)); + type.types = sortedTypes; + type.reducedType = noSubtypeReduction ? undefined : type; + } + return type; + } + + function getReducedTypeOfUnionType(type: UnionType): Type { + // If union type was created without subtype reduction, perform the deferred reduction now + if (!type.reducedType) { + type.reducedType = getUnionType(type.types, /*noSubtypeReduction*/ false); + } + return type.reducedType; + } + + function getTypeFromUnionTypeNode(node: UnionTypeNode): Type { + let links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), /*noSubtypeReduction*/ true); + } + return links.resolvedType; + } + + function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node): Type { + let links = getNodeLinks(node); + if (!links.resolvedType) { + // Deferred resolution of members is handled by resolveObjectTypeMembers + links.resolvedType = createObjectType(TypeFlags.Anonymous, node.symbol); + } + return links.resolvedType; + } + + function getStringLiteralType(node: StringLiteral): StringLiteralType { + if (hasProperty(stringLiteralTypes, node.text)) { + return stringLiteralTypes[node.text]; + } + + let type = stringLiteralTypes[node.text] = createType(TypeFlags.StringLiteral); + type.text = getTextOfNode(node); + return type; + } + + function getTypeFromStringLiteral(node: StringLiteral): Type { + let links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = getStringLiteralType(node); + } + return links.resolvedType; + } + + function getTypeFromTypeNode(node: TypeNode): Type { + switch (node.kind) { + case SyntaxKind.AnyKeyword: + return anyType; + case SyntaxKind.StringKeyword: + return stringType; + case SyntaxKind.NumberKeyword: + return numberType; + case SyntaxKind.BooleanKeyword: + return booleanType; + case SyntaxKind.SymbolKeyword: + return esSymbolType; + case SyntaxKind.VoidKeyword: + return voidType; + case SyntaxKind.StringLiteral: + return getTypeFromStringLiteral(node); + case SyntaxKind.TypeReference: + return getTypeFromTypeReference(node); + case SyntaxKind.HeritageClauseElement: + return getTypeFromHeritageClauseElement(node); + case SyntaxKind.TypeQuery: + return getTypeFromTypeQueryNode(node); + case SyntaxKind.ArrayType: + return getTypeFromArrayTypeNode(node); + case SyntaxKind.TupleType: + return getTypeFromTupleTypeNode(node); + case SyntaxKind.UnionType: + return getTypeFromUnionTypeNode(node); + case SyntaxKind.ParenthesizedType: + return getTypeFromTypeNode((node).type); + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.TypeLiteral: + return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); + // This function assumes that an identifier or qualified name is a type expression + // Callers should first ensure this by calling isTypeNode + case SyntaxKind.Identifier: + case SyntaxKind.QualifiedName: + let symbol = getSymbolInfo(node); + return symbol && getDeclaredTypeOfSymbol(symbol); + default: + return unknownType; + } + } + + function instantiateList(items: T[], mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): T[] { + if (items && items.length) { + let result: T[] = []; + for (let v of items) { + result.push(instantiator(v, mapper)); + } + return result; + } + return items; + } + + function createUnaryTypeMapper(source: Type, target: Type): TypeMapper { + return t => t === source ? target : t; + } + + function createBinaryTypeMapper(source1: Type, target1: Type, source2: Type, target2: Type): TypeMapper { + return t => t === source1 ? target1 : t === source2 ? target2 : t; + } + + function createTypeMapper(sources: Type[], targets: Type[]): TypeMapper { + switch (sources.length) { + case 1: return createUnaryTypeMapper(sources[0], targets[0]); + case 2: return createBinaryTypeMapper(sources[0], targets[0], sources[1], targets[1]); + } + return t => { + for (let i = 0; i < sources.length; i++) { + if (t === sources[i]) { + return targets[i]; + } + } + return t; + }; + } + + function createUnaryTypeEraser(source: Type): TypeMapper { + return t => t === source ? anyType : t; + } + + function createBinaryTypeEraser(source1: Type, source2: Type): TypeMapper { + return t => t === source1 || t === source2 ? anyType : t; + } + + function createTypeEraser(sources: Type[]): TypeMapper { + switch (sources.length) { + case 1: return createUnaryTypeEraser(sources[0]); + case 2: return createBinaryTypeEraser(sources[0], sources[1]); + } + return t => { + for (let source of sources) { + if (t === source) { + return anyType; + } + } + return t; + }; + } + + function createInferenceMapper(context: InferenceContext): TypeMapper { + return t => { + for (let i = 0; i < context.typeParameters.length; i++) { + if (t === context.typeParameters[i]) { + context.inferences[i].isFixed = true; + return getInferredType(context, i); + } + } + return t; + } + } + + function identityMapper(type: Type): Type { + return type; + } + + function combineTypeMappers(mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper { + return t => instantiateType(mapper1(t), mapper2); + } + + function instantiateTypeParameter(typeParameter: TypeParameter, mapper: TypeMapper): TypeParameter { + let result = createType(TypeFlags.TypeParameter); + result.symbol = typeParameter.symbol; + if (typeParameter.constraint) { + result.constraint = instantiateType(typeParameter.constraint, mapper); + } + else { + result.target = typeParameter; + result.mapper = mapper; + } + return result; + } + + function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature { + let freshTypeParameters: TypeParameter[]; + if (signature.typeParameters && !eraseTypeParameters) { + freshTypeParameters = instantiateList(signature.typeParameters, mapper, instantiateTypeParameter); + mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper); + } + let result = createSignature(signature.declaration, freshTypeParameters, + instantiateList(signature.parameters, mapper, instantiateSymbol), + signature.resolvedReturnType ? instantiateType(signature.resolvedReturnType, mapper) : undefined, + signature.minArgumentCount, signature.hasRestParameter, signature.hasStringLiterals); + result.target = signature; + result.mapper = mapper; + return result; + } + + function instantiateSymbol(symbol: Symbol, mapper: TypeMapper): Symbol { + if (symbol.flags & SymbolFlags.Instantiated) { + let links = getSymbolLinks(symbol); + // If symbol being instantiated is itself a instantiation, fetch the original target and combine the + // type mappers. This ensures that original type identities are properly preserved and that aliases + // always reference a non-aliases. + symbol = links.target; + mapper = combineTypeMappers(links.mapper, mapper); + } + + // Keep the flags from the symbol we're instantiating. Mark that is instantiated, and + // also transient so that we can just store data on it directly. + let result = createSymbol(SymbolFlags.Instantiated | SymbolFlags.Transient | symbol.flags, symbol.name); + result.declarations = symbol.declarations; + result.parent = symbol.parent; + result.target = symbol; + result.mapper = mapper; + if (symbol.valueDeclaration) { + result.valueDeclaration = symbol.valueDeclaration; + } + + return result; + } + + function instantiateAnonymousType(type: ObjectType, mapper: TypeMapper): ObjectType { + let result = createObjectType(TypeFlags.Anonymous, type.symbol); + result.properties = instantiateList(getPropertiesOfObjectType(type), mapper, instantiateSymbol); + result.members = createSymbolTable(result.properties); + result.callSignatures = instantiateList(getSignaturesOfType(type, SignatureKind.Call), mapper, instantiateSignature); + result.constructSignatures = instantiateList(getSignaturesOfType(type, SignatureKind.Construct), mapper, instantiateSignature); + let stringIndexType = getIndexTypeOfType(type, IndexKind.String); + let numberIndexType = getIndexTypeOfType(type, IndexKind.Number); + if (stringIndexType) result.stringIndexType = instantiateType(stringIndexType, mapper); + if (numberIndexType) result.numberIndexType = instantiateType(numberIndexType, mapper); + return result; + } + + function instantiateType(type: Type, mapper: TypeMapper): Type { + if (mapper !== identityMapper) { + if (type.flags & TypeFlags.TypeParameter) { + return mapper(type); + } + if (type.flags & TypeFlags.Anonymous) { + return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) ? + instantiateAnonymousType(type, mapper) : type; + } + if (type.flags & TypeFlags.Reference) { + return createTypeReference((type).target, instantiateList((type).typeArguments, mapper, instantiateType)); + } + if (type.flags & TypeFlags.Tuple) { + return createTupleType(instantiateList((type).elementTypes, mapper, instantiateType)); + } + if (type.flags & TypeFlags.Union) { + return getUnionType(instantiateList((type).types, mapper, instantiateType), /*noSubtypeReduction*/ true); + } + } + return type; + } + + // Returns true if the given expression contains (at any level of nesting) a function or arrow expression + // that is subject to contextual typing. + function isContextSensitive(node: Expression | MethodDeclaration | ObjectLiteralElement): boolean { + Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + switch (node.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + return isContextSensitiveFunctionLikeDeclaration(node); + case SyntaxKind.ObjectLiteralExpression: + return forEach((node).properties, isContextSensitive); + case SyntaxKind.ArrayLiteralExpression: + return forEach((node).elements, isContextSensitive); + case SyntaxKind.ConditionalExpression: + return isContextSensitive((node).whenTrue) || + isContextSensitive((node).whenFalse); + case SyntaxKind.BinaryExpression: + return (node).operatorToken.kind === SyntaxKind.BarBarToken && + (isContextSensitive((node).left) || isContextSensitive((node).right)); + case SyntaxKind.PropertyAssignment: + return isContextSensitive((node).initializer); + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + return isContextSensitiveFunctionLikeDeclaration(node); + case SyntaxKind.ParenthesizedExpression: + return isContextSensitive((node).expression); + } + + return false; + } + + function isContextSensitiveFunctionLikeDeclaration(node: FunctionLikeDeclaration) { + return !node.typeParameters && node.parameters.length && !forEach(node.parameters, p => p.type); + } + + function getTypeWithoutConstructors(type: Type): Type { + if (type.flags & TypeFlags.ObjectType) { + let resolved = resolveObjectOrUnionTypeMembers(type); + if (resolved.constructSignatures.length) { + let result = createObjectType(TypeFlags.Anonymous, type.symbol); + result.members = resolved.members; + result.properties = resolved.properties; + result.callSignatures = resolved.callSignatures; + result.constructSignatures = emptyArray; + type = result; + } + } + return type; + } + + // TYPE CHECKING + + let subtypeRelation: Map = {}; + let assignableRelation: Map = {}; + let identityRelation: Map = {}; + + function isTypeIdenticalTo(source: Type, target: Type): boolean { + return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined); + } + + function compareTypes(source: Type, target: Type): Ternary { + return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False; + } + + function isTypeSubtypeOf(source: Type, target: Type): boolean { + return checkTypeSubtypeOf(source, target, /*errorNode*/ undefined); + } + + function isTypeAssignableTo(source: Type, target: Type): boolean { + return checkTypeAssignableTo(source, target, /*errorNode*/ undefined); + } + + function checkTypeSubtypeOf(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: DiagnosticMessageChain): boolean { + return checkTypeRelatedTo(source, target, subtypeRelation, errorNode, headMessage, containingMessageChain); + } + + function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage): boolean { + return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage); + } + + function isSignatureAssignableTo(source: Signature, target: Signature): boolean { + let sourceType = getOrCreateTypeFromSignature(source); + let targetType = getOrCreateTypeFromSignature(target); + return checkTypeRelatedTo(sourceType, targetType, assignableRelation, /*errorNode*/ undefined); + } + + function checkTypeRelatedTo( + source: Type, + target: Type, + relation: Map, + errorNode: Node, + headMessage?: DiagnosticMessage, + containingMessageChain?: DiagnosticMessageChain): boolean { + + let errorInfo: DiagnosticMessageChain; + let sourceStack: ObjectType[]; + let targetStack: ObjectType[]; + let maybeStack: Map[]; + let expandingFlags: number; + let depth = 0; + let overflow = false; + let elaborateErrors = false; + + Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking"); + + let result = isRelatedTo(source, target, errorNode !== undefined, headMessage); + if (overflow) { + error(errorNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target)); + } + else if (errorInfo) { + // If we already computed this relation, but in a context where we didn't want to report errors (e.g. overload resolution), + // then we'll only have a top-level error (e.g. 'Class X does not implement interface Y') without any details. If this happened, + // request a recompuation to get a complete error message. This will be skipped if we've already done this computation in a context + // where errors were being reported. + if (errorInfo.next === undefined) { + errorInfo = undefined; + elaborateErrors = true; + isRelatedTo(source, target, errorNode !== undefined, headMessage); + } + if (containingMessageChain) { + errorInfo = concatenateDiagnosticMessageChains(containingMessageChain, errorInfo); + } + + diagnostics.add(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo)); + } + return result !== Ternary.False; + + function reportError(message: DiagnosticMessage, arg0?: string, arg1?: string, arg2?: string): void { + errorInfo = chainDiagnosticMessages(errorInfo, message, arg0, arg1, arg2); + } + + // Compare two types and return + // Ternary.True if they are related with no assumptions, + // Ternary.Maybe if they are related with assumptions of other relationships, or + // Ternary.False if they are not related. + function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary { + let result: Ternary; + // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases + if (source === target) return Ternary.True; + if (relation !== identityRelation) { + if (target.flags & TypeFlags.Any) return Ternary.True; + if (source === undefinedType) return Ternary.True; + if (source === nullType && target !== undefinedType) return Ternary.True; + if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True; + if (source.flags & TypeFlags.StringLiteral && target === stringType) return Ternary.True; + if (relation === assignableRelation) { + if (source.flags & TypeFlags.Any) return Ternary.True; + if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True; + } + } + let saveErrorInfo = errorInfo; + if (source.flags & TypeFlags.Union || target.flags & TypeFlags.Union) { + if (relation === identityRelation) { + if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union) { + if (result = unionTypeRelatedToUnionType(source, target)) { + if (result &= unionTypeRelatedToUnionType(target, source)) { + return result; + } + } + } + else if (source.flags & TypeFlags.Union) { + if (result = unionTypeRelatedToType(source, target, reportErrors)) { + return result; + } + } + else { + if (result = unionTypeRelatedToType(target, source, reportErrors)) { + return result; + } + } + } + else { + if (source.flags & TypeFlags.Union) { + if (result = unionTypeRelatedToType(source, target, reportErrors)) { + return result; + } + } + else { + if (result = typeRelatedToUnionType(source, target, reportErrors)) { + return result; + } + } + } + } + else if (source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.TypeParameter) { + if (result = typeParameterRelatedTo(source, target, reportErrors)) { + return result; + } + } + else if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (source).target === (target).target) { + // We have type references to same target type, see if relationship holds for all type arguments + if (result = typesRelatedTo((source).typeArguments, (target).typeArguments, reportErrors)) { + return result; + } + } + + // Even if relationship doesn't hold for unions, type parameters, or generic type references, + // it may hold in a structural comparison. + // Report structural errors only if we haven't reported any errors yet + let reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; + // identity relation does not use apparent type + let sourceOrApparentType = relation === identityRelation ? source : getApparentType(source); + if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType) { + if (result = objectTypeRelatedTo(sourceOrApparentType, target, reportStructuralErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } + else if (source.flags & TypeFlags.TypeParameter && sourceOrApparentType.flags & TypeFlags.Union) { + // We clear the errors first because the following check often gives a better error than + // the union comparison above if it is applicable. + errorInfo = saveErrorInfo; + if (result = isRelatedTo(sourceOrApparentType, target, reportErrors)) { + return result; + } + } + + if (reportErrors) { + headMessage = headMessage || Diagnostics.Type_0_is_not_assignable_to_type_1; + let sourceType = typeToString(source); + let targetType = typeToString(target); + if (sourceType === targetType) { + sourceType = typeToString(source, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType); + targetType = typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType); + } + reportError(headMessage, sourceType, targetType); + } + return Ternary.False; + } + + function unionTypeRelatedToUnionType(source: UnionType, target: UnionType): Ternary { + let result = Ternary.True; + let sourceTypes = source.types; + for (let sourceType of sourceTypes) { + let related = typeRelatedToUnionType(sourceType, target, false); + if (!related) { + return Ternary.False; + } + result &= related; + } + return result; + } + + function typeRelatedToUnionType(source: Type, target: UnionType, reportErrors: boolean): Ternary { + let targetTypes = target.types; + for (let i = 0, len = targetTypes.length; i < len; i++) { + let related = isRelatedTo(source, targetTypes[i], reportErrors && i === len - 1); + if (related) { + return related; + } + } + return Ternary.False; + } + + function unionTypeRelatedToType(source: UnionType, target: Type, reportErrors: boolean): Ternary { + let result = Ternary.True; + let sourceTypes = source.types; + for (let sourceType of sourceTypes) { + let related = isRelatedTo(sourceType, target, reportErrors); + if (!related) { + return Ternary.False; + } + result &= related; + } + return result; + } + + function typesRelatedTo(sources: Type[], targets: Type[], reportErrors: boolean): Ternary { + let result = Ternary.True; + for (let i = 0, len = sources.length; i < len; i++) { + let related = isRelatedTo(sources[i], targets[i], reportErrors); + if (!related) { + return Ternary.False; + } + result &= related; + } + return result; + } + + function typeParameterRelatedTo(source: TypeParameter, target: TypeParameter, reportErrors: boolean): Ternary { + if (relation === identityRelation) { + if (source.symbol.name !== target.symbol.name) { + return Ternary.False; + } + // covers case when both type parameters does not have constraint (both equal to noConstraintType) + if (source.constraint === target.constraint) { + return Ternary.True; + } + if (source.constraint === noConstraintType || target.constraint === noConstraintType) { + return Ternary.False; + } + return isRelatedTo(source.constraint, target.constraint, reportErrors); + } + else { + while (true) { + let constraint = getConstraintOfTypeParameter(source); + if (constraint === target) return Ternary.True; + if (!(constraint && constraint.flags & TypeFlags.TypeParameter)) break; + source = constraint; + } + return Ternary.False; + } + } + + // Determine if two object types are related by structure. First, check if the result is already available in the global cache. + // Second, check if we have already started a comparison of the given two types in which case we assume the result to be true. + // Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are + // equal and infinitely expanding. Fourth, if we have reached a depth of 100 nested comparisons, assume we have runaway recursion + // and issue an error. Otherwise, actually compare the structure of the two types. + function objectTypeRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary { + if (overflow) { + return Ternary.False; + } + let id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id; + let related = relation[id]; + //let related: RelationComparisonResult = undefined; // relation[id]; + if (related !== undefined) { + // If we computed this relation already and it was failed and reported, or if we're not being asked to elaborate + // errors, we can use the cached value. Otherwise, recompute the relation + if (!elaborateErrors || (related === RelationComparisonResult.FailedAndReported)) { + return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False; + } + } + if (depth > 0) { + for (let i = 0; i < depth; i++) { + // If source and target are already being compared, consider them related with assumptions + if (maybeStack[i][id]) { + return Ternary.Maybe; + } + } + if (depth === 100) { + overflow = true; + return Ternary.False; + } + } + else { + sourceStack = []; + targetStack = []; + maybeStack = []; + expandingFlags = 0; + } + sourceStack[depth] = source; + targetStack[depth] = target; + maybeStack[depth] = {}; + maybeStack[depth][id] = RelationComparisonResult.Succeeded; + depth++; + let saveExpandingFlags = expandingFlags; + if (!(expandingFlags & 1) && isDeeplyNestedGeneric(source, sourceStack)) expandingFlags |= 1; + if (!(expandingFlags & 2) && isDeeplyNestedGeneric(target, targetStack)) expandingFlags |= 2; + let result: Ternary; + if (expandingFlags === 3) { + result = Ternary.Maybe; + } + else { + result = propertiesRelatedTo(source, target, reportErrors); + if (result) { + result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportErrors); + if (result) { + result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportErrors); + if (result) { + result &= stringIndexTypesRelatedTo(source, target, reportErrors); + if (result) { + result &= numberIndexTypesRelatedTo(source, target, reportErrors); + } + } + } + } + } + expandingFlags = saveExpandingFlags; + depth--; + if (result) { + let maybeCache = maybeStack[depth]; + // If result is definitely true, copy assumptions to global cache, else copy to next level up + let destinationCache = (result === Ternary.True || depth === 0) ? relation : maybeStack[depth - 1]; + copyMap(maybeCache, destinationCache); + } + else { + // A false result goes straight into global cache (when something is false under assumptions it + // will also be false without assumptions) + relation[id] = reportErrors ? RelationComparisonResult.FailedAndReported : RelationComparisonResult.Failed; + } + return result; + } + + // Return true if the given type is part of a deeply nested chain of generic instantiations. We consider this to be the case + // when structural type comparisons have been started for 10 or more instantiations of the same generic type. It is possible, + // though highly unlikely, for this test to be true in a situation where a chain of instantiations is not infinitely expanding. + // Effectively, we will generate a false positive when two types are structurally equal to at least 10 levels, but unequal at + // some level beyond that. + function isDeeplyNestedGeneric(type: ObjectType, stack: ObjectType[]): boolean { + if (type.flags & TypeFlags.Reference && depth >= 10) { + let target = (type).target; + let count = 0; + for (let i = 0; i < depth; i++) { + let t = stack[i]; + if (t.flags & TypeFlags.Reference && (t).target === target) { + count++; + if (count >= 10) return true; + } + } + } + return false; + } + + function propertiesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary { + if (relation === identityRelation) { + return propertiesIdenticalTo(source, target); + } + let result = Ternary.True; + let properties = getPropertiesOfObjectType(target); + let requireOptionalProperties = relation === subtypeRelation && !(source.flags & TypeFlags.ObjectLiteral); + for (let targetProp of properties) { + let sourceProp = getPropertyOfType(source, targetProp.name); + if (sourceProp !== targetProp) { + if (!sourceProp) { + if (!(targetProp.flags & SymbolFlags.Optional) || requireOptionalProperties) { + if (reportErrors) { + reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(targetProp), typeToString(source)); + } + return Ternary.False; + } + } + else if (!(targetProp.flags & SymbolFlags.Prototype)) { + let sourceFlags = getDeclarationFlagsFromSymbol(sourceProp); + let targetFlags = getDeclarationFlagsFromSymbol(targetProp); + if (sourceFlags & NodeFlags.Private || targetFlags & NodeFlags.Private) { + if (sourceProp.valueDeclaration !== targetProp.valueDeclaration) { + if (reportErrors) { + if (sourceFlags & NodeFlags.Private && targetFlags & NodeFlags.Private) { + reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp)); + } + else { + reportError(Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, symbolToString(targetProp), + typeToString(sourceFlags & NodeFlags.Private ? source : target), + typeToString(sourceFlags & NodeFlags.Private ? target : source)); + } + } + return Ternary.False; + } + } + else if (targetFlags & NodeFlags.Protected) { + let sourceDeclaredInClass = sourceProp.parent && sourceProp.parent.flags & SymbolFlags.Class; + let sourceClass = sourceDeclaredInClass ? getDeclaredTypeOfSymbol(sourceProp.parent) : undefined; + let targetClass = getDeclaredTypeOfSymbol(targetProp.parent); + if (!sourceClass || !hasBaseType(sourceClass, targetClass)) { + if (reportErrors) { + reportError(Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, + symbolToString(targetProp), typeToString(sourceClass || source), typeToString(targetClass)); + } + return Ternary.False; + } + } + else if (sourceFlags & NodeFlags.Protected) { + if (reportErrors) { + reportError(Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2, + symbolToString(targetProp), typeToString(source), typeToString(target)); + } + return Ternary.False; + } + let related = isRelatedTo(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp), reportErrors); + if (!related) { + if (reportErrors) { + reportError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp)); + } + return Ternary.False; + } + result &= related; + if (sourceProp.flags & SymbolFlags.Optional && !(targetProp.flags & SymbolFlags.Optional)) { + // TypeScript 1.0 spec (April 2014): 3.8.3 + // S is a subtype of a type T, and T is a supertype of S if ... + // S' and T are object types and, for each member M in T.. + // M is a property and S' contains a property N where + // if M is a required property, N is also a required property + // (M - property in T) + // (N - property in S) + if (reportErrors) { + reportError(Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2, + symbolToString(targetProp), typeToString(source), typeToString(target)); + } + return Ternary.False; + } + } + } + } + return result; + } + + function propertiesIdenticalTo(source: ObjectType, target: ObjectType): Ternary { + let sourceProperties = getPropertiesOfObjectType(source); + let targetProperties = getPropertiesOfObjectType(target); + if (sourceProperties.length !== targetProperties.length) { + return Ternary.False; + } + let result = Ternary.True; + for (let sourceProp of sourceProperties) { + let targetProp = getPropertyOfObjectType(target, sourceProp.name); + if (!targetProp) { + return Ternary.False; + } + let related = compareProperties(sourceProp, targetProp, isRelatedTo); + if (!related) { + return Ternary.False; + } + result &= related; + } + return result; + } + + function signaturesRelatedTo(source: ObjectType, target: ObjectType, kind: SignatureKind, reportErrors: boolean): Ternary { + if (relation === identityRelation) { + return signaturesIdenticalTo(source, target, kind); + } + if (target === anyFunctionType || source === anyFunctionType) { + return Ternary.True; + } + let sourceSignatures = getSignaturesOfType(source, kind); + let targetSignatures = getSignaturesOfType(target, kind); + let result = Ternary.True; + let saveErrorInfo = errorInfo; + outer: for (let t of targetSignatures) { + if (!t.hasStringLiterals || target.flags & TypeFlags.FromSignature) { + let localErrors = reportErrors; + for (let s of sourceSignatures) { + if (!s.hasStringLiterals || source.flags & TypeFlags.FromSignature) { + let related = signatureRelatedTo(s, t, localErrors); + if (related) { + result &= related; + errorInfo = saveErrorInfo; + continue outer; + } + // Only report errors from the first failure + localErrors = false; + } + } + return Ternary.False; + } + } + return result; + } + + function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary { + if (source === target) { + return Ternary.True; + } + if (!target.hasRestParameter && source.minArgumentCount > target.parameters.length) { + return Ternary.False; + } + let sourceMax = source.parameters.length; + let targetMax = target.parameters.length; + let checkCount: number; + if (source.hasRestParameter && target.hasRestParameter) { + checkCount = sourceMax > targetMax ? sourceMax : targetMax; + sourceMax--; + targetMax--; + } + else if (source.hasRestParameter) { + sourceMax--; + checkCount = targetMax; + } + else if (target.hasRestParameter) { + targetMax--; + checkCount = sourceMax; + } + else { + checkCount = sourceMax < targetMax ? sourceMax : targetMax; + } + // Spec 1.0 Section 3.8.3 & 3.8.4: + // M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N + source = getErasedSignature(source); + target = getErasedSignature(target); + let result = Ternary.True; + for (let i = 0; i < checkCount; i++) { + let s = i < sourceMax ? getTypeOfSymbol(source.parameters[i]) : getRestTypeOfSignature(source); + let t = i < targetMax ? getTypeOfSymbol(target.parameters[i]) : getRestTypeOfSignature(target); + let saveErrorInfo = errorInfo; + let related = isRelatedTo(s, t, reportErrors); + if (!related) { + related = isRelatedTo(t, s, false); + if (!related) { + if (reportErrors) { + reportError(Diagnostics.Types_of_parameters_0_and_1_are_incompatible, + source.parameters[i < sourceMax ? i : sourceMax].name, + target.parameters[i < targetMax ? i : targetMax].name); + } + return Ternary.False; + } + errorInfo = saveErrorInfo; + } + result &= related; + } + let t = getReturnTypeOfSignature(target); + if (t === voidType) return result; + let s = getReturnTypeOfSignature(source); + return result & isRelatedTo(s, t, reportErrors); + } + + function signaturesIdenticalTo(source: ObjectType, target: ObjectType, kind: SignatureKind): Ternary { + let sourceSignatures = getSignaturesOfType(source, kind); + let targetSignatures = getSignaturesOfType(target, kind); + if (sourceSignatures.length !== targetSignatures.length) { + return Ternary.False; + } + let result = Ternary.True; + for (let i = 0, len = sourceSignatures.length; i < len; ++i) { + let related = compareSignatures(sourceSignatures[i], targetSignatures[i], /*compareReturnTypes*/ true, isRelatedTo); + if (!related) { + return Ternary.False; + } + result &= related; + } + return result; + } + + function stringIndexTypesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary { + if (relation === identityRelation) { + return indexTypesIdenticalTo(IndexKind.String, source, target); + } + let targetType = getIndexTypeOfType(target, IndexKind.String); + if (targetType) { + let sourceType = getIndexTypeOfType(source, IndexKind.String); + if (!sourceType) { + if (reportErrors) { + reportError(Diagnostics.Index_signature_is_missing_in_type_0, typeToString(source)); + } + return Ternary.False; + } + let related = isRelatedTo(sourceType, targetType, reportErrors); + if (!related) { + if (reportErrors) { + reportError(Diagnostics.Index_signatures_are_incompatible); + } + return Ternary.False; + } + return related; + } + return Ternary.True; + } + + function numberIndexTypesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary { + if (relation === identityRelation) { + return indexTypesIdenticalTo(IndexKind.Number, source, target); + } + let targetType = getIndexTypeOfType(target, IndexKind.Number); + if (targetType) { + let sourceStringType = getIndexTypeOfType(source, IndexKind.String); + let sourceNumberType = getIndexTypeOfType(source, IndexKind.Number); + if (!(sourceStringType || sourceNumberType)) { + if (reportErrors) { + reportError(Diagnostics.Index_signature_is_missing_in_type_0, typeToString(source)); + } + return Ternary.False; + } + let related: Ternary; + if (sourceStringType && sourceNumberType) { + // If we know for sure we're testing both string and numeric index types then only report errors from the second one + related = isRelatedTo(sourceStringType, targetType, false) || isRelatedTo(sourceNumberType, targetType, reportErrors); + } + else { + related = isRelatedTo(sourceStringType || sourceNumberType, targetType, reportErrors); + } + if (!related) { + if (reportErrors) { + reportError(Diagnostics.Index_signatures_are_incompatible); + } + return Ternary.False; + } + return related; + } + return Ternary.True; + } + + function indexTypesIdenticalTo(indexKind: IndexKind, source: ObjectType, target: ObjectType): Ternary { + let targetType = getIndexTypeOfType(target, indexKind); + let sourceType = getIndexTypeOfType(source, indexKind); + if (!sourceType && !targetType) { + return Ternary.True; + } + if (sourceType && targetType) { + return isRelatedTo(sourceType, targetType); + } + return Ternary.False; + } + } + + function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean { + return compareProperties(sourceProp, targetProp, compareTypes) !== Ternary.False; + } + + function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary { + // Two members are considered identical when + // - they are public properties with identical names, optionality, and types, + // - they are private or protected properties originating in the same declaration and having identical types + if (sourceProp === targetProp) { + return Ternary.True; + } + let sourcePropAccessibility = getDeclarationFlagsFromSymbol(sourceProp) & (NodeFlags.Private | NodeFlags.Protected); + let targetPropAccessibility = getDeclarationFlagsFromSymbol(targetProp) & (NodeFlags.Private | NodeFlags.Protected); + if (sourcePropAccessibility !== targetPropAccessibility) { + return Ternary.False; + } + if (sourcePropAccessibility) { + if (getTargetSymbol(sourceProp) !== getTargetSymbol(targetProp)) { + return Ternary.False; + } + } + else { + if ((sourceProp.flags & SymbolFlags.Optional) !== (targetProp.flags & SymbolFlags.Optional)) { + return Ternary.False; + } + } + return compareTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); + } + + function compareSignatures(source: Signature, target: Signature, compareReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary { + if (source === target) { + return Ternary.True; + } + if (source.parameters.length !== target.parameters.length || + source.minArgumentCount !== target.minArgumentCount || + source.hasRestParameter !== target.hasRestParameter) { + return Ternary.False; + } + let result = Ternary.True; + if (source.typeParameters && target.typeParameters) { + if (source.typeParameters.length !== target.typeParameters.length) { + return Ternary.False; + } + for (let i = 0, len = source.typeParameters.length; i < len; ++i) { + let related = compareTypes(source.typeParameters[i], target.typeParameters[i]); + if (!related) { + return Ternary.False; + } + result &= related; + } + } + else if (source.typeParameters || target.typeParameters) { + return Ternary.False; + } + // Spec 1.0 Section 3.8.3 & 3.8.4: + // M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N + source = getErasedSignature(source); + target = getErasedSignature(target); + for (let i = 0, len = source.parameters.length; i < len; i++) { + let s = source.hasRestParameter && i === len - 1 ? getRestTypeOfSignature(source) : getTypeOfSymbol(source.parameters[i]); + let t = target.hasRestParameter && i === len - 1 ? getRestTypeOfSignature(target) : getTypeOfSymbol(target.parameters[i]); + let related = compareTypes(s, t); + if (!related) { + return Ternary.False; + } + result &= related; + } + if (compareReturnTypes) { + result &= compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + } + return result; + } + + function isSupertypeOfEach(candidate: Type, types: Type[]): boolean { + for (let type of types) { + if (candidate !== type && !isTypeSubtypeOf(type, candidate)) return false; + } + return true; + } + + function getCommonSupertype(types: Type[]): Type { + return forEach(types, t => isSupertypeOfEach(t, types) ? t : undefined); + } + + function reportNoCommonSupertypeError(types: Type[], errorLocation: Node, errorMessageChainHead: DiagnosticMessageChain): void { + // The downfallType/bestSupertypeDownfallType is the first type that caused a particular candidate + // to not be the common supertype. So if it weren't for this one downfallType (and possibly others), + // the type in question could have been the common supertype. + let bestSupertype: Type; + let bestSupertypeDownfallType: Type; + let bestSupertypeScore = 0; + + for (let i = 0; i < types.length; i++) { + let score = 0; + let downfallType: Type = undefined; + for (let j = 0; j < types.length; j++) { + if (isTypeSubtypeOf(types[j], types[i])) { + score++; + } + else if (!downfallType) { + downfallType = types[j]; + } + } + + Debug.assert(!!downfallType, "If there is no common supertype, each type should have a downfallType"); + + if (score > bestSupertypeScore) { + bestSupertype = types[i]; + bestSupertypeDownfallType = downfallType; + bestSupertypeScore = score; + } + + // types.length - 1 is the maximum score, given that getCommonSupertype returned false + if (bestSupertypeScore === types.length - 1) { + break; + } + } + + // In the following errors, the {1} slot is before the {0} slot because checkTypeSubtypeOf supplies the + // subtype as the first argument to the error + checkTypeSubtypeOf(bestSupertypeDownfallType, bestSupertype, errorLocation, + Diagnostics.Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0, + errorMessageChainHead); + } + + function isArrayType(type: Type): boolean { + return type.flags & TypeFlags.Reference && (type).target === globalArrayType; + } + + function isArrayLikeType(type: Type): boolean { + // A type is array-like if it is not the undefined or null type and if it is assignable to any[] + return !(type.flags & (TypeFlags.Undefined | TypeFlags.Null)) && isTypeAssignableTo(type, anyArrayType); + } + + function isTupleLikeType(type: Type): boolean { + return !!getPropertyOfType(type, "0"); + } + + /** + * Check if a Type was written as a tuple type literal. + * Prefer using isTupleLikeType() unless the use of `elementTypes` is required. + */ + function isTupleType(type: Type): boolean { + return (type.flags & TypeFlags.Tuple) && !!(type).elementTypes; + } + + function getWidenedTypeOfObjectLiteral(type: Type): Type { + let properties = getPropertiesOfObjectType(type); + let members: SymbolTable = {}; + forEach(properties, p => { + let propType = getTypeOfSymbol(p); + let widenedType = getWidenedType(propType); + if (propType !== widenedType) { + let symbol = createSymbol(p.flags | SymbolFlags.Transient, p.name); + symbol.declarations = p.declarations; + symbol.parent = p.parent; + symbol.type = widenedType; + symbol.target = p; + if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration; + p = symbol; + } + members[p.name] = p; + }); + let stringIndexType = getIndexTypeOfType(type, IndexKind.String); + let numberIndexType = getIndexTypeOfType(type, IndexKind.Number); + if (stringIndexType) stringIndexType = getWidenedType(stringIndexType); + if (numberIndexType) numberIndexType = getWidenedType(numberIndexType); + return createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexType, numberIndexType); + } + + function getWidenedType(type: Type): Type { + if (type.flags & TypeFlags.RequiresWidening) { + if (type.flags & (TypeFlags.Undefined | TypeFlags.Null)) { + return anyType; + } + if (type.flags & TypeFlags.ObjectLiteral) { + return getWidenedTypeOfObjectLiteral(type); + } + if (type.flags & TypeFlags.Union) { + return getUnionType(map((type).types, getWidenedType)); + } + if (isArrayType(type)) { + return createArrayType(getWidenedType((type).typeArguments[0])); + } + } + return type; + } + + function reportWideningErrorsInType(type: Type): boolean { + if (type.flags & TypeFlags.Union) { + let errorReported = false; + forEach((type).types, t => { + if (reportWideningErrorsInType(t)) { + errorReported = true; + } + }); + return errorReported; + } + if (isArrayType(type)) { + return reportWideningErrorsInType((type).typeArguments[0]); + } + if (type.flags & TypeFlags.ObjectLiteral) { + let errorReported = false; + forEach(getPropertiesOfObjectType(type), p => { + let t = getTypeOfSymbol(p); + if (t.flags & TypeFlags.ContainsUndefinedOrNull) { + if (!reportWideningErrorsInType(t)) { + error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(getWidenedType(t))); + } + errorReported = true; + } + }); + return errorReported; + } + return false; + } + + function reportImplicitAnyError(declaration: Declaration, type: Type) { + let typeAsString = typeToString(getWidenedType(type)); + let diagnostic: DiagnosticMessage; + switch (declaration.kind) { + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + diagnostic = Diagnostics.Member_0_implicitly_has_an_1_type; + break; + case SyntaxKind.Parameter: + diagnostic = (declaration).dotDotDotToken ? + Diagnostics.Rest_parameter_0_implicitly_has_an_any_type : + Diagnostics.Parameter_0_implicitly_has_an_1_type; + break; + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + if (!declaration.name) { + error(declaration, Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString); + return; + } + diagnostic = Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type; + break; + default: + diagnostic = Diagnostics.Variable_0_implicitly_has_an_1_type; + } + error(declaration, diagnostic, declarationNameToString(declaration.name), typeAsString); + } + + function reportErrorsFromWidening(declaration: Declaration, type: Type) { + if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsUndefinedOrNull) { + // Report implicit any error within type if possible, otherwise report error on declaration + if (!reportWideningErrorsInType(type)) { + reportImplicitAnyError(declaration, type); + } + } + } + + function forEachMatchingParameterType(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) { + let sourceMax = source.parameters.length; + let targetMax = target.parameters.length; + let count: number; + if (source.hasRestParameter && target.hasRestParameter) { + count = sourceMax > targetMax ? sourceMax : targetMax; + sourceMax--; + targetMax--; + } + else if (source.hasRestParameter) { + sourceMax--; + count = targetMax; + } + else if (target.hasRestParameter) { + targetMax--; + count = sourceMax; + } + else { + count = sourceMax < targetMax ? sourceMax : targetMax; + } + for (let i = 0; i < count; i++) { + let s = i < sourceMax ? getTypeOfSymbol(source.parameters[i]) : getRestTypeOfSignature(source); + let t = i < targetMax ? getTypeOfSymbol(target.parameters[i]) : getRestTypeOfSignature(target); + callback(s, t); + } + } + + function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext { + let inferences: TypeInferences[] = []; + for (let unused of typeParameters) { + inferences.push({ primary: undefined, secondary: undefined, isFixed: false }); + } + return { + typeParameters, + inferUnionTypes, + inferences, + inferredTypes: new Array(typeParameters.length), + }; + } + + function inferTypes(context: InferenceContext, source: Type, target: Type) { + let sourceStack: Type[]; + let targetStack: Type[]; + let depth = 0; + let inferiority = 0; + inferFromTypes(source, target); + + function isInProcess(source: Type, target: Type) { + for (let i = 0; i < depth; i++) { + if (source === sourceStack[i] && target === targetStack[i]) { + return true; + } + } + return false; + } + + function isWithinDepthLimit(type: Type, stack: Type[]) { + if (depth >= 5) { + let target = (type).target; + let count = 0; + for (let i = 0; i < depth; i++) { + let t = stack[i]; + if (t.flags & TypeFlags.Reference && (t).target === target) { + count++; + } + } + return count < 5; + } + return true; + } + + function inferFromTypes(source: Type, target: Type) { + if (source === anyFunctionType) { + return; + } + if (target.flags & TypeFlags.TypeParameter) { + // If target is a type parameter, make an inference + let typeParameters = context.typeParameters; + for (let i = 0; i < typeParameters.length; i++) { + if (target === typeParameters[i]) { + let inferences = context.inferences[i]; + if (!inferences.isFixed) { + // Any inferences that are made to a type parameter in a union type are inferior + // to inferences made to a flat (non-union) type. This is because if we infer to + // T | string[], we really don't know if we should be inferring to T or not (because + // the correct constituent on the target side could be string[]). Therefore, we put + // such inferior inferences into a secondary bucket, and only use them if the primary + // bucket is empty. + let candidates = inferiority ? + inferences.secondary || (inferences.secondary = []) : + inferences.primary || (inferences.primary = []); + if (!contains(candidates, source)) { + candidates.push(source); + } + } + return; + } + } + } + else if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (source).target === (target).target) { + // If source and target are references to the same generic type, infer from type arguments + let sourceTypes = (source).typeArguments; + let targetTypes = (target).typeArguments; + for (let i = 0; i < sourceTypes.length; i++) { + inferFromTypes(sourceTypes[i], targetTypes[i]); + } + } + else if (target.flags & TypeFlags.Union) { + let targetTypes = (target).types; + let typeParameterCount = 0; + let typeParameter: TypeParameter; + // First infer to each type in union that isn't a type parameter + for (let t of targetTypes) { + if (t.flags & TypeFlags.TypeParameter && contains(context.typeParameters, t)) { + typeParameter = t; + typeParameterCount++; + } + else { + inferFromTypes(source, t); + } + } + // If union contains a single naked type parameter, make a secondary inference to that type parameter + if (typeParameterCount === 1) { + inferiority++; + inferFromTypes(source, typeParameter); + inferiority--; + } + } + else if (source.flags & TypeFlags.Union) { + // Source is a union type, infer from each consituent type + let sourceTypes = (source).types; + for (let sourceType of sourceTypes) { + inferFromTypes(sourceType, target); + } + } + else if (source.flags & TypeFlags.ObjectType && (target.flags & (TypeFlags.Reference | TypeFlags.Tuple) || + (target.flags & TypeFlags.Anonymous) && target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral))) { + // If source is an object type, and target is a type reference, a tuple type, the type of a method, or a type literal, infer from members + if (!isInProcess(source, target) && isWithinDepthLimit(source, sourceStack) && isWithinDepthLimit(target, targetStack)) { + if (depth === 0) { + sourceStack = []; + targetStack = []; + } + sourceStack[depth] = source; + targetStack[depth] = target; + depth++; + inferFromProperties(source, target); + inferFromSignatures(source, target, SignatureKind.Call); + inferFromSignatures(source, target, SignatureKind.Construct); + inferFromIndexTypes(source, target, IndexKind.String, IndexKind.String); + inferFromIndexTypes(source, target, IndexKind.Number, IndexKind.Number); + inferFromIndexTypes(source, target, IndexKind.String, IndexKind.Number); + depth--; + } + } + } + + function inferFromProperties(source: Type, target: Type) { + let properties = getPropertiesOfObjectType(target); + for (let targetProp of properties) { + let sourceProp = getPropertyOfObjectType(source, targetProp.name); + if (sourceProp) { + inferFromTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); + } + } + } + + function inferFromSignatures(source: Type, target: Type, kind: SignatureKind) { + let sourceSignatures = getSignaturesOfType(source, kind); + let targetSignatures = getSignaturesOfType(target, kind); + let sourceLen = sourceSignatures.length; + let targetLen = targetSignatures.length; + let len = sourceLen < targetLen ? sourceLen : targetLen; + for (let i = 0; i < len; i++) { + inferFromSignature(getErasedSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i])); + } + } + + function inferFromSignature(source: Signature, target: Signature) { + forEachMatchingParameterType(source, target, inferFromTypes); + inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + } + + function inferFromIndexTypes(source: Type, target: Type, sourceKind: IndexKind, targetKind: IndexKind) { + let targetIndexType = getIndexTypeOfType(target, targetKind); + if (targetIndexType) { + let sourceIndexType = getIndexTypeOfType(source, sourceKind); + if (sourceIndexType) { + inferFromTypes(sourceIndexType, targetIndexType); + } + } + } + } + + function getInferenceCandidates(context: InferenceContext, index: number): Type[] { + let inferences = context.inferences[index]; + return inferences.primary || inferences.secondary || emptyArray; + } + + function getInferredType(context: InferenceContext, index: number): Type { + let inferredType = context.inferredTypes[index]; + let inferenceSucceeded: boolean; + if (!inferredType) { + let inferences = getInferenceCandidates(context, index); + if (inferences.length) { + // Infer widened union or supertype, or the unknown type for no common supertype + let unionOrSuperType = context.inferUnionTypes ? getUnionType(inferences) : getCommonSupertype(inferences); + inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType; + inferenceSucceeded = !!unionOrSuperType; + } + else { + // Infer the empty object type when no inferences were made. It is important to remember that + // in this case, inference still succeeds, meaning there is no error for not having inference + // candidates. An inference error only occurs when there are *conflicting* candidates, i.e. + // candidates with no common supertype. + inferredType = emptyObjectType; + inferenceSucceeded = true; + } + + // Only do the constraint check if inference succeeded (to prevent cascading errors) + if (inferenceSucceeded) { + let constraint = getConstraintOfTypeParameter(context.typeParameters[index]); + inferredType = constraint && !isTypeAssignableTo(inferredType, constraint) ? constraint : inferredType; + } + else if (context.failedTypeParameterIndex === undefined || context.failedTypeParameterIndex > index) { + // If inference failed, it is necessary to record the index of the failed type parameter (the one we are on). + // It might be that inference has already failed on a later type parameter on a previous call to inferTypeArguments. + // So if this failure is on preceding type parameter, this type parameter is the new failure index. + context.failedTypeParameterIndex = index; + } + context.inferredTypes[index] = inferredType; + } + return inferredType; + } + + function getInferredTypes(context: InferenceContext): Type[] { + for (let i = 0; i < context.inferredTypes.length; i++) { + getInferredType(context, i); + } + + return context.inferredTypes; + } + + function hasAncestor(node: Node, kind: SyntaxKind): boolean { + return getAncestor(node, kind) !== undefined; + } + + // EXPRESSION TYPE CHECKING + + function getResolvedSymbol(node: Identifier): Symbol { + let links = getNodeLinks(node); + if (!links.resolvedSymbol) { + links.resolvedSymbol = (!nodeIsMissing(node) && resolveName(node, node.text, SymbolFlags.Value | SymbolFlags.ExportValue, Diagnostics.Cannot_find_name_0, node)) || unknownSymbol; + } + return links.resolvedSymbol; + } + + function isInTypeQuery(node: Node): boolean { + // TypeScript 1.0 spec (April 2014): 3.6.3 + // A type query consists of the keyword typeof followed by an expression. + // The expression is restricted to a single identifier or a sequence of identifiers separated by periods + while (node) { + switch (node.kind) { + case SyntaxKind.TypeQuery: + return true; + case SyntaxKind.Identifier: + case SyntaxKind.QualifiedName: + node = node.parent; + continue; + default: + return false; + } + } + Debug.fail("should not get here"); + } + + // For a union type, remove all constituent types that are of the given type kind (when isOfTypeKind is true) + // or not of the given type kind (when isOfTypeKind is false) + function removeTypesFromUnionType(type: Type, typeKind: TypeFlags, isOfTypeKind: boolean, allowEmptyUnionResult: boolean): Type { + if (type.flags & TypeFlags.Union) { + let types = (type).types; + if (forEach(types, t => !!(t.flags & typeKind) === isOfTypeKind)) { + // Above we checked if we have anything to remove, now use the opposite test to do the removal + let narrowedType = getUnionType(filter(types, t => !(t.flags & typeKind) === isOfTypeKind)); + if (allowEmptyUnionResult || narrowedType !== emptyObjectType) { + return narrowedType; + } + } + } + else if (allowEmptyUnionResult && !!(type.flags & typeKind) === isOfTypeKind) { + // Use getUnionType(emptyArray) instead of emptyObjectType in case the way empty union types + // are represented ever changes. + return getUnionType(emptyArray); + } + return type; + } + + function hasInitializer(node: VariableLikeDeclaration): boolean { + return !!(node.initializer || isBindingPattern(node.parent) && hasInitializer(node.parent.parent)); + } + + // Check if a given variable is assigned within a given syntax node + function isVariableAssignedWithin(symbol: Symbol, node: Node): boolean { + let links = getNodeLinks(node); + if (links.assignmentChecks) { + let cachedResult = links.assignmentChecks[symbol.id]; + if (cachedResult !== undefined) { + return cachedResult; + } + } + else { + links.assignmentChecks = {}; + } + return links.assignmentChecks[symbol.id] = isAssignedIn(node); + + function isAssignedInBinaryExpression(node: BinaryExpression) { + if (node.operatorToken.kind >= SyntaxKind.FirstAssignment && node.operatorToken.kind <= SyntaxKind.LastAssignment) { + let n = node.left; + while (n.kind === SyntaxKind.ParenthesizedExpression) { + n = (n).expression; + } + if (n.kind === SyntaxKind.Identifier && getResolvedSymbol(n) === symbol) { + return true; + } + } + return forEachChild(node, isAssignedIn); + } + + function isAssignedInVariableDeclaration(node: VariableLikeDeclaration) { + if (!isBindingPattern(node.name) && getSymbolOfNode(node) === symbol && hasInitializer(node)) { + return true; + } + return forEachChild(node, isAssignedIn); + } + + function isAssignedIn(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.BinaryExpression: + return isAssignedInBinaryExpression(node); + case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: + return isAssignedInVariableDeclaration(node); + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.PrefixUnaryExpression: + case SyntaxKind.DeleteExpression: + case SyntaxKind.TypeOfExpression: + case SyntaxKind.VoidExpression: + case SyntaxKind.PostfixUnaryExpression: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.SpreadElementExpression: + case SyntaxKind.Block: + case SyntaxKind.VariableStatement: + case SyntaxKind.ExpressionStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.ReturnStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + case SyntaxKind.LabeledStatement: + case SyntaxKind.ThrowStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.CatchClause: + return forEachChild(node, isAssignedIn); + } + return false; + } + } + + function resolveLocation(node: Node) { + // Resolve location from top down towards node if it is a context sensitive expression + // That helps in making sure not assigning types as any when resolved out of order + let containerNodes: Node[] = []; + for (let parent = node.parent; parent; parent = parent.parent) { + if ((isExpression(parent) || isObjectLiteralMethod(node)) && + isContextSensitive(parent)) { + containerNodes.unshift(parent); + } + } + + ts.forEach(containerNodes, node => { getTypeOfNode(node); }); + } + + function getSymbolAtLocation(node: Node): Symbol { + resolveLocation(node); + return getSymbolInfo(node); + } + + function getTypeAtLocation(node: Node): Type { + resolveLocation(node); + return getTypeOfNode(node); + } + + function getTypeOfSymbolAtLocation(symbol: Symbol, node: Node): Type { + resolveLocation(node); + // Get the narrowed type of symbol at given location instead of just getting + // the type of the symbol. + // eg. + // function foo(a: string | number) { + // if (typeof a === "string") { + // a/**/ + // } + // } + // getTypeOfSymbol for a would return type of parameter symbol string | number + // Unless we provide location /**/, checker wouldn't know how to narrow the type + // By using getNarrowedTypeOfSymbol would return string since it would be able to narrow + // it by typeguard in the if true condition + return getNarrowedTypeOfSymbol(symbol, node); + } + + // Get the narrowed type of a given symbol at a given location + function getNarrowedTypeOfSymbol(symbol: Symbol, node: Node) { + let type = getTypeOfSymbol(symbol); + // Only narrow when symbol is variable of type any or an object, union, or type parameter type + if (node && symbol.flags & SymbolFlags.Variable && type.flags & (TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.Union | TypeFlags.TypeParameter)) { + loop: while (node.parent) { + let child = node; + node = node.parent; + let narrowedType = type; + switch (node.kind) { + case SyntaxKind.IfStatement: + // In a branch of an if statement, narrow based on controlling expression + if (child !== (node).expression) { + narrowedType = narrowType(type, (node).expression, /*assumeTrue*/ child === (node).thenStatement); + } + break; + case SyntaxKind.ConditionalExpression: + // In a branch of a conditional expression, narrow based on controlling condition + if (child !== (node).condition) { + narrowedType = narrowType(type, (node).condition, /*assumeTrue*/ child === (node).whenTrue); + } + break; + case SyntaxKind.BinaryExpression: + // In the right operand of an && or ||, narrow based on left operand + if (child === (node).right) { + if ((node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { + narrowedType = narrowType(type, (node).left, /*assumeTrue*/ true); + } + else if ((node).operatorToken.kind === SyntaxKind.BarBarToken) { + narrowedType = narrowType(type, (node).left, /*assumeTrue*/ false); + } + } + break; + case SyntaxKind.SourceFile: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.Constructor: + // Stop at the first containing function or module declaration + break loop; + } + // Use narrowed type if construct contains no assignments to variable + if (narrowedType !== type) { + if (isVariableAssignedWithin(symbol, node)) { + break; + } + type = narrowedType; + } + } + } + return type; + + function narrowTypeByEquality(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { + // Check that we have 'typeof ' on the left and string literal on the right + if (expr.left.kind !== SyntaxKind.TypeOfExpression || expr.right.kind !== SyntaxKind.StringLiteral) { + return type; + } + let left = expr.left; + let right = expr.right; + if (left.expression.kind !== SyntaxKind.Identifier || getResolvedSymbol(left.expression) !== symbol) { + return type; + } + let typeInfo = primitiveTypeInfo[right.text]; + if (expr.operatorToken.kind === SyntaxKind.ExclamationEqualsEqualsToken) { + assumeTrue = !assumeTrue; + } + if (assumeTrue) { + // Assumed result is true. If check was not for a primitive type, remove all primitive types + if (!typeInfo) { + return removeTypesFromUnionType(type, /*typeKind*/ TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.Boolean | TypeFlags.ESSymbol, + /*isOfTypeKind*/ true, /*allowEmptyUnionResult*/ false); + } + // Check was for a primitive type, return that primitive type if it is a subtype + if (isTypeSubtypeOf(typeInfo.type, type)) { + return typeInfo.type; + } + // Otherwise, remove all types that aren't of the primitive type kind. This can happen when the type is + // union of enum types and other types. + return removeTypesFromUnionType(type, /*typeKind*/ typeInfo.flags, /*isOfTypeKind*/ false, /*allowEmptyUnionResult*/ false); + } + else { + // Assumed result is false. If check was for a primitive type, remove that primitive type + if (typeInfo) { + return removeTypesFromUnionType(type, /*typeKind*/ typeInfo.flags, /*isOfTypeKind*/ true, /*allowEmptyUnionResult*/ false); + } + // Otherwise we don't have enough information to do anything. + return type; + } + } + + function narrowTypeByAnd(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { + if (assumeTrue) { + // The assumed result is true, therefore we narrow assuming each operand to be true. + return narrowType(narrowType(type, expr.left, /*assumeTrue*/ true), expr.right, /*assumeTrue*/ true); + } + else { + // The assumed result is false. This means either the first operand was false, or the first operand was true + // and the second operand was false. We narrow with those assumptions and union the two resulting types. + return getUnionType([ + narrowType(type, expr.left, /*assumeTrue*/ false), + narrowType(narrowType(type, expr.left, /*assumeTrue*/ true), expr.right, /*assumeTrue*/ false) + ]); + } + } + + function narrowTypeByOr(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { + if (assumeTrue) { + // The assumed result is true. This means either the first operand was true, or the first operand was false + // and the second operand was true. We narrow with those assumptions and union the two resulting types. + return getUnionType([ + narrowType(type, expr.left, /*assumeTrue*/ true), + narrowType(narrowType(type, expr.left, /*assumeTrue*/ false), expr.right, /*assumeTrue*/ true) + ]); + } + else { + // The assumed result is false, therefore we narrow assuming each operand to be false. + return narrowType(narrowType(type, expr.left, /*assumeTrue*/ false), expr.right, /*assumeTrue*/ false); + } + } + + function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { + // Check that type is not any, assumed result is true, and we have variable symbol on the left + if (type.flags & TypeFlags.Any || !assumeTrue || expr.left.kind !== SyntaxKind.Identifier || getResolvedSymbol(expr.left) !== symbol) { + return type; + } + // Check that right operand is a function type with a prototype property + let rightType = checkExpression(expr.right); + if (!isTypeSubtypeOf(rightType, globalFunctionType)) { + return type; + } + // Target type is type of prototype property + let prototypeProperty = getPropertyOfType(rightType, "prototype"); + if (!prototypeProperty) { + return type; + } + let targetType = getTypeOfSymbol(prototypeProperty); + // Narrow to target type if it is a subtype of current type + if (isTypeSubtypeOf(targetType, type)) { + return targetType; + } + // If current type is a union type, remove all constituents that aren't subtypes of target type + if (type.flags & TypeFlags.Union) { + return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, targetType))); + } + return type; + } + + // Narrow the given type based on the given expression having the assumed boolean value. The returned type + // will be a subtype or the same type as the argument. + function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type { + switch (expr.kind) { + case SyntaxKind.ParenthesizedExpression: + return narrowType(type, (expr).expression, assumeTrue); + case SyntaxKind.BinaryExpression: + let operator = (expr).operatorToken.kind; + if (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) { + return narrowTypeByEquality(type, expr, assumeTrue); + } + else if (operator === SyntaxKind.AmpersandAmpersandToken) { + return narrowTypeByAnd(type, expr, assumeTrue); + } + else if (operator === SyntaxKind.BarBarToken) { + return narrowTypeByOr(type, expr, assumeTrue); + } + else if (operator === SyntaxKind.InstanceOfKeyword) { + return narrowTypeByInstanceof(type, expr, assumeTrue); + } + break; + case SyntaxKind.PrefixUnaryExpression: + if ((expr).operator === SyntaxKind.ExclamationToken) { + return narrowType(type, (expr).operand, !assumeTrue); + } + break; + } + return type; + } + } + + function checkIdentifier(node: Identifier): Type { + let symbol = getResolvedSymbol(node); + + // As noted in ECMAScript 6 language spec, arrow functions never have an arguments objects. + // Although in down-level emit of arrow function, we emit it using function expression which means that + // arguments objects will be bound to the inner object; emitting arrow function natively in ES6, arguments objects + // will be bound to non-arrow function that contain this arrow function. This results in inconsistent behavior. + // To avoid that we will give an error to users if they use arguments objects in arrow function so that they + // can explicitly bound arguments objects + if (symbol === argumentsSymbol && getContainingFunction(node).kind === SyntaxKind.ArrowFunction && languageVersion < ScriptTarget.ES6) { + error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression); + } + + if (symbol.flags & SymbolFlags.Alias && !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(symbol))) { + markAliasSymbolAsReferenced(symbol); + } + + checkCollisionWithCapturedSuperVariable(node, node); + checkCollisionWithCapturedThisVariable(node, node); + checkBlockScopedBindingCapturedInLoop(node, symbol); + + return getNarrowedTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol), node); + } + + function isInsideFunction(node: Node, threshold: Node): boolean { + let current = node; + while (current && current !== threshold) { + if (isFunctionLike(current)) { + return true; + } + current = current.parent; + } + + return false; + } + + function checkBlockScopedBindingCapturedInLoop(node: Identifier, symbol: Symbol): void { + if (languageVersion >= ScriptTarget.ES6 || + (symbol.flags & SymbolFlags.BlockScopedVariable) === 0 || + symbol.valueDeclaration.parent.kind === SyntaxKind.CatchClause) { + return; + } + + // - check if binding is used in some function + // (stop the walk when reaching container of binding declaration) + // - if first check succeeded - check if variable is declared inside the loop + + // nesting structure: + // (variable declaration or binding element) -> variable declaration list -> container + let container: Node = symbol.valueDeclaration; + while (container.kind !== SyntaxKind.VariableDeclarationList) { + container = container.parent; + } + // get the parent of variable declaration list + container = container.parent; + if (container.kind === SyntaxKind.VariableStatement) { + // if parent is variable statement - get its parent + container = container.parent; + } + + let inFunction = isInsideFunction(node.parent, container); + + let current = container; + while (current && !nodeStartsNewLexicalEnvironment(current)) { + if (isIterationStatement(current, /*lookInLabeledStatements*/ false)) { + if (inFunction) { + grammarErrorOnFirstToken(current, Diagnostics.Loop_contains_block_scoped_variable_0_referenced_by_a_function_in_the_loop_This_is_only_supported_in_ECMAScript_6_or_higher, declarationNameToString(node)); + } + // mark value declaration so during emit they can have a special handling + getNodeLinks(symbol.valueDeclaration).flags |= NodeCheckFlags.BlockScopedBindingInLoop; + break; + } + current = current.parent; + } + } + + function captureLexicalThis(node: Node, container: Node): void { + let classNode = container.parent && container.parent.kind === SyntaxKind.ClassDeclaration ? container.parent : undefined; + getNodeLinks(node).flags |= NodeCheckFlags.LexicalThis; + if (container.kind === SyntaxKind.PropertyDeclaration || container.kind === SyntaxKind.Constructor) { + getNodeLinks(classNode).flags |= NodeCheckFlags.CaptureThis; + } + else { + getNodeLinks(container).flags |= NodeCheckFlags.CaptureThis; + } + } + + function checkThisExpression(node: Node): Type { + // Stop at the first arrow function so that we can + // tell whether 'this' needs to be captured. + let container = getThisContainer(node, /* includeArrowFunctions */ true); + let needToCaptureLexicalThis = false; + + // Now skip arrow functions to get the "real" owner of 'this'. + if (container.kind === SyntaxKind.ArrowFunction) { + container = getThisContainer(container, /* includeArrowFunctions */ false); + + // When targeting es6, arrow function lexically bind "this" so we do not need to do the work of binding "this" in emitted code + needToCaptureLexicalThis = (languageVersion < ScriptTarget.ES6); + } + + switch (container.kind) { + case SyntaxKind.ModuleDeclaration: + error(node, Diagnostics.this_cannot_be_referenced_in_a_module_body); + // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks + break; + case SyntaxKind.EnumDeclaration: + error(node, Diagnostics.this_cannot_be_referenced_in_current_location); + // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks + break; + case SyntaxKind.Constructor: + if (isInConstructorArgumentInitializer(node, container)) { + error(node, Diagnostics.this_cannot_be_referenced_in_constructor_arguments); + // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks + } + break; + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + if (container.flags & NodeFlags.Static) { + error(node, Diagnostics.this_cannot_be_referenced_in_a_static_property_initializer); + // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks + } + break; + case SyntaxKind.ComputedPropertyName: + error(node, Diagnostics.this_cannot_be_referenced_in_a_computed_property_name); + break; + } + + if (needToCaptureLexicalThis) { + captureLexicalThis(node, container); + } + + let classNode = container.parent && container.parent.kind === SyntaxKind.ClassDeclaration ? container.parent : undefined; + if (classNode) { + let symbol = getSymbolOfNode(classNode); + return container.flags & NodeFlags.Static ? getTypeOfSymbol(symbol) : getDeclaredTypeOfSymbol(symbol); + } + return anyType; + } + + function isInConstructorArgumentInitializer(node: Node, constructorDecl: Node): boolean { + for (let n = node; n && n !== constructorDecl; n = n.parent) { + if (n.kind === SyntaxKind.Parameter) { + return true; + } + } + return false; + } + + function checkSuperExpression(node: Node): Type { + let isCallExpression = node.parent.kind === SyntaxKind.CallExpression && (node.parent).expression === node; + let enclosingClass = getAncestor(node, SyntaxKind.ClassDeclaration); + let baseClass: Type; + if (enclosingClass && getClassExtendsHeritageClauseElement(enclosingClass)) { + let classType = getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClass)); + let baseTypes = getBaseTypes(classType); + baseClass = baseTypes.length && baseTypes[0]; + } + + if (!baseClass) { + error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class); + return unknownType; + } + + let container = getSuperContainer(node, /*includeFunctions*/ true); + + if (container) { + let canUseSuperExpression = false; + let needToCaptureLexicalThis: boolean; + if (isCallExpression) { + // TS 1.0 SPEC (April 2014): 4.8.1 + // Super calls are only permitted in constructors of derived classes + canUseSuperExpression = container.kind === SyntaxKind.Constructor; + } + else { + // TS 1.0 SPEC (April 2014) + // 'super' property access is allowed + // - In a constructor, instance member function, instance member accessor, or instance member variable initializer where this references a derived class instance + // - In a static member function or static member accessor + + // super property access might appear in arrow functions with arbitrary deep nesting + needToCaptureLexicalThis = false; + while (container && container.kind === SyntaxKind.ArrowFunction) { + container = getSuperContainer(container, /*includeFunctions*/ true); + needToCaptureLexicalThis = languageVersion < ScriptTarget.ES6; + } + + // topmost container must be something that is directly nested in the class declaration + if (container && container.parent && container.parent.kind === SyntaxKind.ClassDeclaration) { + if (container.flags & NodeFlags.Static) { + canUseSuperExpression = + container.kind === SyntaxKind.MethodDeclaration || + container.kind === SyntaxKind.MethodSignature || + container.kind === SyntaxKind.GetAccessor || + container.kind === SyntaxKind.SetAccessor; + } + else { + canUseSuperExpression = + container.kind === SyntaxKind.MethodDeclaration || + container.kind === SyntaxKind.MethodSignature || + container.kind === SyntaxKind.GetAccessor || + container.kind === SyntaxKind.SetAccessor || + container.kind === SyntaxKind.PropertyDeclaration || + container.kind === SyntaxKind.PropertySignature || + container.kind === SyntaxKind.Constructor; + } + } + } + + if (canUseSuperExpression) { + let returnType: Type; + + if ((container.flags & NodeFlags.Static) || isCallExpression) { + getNodeLinks(node).flags |= NodeCheckFlags.SuperStatic; + returnType = getTypeOfSymbol(baseClass.symbol); + } + else { + getNodeLinks(node).flags |= NodeCheckFlags.SuperInstance; + returnType = baseClass; + } + + if (container.kind === SyntaxKind.Constructor && isInConstructorArgumentInitializer(node, container)) { + // issue custom error message for super property access in constructor arguments (to be aligned with old compiler) + error(node, Diagnostics.super_cannot_be_referenced_in_constructor_arguments); + returnType = unknownType; + } + + if (!isCallExpression && needToCaptureLexicalThis) { + // call expressions are allowed only in constructors so they should always capture correct 'this' + // super property access expressions can also appear in arrow functions - + // in this case they should also use correct lexical this + captureLexicalThis(node.parent, container); + } + + return returnType; + } + } + + if (container && container.kind === SyntaxKind.ComputedPropertyName) { + error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name); + } + else if (isCallExpression) { + error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors); + } + else { + error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class); + } + + return unknownType; + } + + // Return contextual type of parameter or undefined if no contextual type is available + function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type { + if (isFunctionExpressionOrArrowFunction(parameter.parent)) { + let func = parameter.parent; + if (isContextSensitive(func)) { + let contextualSignature = getContextualSignature(func); + if (contextualSignature) { + + let funcHasRestParameters = hasRestParameters(func); + let len = func.parameters.length - (funcHasRestParameters ? 1 : 0); + let indexOfParameter = indexOf(func.parameters, parameter); + if (indexOfParameter < len) { + return getTypeAtPosition(contextualSignature, indexOfParameter); + } + + // If last parameter is contextually rest parameter get its type + if (indexOfParameter === (func.parameters.length - 1) && + funcHasRestParameters && contextualSignature.hasRestParameter && func.parameters.length >= contextualSignature.parameters.length) { + return getTypeOfSymbol(contextualSignature.parameters[contextualSignature.parameters.length - 1]); + } + } + } + } + return undefined; + } + + // In a variable, parameter or property declaration with a type annotation, the contextual type of an initializer + // expression is the type of the variable, parameter or property. Otherwise, in a parameter declaration of a + // contextually typed function expression, the contextual type of an initializer expression is the contextual type + // of the parameter. Otherwise, in a variable or parameter declaration with a binding pattern name, the contextual + // type of an initializer expression is the type implied by the binding pattern. + function getContextualTypeForInitializerExpression(node: Expression): Type { + let declaration = node.parent; + if (node === declaration.initializer) { + if (declaration.type) { + return getTypeFromTypeNode(declaration.type); + } + if (declaration.kind === SyntaxKind.Parameter) { + let type = getContextuallyTypedParameterType(declaration); + if (type) { + return type; + } + } + if (isBindingPattern(declaration.name)) { + return getTypeFromBindingPattern(declaration.name); + } + } + return undefined; + } + + function getContextualTypeForReturnExpression(node: Expression): Type { + let func = getContainingFunction(node); + if (func) { + // If the containing function has a return type annotation, is a constructor, or is a get accessor whose + // corresponding set accessor has a type annotation, return statements in the function are contextually typed + if (func.type || func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(func.symbol, SyntaxKind.SetAccessor))) { + return getReturnTypeOfSignature(getSignatureFromDeclaration(func)); + } + // Otherwise, if the containing function is contextually typed by a function type with exactly one call signature + // and that call signature is non-generic, return statements are contextually typed by the return type of the signature + let signature = getContextualSignatureForFunctionLikeDeclaration(func); + if (signature) { + return getReturnTypeOfSignature(signature); + } + } + return undefined; + } + + // In a typed function call, an argument or substitution expression is contextually typed by the type of the corresponding parameter. + function getContextualTypeForArgument(callTarget: CallLikeExpression, arg: Expression): Type { + let args = getEffectiveCallArguments(callTarget); + let argIndex = indexOf(args, arg); + if (argIndex >= 0) { + let signature = getResolvedSignature(callTarget); + return getTypeAtPosition(signature, argIndex); + } + return undefined; + } + + function getContextualTypeForSubstitutionExpression(template: TemplateExpression, substitutionExpression: Expression) { + if (template.parent.kind === SyntaxKind.TaggedTemplateExpression) { + return getContextualTypeForArgument(template.parent, substitutionExpression); + } + + return undefined; + } + + function getContextualTypeForBinaryOperand(node: Expression): Type { + let binaryExpression = node.parent; + let operator = binaryExpression.operatorToken.kind; + if (operator >= SyntaxKind.FirstAssignment && operator <= SyntaxKind.LastAssignment) { + // In an assignment expression, the right operand is contextually typed by the type of the left operand. + if (node === binaryExpression.right) { + return checkExpression(binaryExpression.left); + } + } + else if (operator === SyntaxKind.BarBarToken) { + // When an || expression has a contextual type, the operands are contextually typed by that type. When an || + // expression has no contextual type, the right operand is contextually typed by the type of the left operand. + let type = getContextualType(binaryExpression); + if (!type && node === binaryExpression.right) { + type = checkExpression(binaryExpression.left); + } + return type; + } + return undefined; + } + + // Apply a mapping function to a contextual type and return the resulting type. If the contextual type + // is a union type, the mapping function is applied to each constituent type and a union of the resulting + // types is returned. + function applyToContextualType(type: Type, mapper: (t: Type) => Type): Type { + if (!(type.flags & TypeFlags.Union)) { + return mapper(type); + } + let types = (type).types; + let mappedType: Type; + let mappedTypes: Type[]; + for (let current of types) { + let t = mapper(current); + if (t) { + if (!mappedType) { + mappedType = t; + } + else if (!mappedTypes) { + mappedTypes = [mappedType, t]; + } + else { + mappedTypes.push(t); + } + } + } + return mappedTypes ? getUnionType(mappedTypes) : mappedType; + } + + function getTypeOfPropertyOfContextualType(type: Type, name: string) { + return applyToContextualType(type, t => { + let prop = getPropertyOfObjectType(t, name); + return prop ? getTypeOfSymbol(prop) : undefined; + }); + } + + function getIndexTypeOfContextualType(type: Type, kind: IndexKind) { + return applyToContextualType(type, t => getIndexTypeOfObjectOrUnionType(t, kind)); + } + + // Return true if the given contextual type is a tuple-like type + function contextualTypeIsTupleLikeType(type: Type): boolean { + return !!(type.flags & TypeFlags.Union ? forEach((type).types, isTupleLikeType) : isTupleLikeType(type)); + } + + // Return true if the given contextual type provides an index signature of the given kind + function contextualTypeHasIndexSignature(type: Type, kind: IndexKind): boolean { + return !!(type.flags & TypeFlags.Union ? forEach((type).types, t => getIndexTypeOfObjectOrUnionType(t, kind)) : getIndexTypeOfObjectOrUnionType(type, kind)); + } + + // In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of + // the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one + // exists. Otherwise, it is the type of the string index signature in T, if one exists. + function getContextualTypeForObjectLiteralMethod(node: MethodDeclaration): Type { + Debug.assert(isObjectLiteralMethod(node)); + if (isInsideWithStatementBody(node)) { + // We cannot answer semantic questions within a with block, do not proceed any further + return undefined; + } + + return getContextualTypeForObjectLiteralElement(node); + } + + function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElement) { + let objectLiteral = element.parent; + let type = getContextualType(objectLiteral); + if (type) { + if (!hasDynamicName(element)) { + // For a (non-symbol) computed property, there is no reason to look up the name + // in the type. It will just be "__computed", which does not appear in any + // SymbolTable. + let symbolName = getSymbolOfNode(element).name; + let propertyType = getTypeOfPropertyOfContextualType(type, symbolName); + if (propertyType) { + return propertyType; + } + } + + return isNumericName(element.name) && getIndexTypeOfContextualType(type, IndexKind.Number) || + getIndexTypeOfContextualType(type, IndexKind.String); + } + + return undefined; + } + + // In an array literal contextually typed by a type T, the contextual type of an element expression at index N is + // the type of the property with the numeric name N in T, if one exists. Otherwise, if T has a numeric index signature, + // it is the type of the numeric index signature in T. Otherwise, in ES6 and higher, the contextual type is the iterated + // type of T. + function getContextualTypeForElementExpression(node: Expression): Type { + let arrayLiteral = node.parent; + let type = getContextualType(arrayLiteral); + if (type) { + let index = indexOf(arrayLiteral.elements, node); + return getTypeOfPropertyOfContextualType(type, "" + index) + || getIndexTypeOfContextualType(type, IndexKind.Number) + || (languageVersion >= ScriptTarget.ES6 ? checkIteratedType(type, /*expressionForError*/ undefined) : undefined); + } + return undefined; + } + + // In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type. + function getContextualTypeForConditionalOperand(node: Expression): Type { + let conditional = node.parent; + return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined; + } + + // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily + // be "pushed" onto a node using the contextualType property. + function getContextualType(node: Expression): Type { + if (isInsideWithStatementBody(node)) { + // We cannot answer semantic questions within a with block, do not proceed any further + return undefined; + } + if (node.contextualType) { + return node.contextualType; + } + let parent = node.parent; + switch (parent.kind) { + case SyntaxKind.VariableDeclaration: + case SyntaxKind.Parameter: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.BindingElement: + return getContextualTypeForInitializerExpression(node); + case SyntaxKind.ArrowFunction: + case SyntaxKind.ReturnStatement: + return getContextualTypeForReturnExpression(node); + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + return getContextualTypeForArgument(parent, node); + case SyntaxKind.TypeAssertionExpression: + return getTypeFromTypeNode((parent).type); + case SyntaxKind.BinaryExpression: + return getContextualTypeForBinaryOperand(node); + case SyntaxKind.PropertyAssignment: + return getContextualTypeForObjectLiteralElement(parent); + case SyntaxKind.ArrayLiteralExpression: + return getContextualTypeForElementExpression(node); + case SyntaxKind.ConditionalExpression: + return getContextualTypeForConditionalOperand(node); + case SyntaxKind.TemplateSpan: + Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression); + return getContextualTypeForSubstitutionExpression(parent.parent, node); + case SyntaxKind.ParenthesizedExpression: + return getContextualType(parent); + } + return undefined; + } + + // If the given type is an object or union type, if that type has a single signature, and if + // that signature is non-generic, return the signature. Otherwise return undefined. + function getNonGenericSignature(type: Type): Signature { + let signatures = getSignaturesOfObjectOrUnionType(type, SignatureKind.Call); + if (signatures.length === 1) { + let signature = signatures[0]; + if (!signature.typeParameters) { + return signature; + } + } + } + + function isFunctionExpressionOrArrowFunction(node: Node): boolean { + return node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction; + } + + function getContextualSignatureForFunctionLikeDeclaration(node: FunctionLikeDeclaration): Signature { + // Only function expressions and arrow functions are contextually typed. + return isFunctionExpressionOrArrowFunction(node) ? getContextualSignature(node) : undefined; + } + + // Return the contextual signature for a given expression node. A contextual type provides a + // contextual signature if it has a single call signature and if that call signature is non-generic. + // If the contextual type is a union type, get the signature from each type possible and if they are + // all identical ignoring their return type, the result is same signature but with return type as + // union type of return types from these signatures + function getContextualSignature(node: FunctionExpression | MethodDeclaration): Signature { + Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + let type = isObjectLiteralMethod(node) + ? getContextualTypeForObjectLiteralMethod(node) + : getContextualType(node); + if (!type) { + return undefined; + } + if (!(type.flags & TypeFlags.Union)) { + return getNonGenericSignature(type); + } + let signatureList: Signature[]; + let types = (type).types; + for (let current of types) { + // The signature set of all constituent type with call signatures should match + // So number of signatures allowed is either 0 or 1 + if (signatureList && + getSignaturesOfObjectOrUnionType(current, SignatureKind.Call).length > 1) { + return undefined; + } + + let signature = getNonGenericSignature(current); + if (signature) { + if (!signatureList) { + // This signature will contribute to contextual union signature + signatureList = [signature]; + } + else if (!compareSignatures(signatureList[0], signature, /*compareReturnTypes*/ false, compareTypes)) { + // Signatures aren't identical, do not use + return undefined; + } + else { + // Use this signature for contextual union signature + signatureList.push(signature); + } + } + } + + // Result is union of signatures collected (return type is union of return types of this signature set) + let result: Signature; + if (signatureList) { + result = cloneSignature(signatureList[0]); + // Clear resolved return type we possibly got from cloneSignature + result.resolvedReturnType = undefined; + result.unionSignatures = signatureList; + } + return result; + } + + // Presence of a contextual type mapper indicates inferential typing, except the identityMapper object is + // used as a special marker for other purposes. + function isInferentialContext(mapper: TypeMapper) { + return mapper && mapper !== identityMapper; + } + + // A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property + // assignment in an object literal that is an assignment target, or if it is parented by an array literal that is + // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'. + function isAssignmentTarget(node: Node): boolean { + let parent = node.parent; + if (parent.kind === SyntaxKind.BinaryExpression && (parent).operatorToken.kind === SyntaxKind.EqualsToken && (parent).left === node) { + return true; + } + if (parent.kind === SyntaxKind.PropertyAssignment) { + return isAssignmentTarget(parent.parent); + } + if (parent.kind === SyntaxKind.ArrayLiteralExpression) { + return isAssignmentTarget(parent); + } + return false; + } + + function checkSpreadElementExpression(node: SpreadElementExpression, contextualMapper?: TypeMapper): Type { + // It is usually not safe to call checkExpressionCached if we can be contextually typing. + // You can tell that we are contextually typing because of the contextualMapper parameter. + // While it is true that a spread element can have a contextual type, it does not do anything + // with this type. It is neither affected by it, nor does it propagate it to its operand. + // So the fact that contextualMapper is passed is not important, because the operand of a spread + // element is not contextually typed. + let arrayOrIterableType = checkExpressionCached(node.expression, contextualMapper); + return checkIteratedTypeOrElementType(arrayOrIterableType, node.expression, /*allowStringInput*/ false); + } + + function checkArrayLiteral(node: ArrayLiteralExpression, contextualMapper?: TypeMapper): Type { + let elements = node.elements; + if (!elements.length) { + return createArrayType(undefinedType); + } + let hasSpreadElement = false; + let elementTypes: Type[] = []; + let inDestructuringPattern = isAssignmentTarget(node); + for (let e of elements) { + if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElementExpression) { + // Given the following situation: + // var c: {}; + // [...c] = ["", 0]; + // + // c is represented in the tree as a spread element in an array literal. + // But c really functions as a rest element, and its purpose is to provide + // a contextual type for the right hand side of the assignment. Therefore, + // instead of calling checkExpression on "...c", which will give an error + // if c is not iterable/array-like, we need to act as if we are trying to + // get the contextual element type from it. So we do something similar to + // getContextualTypeForElementExpression, which will crucially not error + // if there is no index type / iterated type. + let restArrayType = checkExpression((e).expression, contextualMapper); + let restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) || + (languageVersion >= ScriptTarget.ES6 ? checkIteratedType(restArrayType, /*expressionForError*/ undefined) : undefined); + + if (restElementType) { + elementTypes.push(restElementType); + } + } + else { + let type = checkExpression(e, contextualMapper); + elementTypes.push(type); + } + hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElementExpression; + } + if (!hasSpreadElement) { + let contextualType = getContextualType(node); + if (contextualType && contextualTypeIsTupleLikeType(contextualType) || inDestructuringPattern) { + return createTupleType(elementTypes); + } + } + return createArrayType(getUnionType(elementTypes)); + } + + function isNumericName(name: DeclarationName): boolean { + return name.kind === SyntaxKind.ComputedPropertyName ? isNumericComputedName(name) : isNumericLiteralName((name).text); + } + + function isNumericComputedName(name: ComputedPropertyName): boolean { + // It seems odd to consider an expression of type Any to result in a numeric name, + // but this behavior is consistent with checkIndexedAccess + return allConstituentTypesHaveKind(checkComputedPropertyName(name), TypeFlags.Any | TypeFlags.NumberLike); + } + + function isNumericLiteralName(name: string) { + // The intent of numeric names is that + // - they are names with text in a numeric form, and that + // - setting properties/indexing with them is always equivalent to doing so with the numeric literal 'numLit', + // acquired by applying the abstract 'ToNumber' operation on the name's text. + // + // The subtlety is in the latter portion, as we cannot reliably say that anything that looks like a numeric literal is a numeric name. + // In fact, it is the case that the text of the name must be equal to 'ToString(numLit)' for this to hold. + // + // Consider the property name '"0xF00D"'. When one indexes with '0xF00D', they are actually indexing with the value of 'ToString(0xF00D)' + // according to the ECMAScript specification, so it is actually as if the user indexed with the string '"61453"'. + // Thus, the text of all numeric literals equivalent to '61543' such as '0xF00D', '0xf00D', '0170015', etc. are not valid numeric names + // because their 'ToString' representation is not equal to their original text. + // This is motivated by ECMA-262 sections 9.3.1, 9.8.1, 11.1.5, and 11.2.1. + // + // Here, we test whether 'ToString(ToNumber(name))' is exactly equal to 'name'. + // The '+' prefix operator is equivalent here to applying the abstract ToNumber operation. + // Applying the 'toString()' method on a number gives us the abstract ToString operation on a number. + // + // Note that this accepts the values 'Infinity', '-Infinity', and 'NaN', and that this is intentional. + // This is desired behavior, because when indexing with them as numeric entities, you are indexing + // with the strings '"Infinity"', '"-Infinity"', and '"NaN"' respectively. + return (+name).toString() === name; + } + + function checkComputedPropertyName(node: ComputedPropertyName): Type { + let links = getNodeLinks(node.expression); + if (!links.resolvedType) { + links.resolvedType = checkExpression(node.expression); + + // This will allow types number, string, symbol or any. It will also allow enums, the unknown + // type, and any union of these types (like string | number). + if (!allConstituentTypesHaveKind(links.resolvedType, TypeFlags.Any | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.ESSymbol)) { + error(node, Diagnostics.A_computed_property_name_must_be_of_type_string_number_symbol_or_any); + } + else { + checkThatExpressionIsProperSymbolReference(node.expression, links.resolvedType, /*reportError*/ true); + } + } + + return links.resolvedType; + } + + function checkObjectLiteral(node: ObjectLiteralExpression, contextualMapper?: TypeMapper): Type { + // Grammar checking + checkGrammarObjectLiteralExpression(node); + + let propertiesTable: SymbolTable = {}; + let propertiesArray: Symbol[] = []; + let contextualType = getContextualType(node); + let typeFlags: TypeFlags; + + for (let memberDecl of node.properties) { + let member = memberDecl.symbol; + if (memberDecl.kind === SyntaxKind.PropertyAssignment || + memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment || + isObjectLiteralMethod(memberDecl)) { + let type: Type; + if (memberDecl.kind === SyntaxKind.PropertyAssignment) { + type = checkPropertyAssignment(memberDecl, contextualMapper); + } + else if (memberDecl.kind === SyntaxKind.MethodDeclaration) { + type = checkObjectLiteralMethod(memberDecl, contextualMapper); + } + else { + Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment); + type = checkExpression((memberDecl).name, contextualMapper); + } + typeFlags |= type.flags; + let prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name); + prop.declarations = member.declarations; + prop.parent = member.parent; + if (member.valueDeclaration) { + prop.valueDeclaration = member.valueDeclaration; + } + + prop.type = type; + prop.target = member; + member = prop; + } + else { + // TypeScript 1.0 spec (April 2014) + // A get accessor declaration is processed in the same manner as + // an ordinary function declaration(section 6.1) with no parameters. + // A set accessor declaration is processed in the same manner + // as an ordinary function declaration with a single parameter and a Void return type. + Debug.assert(memberDecl.kind === SyntaxKind.GetAccessor || memberDecl.kind === SyntaxKind.SetAccessor); + checkAccessorDeclaration(memberDecl); + } + + if (!hasDynamicName(memberDecl)) { + propertiesTable[member.name] = member; + } + propertiesArray.push(member); + } + + let stringIndexType = getIndexType(IndexKind.String); + let numberIndexType = getIndexType(IndexKind.Number); + let result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType); + result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull); + return result; + + function getIndexType(kind: IndexKind) { + if (contextualType && contextualTypeHasIndexSignature(contextualType, kind)) { + let propTypes: Type[] = []; + for (let i = 0; i < propertiesArray.length; i++) { + let propertyDecl = node.properties[i]; + if (kind === IndexKind.String || isNumericName(propertyDecl.name)) { + // Do not call getSymbolOfNode(propertyDecl), as that will get the + // original symbol for the node. We actually want to get the symbol + // created by checkObjectLiteral, since that will be appropriately + // contextually typed and resolved. + let type = getTypeOfSymbol(propertiesArray[i]); + if (!contains(propTypes, type)) { + propTypes.push(type); + } + } + } + let result = propTypes.length ? getUnionType(propTypes) : undefinedType; + typeFlags |= result.flags; + return result; + } + return undefined; + } + } + + // If a symbol is a synthesized symbol with no value declaration, we assume it is a property. Example of this are the synthesized + // '.prototype' property as well as synthesized tuple index properties. + function getDeclarationKindFromSymbol(s: Symbol) { + return s.valueDeclaration ? s.valueDeclaration.kind : SyntaxKind.PropertyDeclaration; + } + + function getDeclarationFlagsFromSymbol(s: Symbol) { + return s.valueDeclaration ? getCombinedNodeFlags(s.valueDeclaration) : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0; + } + + function checkClassPropertyAccess(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, type: Type, prop: Symbol) { + let flags = getDeclarationFlagsFromSymbol(prop); + // Public properties are always accessible + if (!(flags & (NodeFlags.Private | NodeFlags.Protected))) { + return; + } + // Property is known to be private or protected at this point + // Get the declaring and enclosing class instance types + let enclosingClassDeclaration = getAncestor(node, SyntaxKind.ClassDeclaration); + let enclosingClass = enclosingClassDeclaration ? getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClassDeclaration)) : undefined; + let declaringClass = getDeclaredTypeOfSymbol(prop.parent); + // Private property is accessible if declaring and enclosing class are the same + if (flags & NodeFlags.Private) { + if (declaringClass !== enclosingClass) { + error(node, Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, symbolToString(prop), typeToString(declaringClass)); + } + return; + } + // Property is known to be protected at this point + // All protected properties of a supertype are accessible in a super access + if (left.kind === SyntaxKind.SuperKeyword) { + return; + } + // A protected property is accessible in the declaring class and classes derived from it + if (!enclosingClass || !hasBaseType(enclosingClass, declaringClass)) { + error(node, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(declaringClass)); + return; + } + // No further restrictions for static properties + if (flags & NodeFlags.Static) { + return; + } + // An instance property must be accessed through an instance of the enclosing class + if (!(getTargetType(type).flags & (TypeFlags.Class | TypeFlags.Interface) && hasBaseType(type, enclosingClass))) { + error(node, Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1, symbolToString(prop), typeToString(enclosingClass)); + } + } + + function checkPropertyAccessExpression(node: PropertyAccessExpression) { + return checkPropertyAccessExpressionOrQualifiedName(node, node.expression, node.name); + } + + function checkQualifiedName(node: QualifiedName) { + return checkPropertyAccessExpressionOrQualifiedName(node, node.left, node.right); + } + + function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) { + let type = checkExpressionOrQualifiedName(left); + if (type === unknownType) return type; + if (type !== anyType) { + let apparentType = getApparentType(getWidenedType(type)); + if (apparentType === unknownType) { + // handle cases when type is Type parameter with invalid constraint + return unknownType; + } + let prop = getPropertyOfType(apparentType, right.text); + if (!prop) { + if (right.text) { + error(right, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(right), typeToString(type)); + } + return unknownType; + } + getNodeLinks(node).resolvedSymbol = prop; + if (prop.parent && prop.parent.flags & SymbolFlags.Class) { + // TS 1.0 spec (April 2014): 4.8.2 + // - In a constructor, instance member function, instance member accessor, or + // instance member variable initializer where this references a derived class instance, + // a super property access is permitted and must specify a public instance member function of the base class. + // - In a static member function or static member accessor + // where this references the constructor function object of a derived class, + // a super property access is permitted and must specify a public static member function of the base class. + if (left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) { + error(right, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); + } + else { + checkClassPropertyAccess(node, left, type, prop); + } + } + return getTypeOfSymbol(prop); + } + return anyType; + } + + function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean { + let left = node.kind === SyntaxKind.PropertyAccessExpression + ? (node).expression + : (node).left; + + let type = checkExpressionOrQualifiedName(left); + if (type !== unknownType && type !== anyType) { + let prop = getPropertyOfType(getWidenedType(type), propertyName); + if (prop && prop.parent && prop.parent.flags & SymbolFlags.Class) { + if (left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) { + return false; + } + else { + let modificationCount = diagnostics.getModificationCount(); + checkClassPropertyAccess(node, left, type, prop); + return diagnostics.getModificationCount() === modificationCount; + } + } + } + return true; + } + + function checkIndexedAccess(node: ElementAccessExpression): Type { + // Grammar checking + if (!node.argumentExpression) { + let sourceFile = getSourceFile(node); + if (node.parent.kind === SyntaxKind.NewExpression && (node.parent).expression === node) { + let start = skipTrivia(sourceFile.text, node.expression.end); + let end = node.end; + grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead); + } + else { + let start = node.end - "]".length; + let end = node.end; + grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.Expression_expected); + } + } + + // Obtain base constraint such that we can bail out if the constraint is an unknown type + let objectType = getApparentType(checkExpression(node.expression)); + let indexType = node.argumentExpression ? checkExpression(node.argumentExpression) : unknownType; + + if (objectType === unknownType) { + return unknownType; + } + + let isConstEnum = isConstEnumObjectType(objectType); + if (isConstEnum && + (!node.argumentExpression || node.argumentExpression.kind !== SyntaxKind.StringLiteral)) { + error(node.argumentExpression, Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal); + return unknownType; + } + + // TypeScript 1.0 spec (April 2014): 4.10 Property Access + // - If IndexExpr is a string literal or a numeric literal and ObjExpr's apparent type has a property with the name + // given by that literal(converted to its string representation in the case of a numeric literal), the property access is of the type of that property. + // - Otherwise, if ObjExpr's apparent type has a numeric index signature and IndexExpr is of type Any, the Number primitive type, or an enum type, + // the property access is of the type of that index signature. + // - Otherwise, if ObjExpr's apparent type has a string index signature and IndexExpr is of type Any, the String or Number primitive type, or an enum type, + // the property access is of the type of that index signature. + // - Otherwise, if IndexExpr is of type Any, the String or Number primitive type, or an enum type, the property access is of type Any. + + // See if we can index as a property. + if (node.argumentExpression) { + let name = getPropertyNameForIndexedAccess(node.argumentExpression, indexType); + if (name !== undefined) { + let prop = getPropertyOfType(objectType, name); + if (prop) { + getNodeLinks(node).resolvedSymbol = prop; + return getTypeOfSymbol(prop); + } + else if (isConstEnum) { + error(node.argumentExpression, Diagnostics.Property_0_does_not_exist_on_const_enum_1, name, symbolToString(objectType.symbol)); + return unknownType; + } + } + } + + // Check for compatible indexer types. + if (allConstituentTypesHaveKind(indexType, TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbol)) { + + // Try to use a number indexer. + if (allConstituentTypesHaveKind(indexType, TypeFlags.Any | TypeFlags.NumberLike)) { + let numberIndexType = getIndexTypeOfType(objectType, IndexKind.Number); + if (numberIndexType) { + return numberIndexType; + } + } + + // Try to use string indexing. + let stringIndexType = getIndexTypeOfType(objectType, IndexKind.String); + if (stringIndexType) { + return stringIndexType; + } + + // Fall back to any. + if (compilerOptions.noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && objectType !== anyType) { + error(node, Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type); + } + + return anyType; + } + + // REVIEW: Users should know the type that was actually used. + error(node, Diagnostics.An_index_expression_argument_must_be_of_type_string_number_symbol_or_any); + + return unknownType; + } + + /** + * If indexArgumentExpression is a string literal or number literal, returns its text. + * If indexArgumentExpression is a well known symbol, returns the property name corresponding + * to this symbol, as long as it is a proper symbol reference. + * Otherwise, returns undefined. + */ + function getPropertyNameForIndexedAccess(indexArgumentExpression: Expression, indexArgumentType: Type): string { + if (indexArgumentExpression.kind === SyntaxKind.StringLiteral || indexArgumentExpression.kind === SyntaxKind.NumericLiteral) { + return (indexArgumentExpression).text; + } + if (checkThatExpressionIsProperSymbolReference(indexArgumentExpression, indexArgumentType, /*reportError*/ false)) { + let rightHandSideName = ((indexArgumentExpression).name).text; + return getPropertyNameForKnownSymbolName(rightHandSideName); + } + + return undefined; + } + + /** + * A proper symbol reference requires the following: + * 1. The property access denotes a property that exists + * 2. The expression is of the form Symbol. + * 3. The property access is of the primitive type symbol. + * 4. Symbol in this context resolves to the global Symbol object + */ + function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean { + if (expressionType === unknownType) { + // There is already an error, so no need to report one. + return false; + } + + if (!isWellKnownSymbolSyntactically(expression)) { + return false; + } + + // Make sure the property type is the primitive symbol type + if ((expressionType.flags & TypeFlags.ESSymbol) === 0) { + if (reportError) { + error(expression, Diagnostics.A_computed_property_name_of_the_form_0_must_be_of_type_symbol, getTextOfNode(expression)); + } + return false; + } + + // The name is Symbol., so make sure Symbol actually resolves to the + // global Symbol object + let leftHandSide = (expression).expression; + let leftHandSideSymbol = getResolvedSymbol(leftHandSide); + if (!leftHandSideSymbol) { + return false; + } + + let globalESSymbol = getGlobalESSymbolConstructorSymbol(); + if (!globalESSymbol) { + // Already errored when we tried to look up the symbol + return false; + } + + if (leftHandSideSymbol !== globalESSymbol) { + if (reportError) { + error(leftHandSide, Diagnostics.Symbol_reference_does_not_refer_to_the_global_Symbol_constructor_object); + } + return false; + } + + return true; + } + + function resolveUntypedCall(node: CallLikeExpression): Signature { + if (node.kind === SyntaxKind.TaggedTemplateExpression) { + checkExpression((node).template); + } + else { + forEach((node).arguments, argument => { + checkExpression(argument); + }); + } + return anySignature; + } + + function resolveErrorCall(node: CallLikeExpression): Signature { + resolveUntypedCall(node); + return unknownSignature; + } + + // Re-order candidate signatures into the result array. Assumes the result array to be empty. + // The candidate list orders groups in reverse, but within a group signatures are kept in declaration order + // A nit here is that we reorder only signatures that belong to the same symbol, + // so order how inherited signatures are processed is still preserved. + // interface A { (x: string): void } + // interface B extends A { (x: 'foo'): string } + // let b: B; + // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void] + function reorderCandidates(signatures: Signature[], result: Signature[]): void { + let lastParent: Node; + let lastSymbol: Symbol; + let cutoffIndex: number = 0; + let index: number; + let specializedIndex: number = -1; + let spliceIndex: number; + Debug.assert(!result.length); + for (let signature of signatures) { + let symbol = signature.declaration && getSymbolOfNode(signature.declaration); + let parent = signature.declaration && signature.declaration.parent; + if (!lastSymbol || symbol === lastSymbol) { + if (lastParent && parent === lastParent) { + index++; + } + else { + lastParent = parent; + index = cutoffIndex; + } + } + else { + // current declaration belongs to a different symbol + // set cutoffIndex so re-orderings in the future won't change result set from 0 to cutoffIndex + index = cutoffIndex = result.length; + lastParent = parent; + } + lastSymbol = symbol; + + // specialized signatures always need to be placed before non-specialized signatures regardless + // of the cutoff position; see GH#1133 + if (signature.hasStringLiterals) { + specializedIndex++; + spliceIndex = specializedIndex; + // The cutoff index always needs to be greater than or equal to the specialized signature index + // in order to prevent non-specialized signatures from being added before a specialized + // signature. + cutoffIndex++; + } + else { + spliceIndex = index; + } + + result.splice(spliceIndex, 0, signature); + } + } + + function getSpreadArgumentIndex(args: Expression[]): number { + for (let i = 0; i < args.length; i++) { + if (args[i].kind === SyntaxKind.SpreadElementExpression) { + return i; + } + } + return -1; + } + + function hasCorrectArity(node: CallLikeExpression, args: Expression[], signature: Signature) { + let adjustedArgCount: number; // Apparent number of arguments we will have in this call + let typeArguments: NodeArray; // Type arguments (undefined if none) + let callIsIncomplete: boolean; // In incomplete call we want to be lenient when we have too few arguments + + if (node.kind === SyntaxKind.TaggedTemplateExpression) { + let tagExpression = node; + + // Even if the call is incomplete, we'll have a missing expression as our last argument, + // so we can say the count is just the arg list length + adjustedArgCount = args.length; + typeArguments = undefined; + + if (tagExpression.template.kind === SyntaxKind.TemplateExpression) { + // If a tagged template expression lacks a tail literal, the call is incomplete. + // Specifically, a template only can end in a TemplateTail or a Missing literal. + let templateExpression = tagExpression.template; + let lastSpan = lastOrUndefined(templateExpression.templateSpans); + Debug.assert(lastSpan !== undefined); // we should always have at least one span. + callIsIncomplete = nodeIsMissing(lastSpan.literal) || !!lastSpan.literal.isUnterminated; + } + else { + // If the template didn't end in a backtick, or its beginning occurred right prior to EOF, + // then this might actually turn out to be a TemplateHead in the future; + // so we consider the call to be incomplete. + let templateLiteral = tagExpression.template; + Debug.assert(templateLiteral.kind === SyntaxKind.NoSubstitutionTemplateLiteral); + callIsIncomplete = !!templateLiteral.isUnterminated; + } + } + else { + let callExpression = node; + if (!callExpression.arguments) { + // This only happens when we have something of the form: 'new C' + Debug.assert(callExpression.kind === SyntaxKind.NewExpression); + + return signature.minArgumentCount === 0; + } + + // For IDE scenarios we may have an incomplete call, so a trailing comma is tantamount to adding another argument. + adjustedArgCount = callExpression.arguments.hasTrailingComma ? args.length + 1 : args.length; + + // If we are missing the close paren, the call is incomplete. + callIsIncomplete = (callExpression).arguments.end === callExpression.end; + + typeArguments = callExpression.typeArguments; + } + + // If the user supplied type arguments, but the number of type arguments does not match + // the declared number of type parameters, the call has an incorrect arity. + let hasRightNumberOfTypeArgs = !typeArguments || + (signature.typeParameters && typeArguments.length === signature.typeParameters.length); + if (!hasRightNumberOfTypeArgs) { + return false; + } + + // If spread arguments are present, check that they correspond to a rest parameter. If so, no + // further checking is necessary. + let spreadArgIndex = getSpreadArgumentIndex(args); + if (spreadArgIndex >= 0) { + return signature.hasRestParameter && spreadArgIndex >= signature.parameters.length - 1; + } + + // Too many arguments implies incorrect arity. + if (!signature.hasRestParameter && adjustedArgCount > signature.parameters.length) { + return false; + } + + // If the call is incomplete, we should skip the lower bound check. + let hasEnoughArguments = adjustedArgCount >= signature.minArgumentCount; + return callIsIncomplete || hasEnoughArguments; + } + + // If type has a single call signature and no other members, return that signature. Otherwise, return undefined. + function getSingleCallSignature(type: Type): Signature { + if (type.flags & TypeFlags.ObjectType) { + let resolved = resolveObjectOrUnionTypeMembers(type); + if (resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0 && + resolved.properties.length === 0 && !resolved.stringIndexType && !resolved.numberIndexType) { + return resolved.callSignatures[0]; + } + } + return undefined; + } + + // Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec) + function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper: TypeMapper): Signature { + let context = createInferenceContext(signature.typeParameters, /*inferUnionTypes*/ true); + forEachMatchingParameterType(contextualSignature, signature, (source, target) => { + // Type parameters from outer context referenced by source type are fixed by instantiation of the source type + inferTypes(context, instantiateType(source, contextualMapper), target); + }); + return getSignatureInstantiation(signature, getInferredTypes(context)); + } + + function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[], context: InferenceContext): void { + let typeParameters = signature.typeParameters; + let inferenceMapper = createInferenceMapper(context); + + // Clear out all the inference results from the last time inferTypeArguments was called on this context + for (let i = 0; i < typeParameters.length; i++) { + // As an optimization, we don't have to clear (and later recompute) inferred types + // for type parameters that have already been fixed on the previous call to inferTypeArguments. + // It would be just as correct to reset all of them. But then we'd be repeating the same work + // for the type parameters that were fixed, namely the work done by getInferredType. + if (!context.inferences[i].isFixed) { + context.inferredTypes[i] = undefined; + } + } + + // On this call to inferTypeArguments, we may get more inferences for certain type parameters that were not + // fixed last time. This means that a type parameter that failed inference last time may succeed this time, + // or vice versa. Therefore, the failedTypeParameterIndex is useless if it points to an unfixed type parameter, + // because it may change. So here we reset it. However, getInferredType will not revisit any type parameters + // that were previously fixed. So if a fixed type parameter failed previously, it will fail again because + // it will contain the exact same set of inferences. So if we reset the index from a fixed type parameter, + // we will lose information that we won't recover this time around. + if (context.failedTypeParameterIndex !== undefined && !context.inferences[context.failedTypeParameterIndex].isFixed) { + context.failedTypeParameterIndex = undefined; + } + + // We perform two passes over the arguments. In the first pass we infer from all arguments, but use + // wildcards for all context sensitive function expressions. + for (let i = 0; i < args.length; i++) { + let arg = args[i]; + if (arg.kind !== SyntaxKind.OmittedExpression) { + let paramType = getTypeAtPosition(signature, i); + let argType: Type; + if (i === 0 && args[i].parent.kind === SyntaxKind.TaggedTemplateExpression) { + argType = globalTemplateStringsArrayType; + } + else { + // For context sensitive arguments we pass the identityMapper, which is a signal to treat all + // context sensitive function expressions as wildcards + let mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper; + argType = checkExpressionWithContextualType(arg, paramType, mapper); + } + inferTypes(context, argType, paramType); + } + } + + // In the second pass we visit only context sensitive arguments, and only those that aren't excluded, this + // time treating function expressions normally (which may cause previously inferred type arguments to be fixed + // as we construct types for contextually typed parameters) + if (excludeArgument) { + for (let i = 0; i < args.length; i++) { + // No need to check for omitted args and template expressions, their exlusion value is always undefined + if (excludeArgument[i] === false) { + let arg = args[i]; + let paramType = getTypeAtPosition(signature, i); + inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType); + } + } + } + + getInferredTypes(context); + } + + function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean): boolean { + let typeParameters = signature.typeParameters; + let typeArgumentsAreAssignable = true; + for (let i = 0; i < typeParameters.length; i++) { + let typeArgNode = typeArguments[i]; + let typeArgument = getTypeFromTypeNode(typeArgNode); + // Do not push on this array! It has a preallocated length + typeArgumentResultTypes[i] = typeArgument; + if (typeArgumentsAreAssignable /* so far */) { + let constraint = getConstraintOfTypeParameter(typeParameters[i]); + if (constraint) { + typeArgumentsAreAssignable = checkTypeAssignableTo(typeArgument, constraint, reportErrors ? typeArgNode : undefined, + Diagnostics.Type_0_does_not_satisfy_the_constraint_1); + } + } + } + return typeArgumentsAreAssignable; + } + + function checkApplicableSignature(node: CallLikeExpression, args: Expression[], signature: Signature, relation: Map, excludeArgument: boolean[], reportErrors: boolean) { + for (let i = 0; i < args.length; i++) { + let arg = args[i]; + if (arg.kind !== SyntaxKind.OmittedExpression) { + // Check spread elements against rest type (from arity check we know spread argument corresponds to a rest parameter) + let paramType = getTypeAtPosition(signature, i); + // A tagged template expression provides a special first argument, and string literals get string literal types + // unless we're reporting errors + let argType = i === 0 && node.kind === SyntaxKind.TaggedTemplateExpression + ? globalTemplateStringsArrayType + : arg.kind === SyntaxKind.StringLiteral && !reportErrors + ? getStringLiteralType(arg) + : checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined); + + // Use argument expression as error location when reporting errors + if (!checkTypeRelatedTo(argType, paramType, relation, reportErrors ? arg : undefined, + Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1)) { + return false; + } + } + } + return true; + } + + /** + * Returns the effective arguments for an expression that works like a function invocation. + * + * If 'node' is a CallExpression or a NewExpression, then its argument list is returned. + * If 'node' is a TaggedTemplateExpression, a new argument list is constructed from the substitution + * expressions, where the first element of the list is the template for error reporting purposes. + */ + function getEffectiveCallArguments(node: CallLikeExpression): Expression[] { + let args: Expression[]; + if (node.kind === SyntaxKind.TaggedTemplateExpression) { + let template = (node).template; + args = [template]; + + if (template.kind === SyntaxKind.TemplateExpression) { + forEach((template).templateSpans, span => { + args.push(span.expression); + }); + } + } + else { + args = (node).arguments || emptyArray; + } + + return args; + } + + /** + * In a 'super' call, type arguments are not provided within the CallExpression node itself. + * Instead, they must be fetched from the class declaration's base type node. + * + * If 'node' is a 'super' call (e.g. super(...), new super(...)), then we attempt to fetch + * the type arguments off the containing class's first heritage clause (if one exists). Note that if + * type arguments are supplied on the 'super' call, they are ignored (though this is syntactically incorrect). + * + * In all other cases, the call's explicit type arguments are returned. + */ + function getEffectiveTypeArguments(callExpression: CallExpression): TypeNode[] { + if (callExpression.expression.kind === SyntaxKind.SuperKeyword) { + let containingClass = getAncestor(callExpression, SyntaxKind.ClassDeclaration); + let baseClassTypeNode = containingClass && getClassExtendsHeritageClauseElement(containingClass); + return baseClassTypeNode && baseClassTypeNode.typeArguments; + } + else { + // Ordinary case - simple function invocation. + return callExpression.typeArguments; + } + } + + function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[]): Signature { + let isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; + + let typeArguments: TypeNode[]; + + if (!isTaggedTemplate) { + typeArguments = getEffectiveTypeArguments(node); + + // We already perform checking on the type arguments on the class declaration itself. + if ((node).expression.kind !== SyntaxKind.SuperKeyword) { + forEach(typeArguments, checkSourceElement); + } + } + + let candidates = candidatesOutArray || []; + // reorderCandidates fills up the candidates array directly + reorderCandidates(signatures, candidates); + if (!candidates.length) { + error(node, Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target); + return resolveErrorCall(node); + } + + let args = getEffectiveCallArguments(node); + + // The following applies to any value of 'excludeArgument[i]': + // - true: the argument at 'i' is susceptible to a one-time permanent contextual typing. + // - undefined: the argument at 'i' is *not* susceptible to permanent contextual typing. + // - false: the argument at 'i' *was* and *has been* permanently contextually typed. + // + // The idea is that we will perform type argument inference & assignability checking once + // without using the susceptible parameters that are functions, and once more for each of those + // parameters, contextually typing each as we go along. + // + // For a tagged template, then the first argument be 'undefined' if necessary + // because it represents a TemplateStringsArray. + let excludeArgument: boolean[]; + for (let i = isTaggedTemplate ? 1 : 0; i < args.length; i++) { + if (isContextSensitive(args[i])) { + if (!excludeArgument) { + excludeArgument = new Array(args.length); + } + excludeArgument[i] = true; + } + } + + // The following variables are captured and modified by calls to chooseOverload. + // If overload resolution or type argument inference fails, we want to report the + // best error possible. The best error is one which says that an argument was not + // assignable to a parameter. This implies that everything else about the overload + // was fine. So if there is any overload that is only incorrect because of an + // argument, we will report an error on that one. + // + // function foo(s: string) {} + // function foo(n: number) {} // Report argument error on this overload + // function foo() {} + // foo(true); + // + // If none of the overloads even made it that far, there are two possibilities. + // There was a problem with type arguments for some overload, in which case + // report an error on that. Or none of the overloads even had correct arity, + // in which case give an arity error. + // + // function foo(x: T, y: T) {} // Report type argument inference error + // function foo() {} + // foo(0, true); + // + let candidateForArgumentError: Signature; + let candidateForTypeArgumentError: Signature; + let resultOfFailedInference: InferenceContext; + let result: Signature; + + // Section 4.12.1: + // if the candidate list contains one or more signatures for which the type of each argument + // expression is a subtype of each corresponding parameter type, the return type of the first + // of those signatures becomes the return type of the function call. + // Otherwise, the return type of the first signature in the candidate list becomes the return + // type of the function call. + // + // Whether the call is an error is determined by assignability of the arguments. The subtype pass + // is just important for choosing the best signature. So in the case where there is only one + // signature, the subtype pass is useless. So skipping it is an optimization. + if (candidates.length > 1) { + result = chooseOverload(candidates, subtypeRelation); + } + if (!result) { + // Reinitialize these pointers for round two + candidateForArgumentError = undefined; + candidateForTypeArgumentError = undefined; + resultOfFailedInference = undefined; + result = chooseOverload(candidates, assignableRelation); + } + if (result) { + return result; + } + + // No signatures were applicable. Now report errors based on the last applicable signature with + // no arguments excluded from assignability checks. + // If candidate is undefined, it means that no candidates had a suitable arity. In that case, + // skip the checkApplicableSignature check. + if (candidateForArgumentError) { + // excludeArgument is undefined, in this case also equivalent to [undefined, undefined, ...] + // The importance of excludeArgument is to prevent us from typing function expression parameters + // in arguments too early. If possible, we'd like to only type them once we know the correct + // overload. However, this matters for the case where the call is correct. When the call is + // an error, we don't need to exclude any arguments, although it would cause no harm to do so. + checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true); + } + else if (candidateForTypeArgumentError) { + if (!isTaggedTemplate && (node).typeArguments) { + checkTypeArguments(candidateForTypeArgumentError, (node).typeArguments, [], /*reportErrors*/ true) + } + else { + Debug.assert(resultOfFailedInference.failedTypeParameterIndex >= 0); + let failedTypeParameter = candidateForTypeArgumentError.typeParameters[resultOfFailedInference.failedTypeParameterIndex]; + let inferenceCandidates = getInferenceCandidates(resultOfFailedInference, resultOfFailedInference.failedTypeParameterIndex); + + let diagnosticChainHead = chainDiagnosticMessages(/*details*/ undefined, // details will be provided by call to reportNoCommonSupertypeError + Diagnostics.The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly, + typeToString(failedTypeParameter)); + + reportNoCommonSupertypeError(inferenceCandidates, (node).expression || (node).tag, diagnosticChainHead); + } + } + else { + error(node, Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target); + } + + // No signature was applicable. We have already reported the errors for the invalid signature. + // If this is a type resolution session, e.g. Language Service, try to get better information that anySignature. + // Pick the first candidate that matches the arity. This way we can get a contextual type for cases like: + // declare function f(a: { xa: number; xb: number; }); + // f({ | + if (!produceDiagnostics) { + for (let candidate of candidates) { + if (hasCorrectArity(node, args, candidate)) { + return candidate; + } + } + } + + return resolveErrorCall(node); + + function chooseOverload(candidates: Signature[], relation: Map) { + for (let originalCandidate of candidates) { + if (!hasCorrectArity(node, args, originalCandidate)) { + continue; + } + + let candidate: Signature; + let typeArgumentsAreValid: boolean; + let inferenceContext = originalCandidate.typeParameters + ? createInferenceContext(originalCandidate.typeParameters, /*inferUnionTypes*/ false) + : undefined; + + while (true) { + candidate = originalCandidate; + if (candidate.typeParameters) { + let typeArgumentTypes: Type[]; + if (typeArguments) { + typeArgumentTypes = new Array(candidate.typeParameters.length); + typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false) + } + else { + inferTypeArguments(candidate, args, excludeArgument, inferenceContext); + typeArgumentsAreValid = inferenceContext.failedTypeParameterIndex === undefined; + typeArgumentTypes = inferenceContext.inferredTypes; + } + if (!typeArgumentsAreValid) { + break; + } + candidate = getSignatureInstantiation(candidate, typeArgumentTypes); + } + if (!checkApplicableSignature(node, args, candidate, relation, excludeArgument, /*reportErrors*/ false)) { + break; + } + let index = excludeArgument ? indexOf(excludeArgument, true) : -1; + if (index < 0) { + return candidate; + } + excludeArgument[index] = false; + } + + // A post-mortem of this iteration of the loop. The signature was not applicable, + // so we want to track it as a candidate for reporting an error. If the candidate + // had no type parameters, or had no issues related to type arguments, we can + // report an error based on the arguments. If there was an issue with type + // arguments, then we can only report an error based on the type arguments. + if (originalCandidate.typeParameters) { + let instantiatedCandidate = candidate; + if (typeArgumentsAreValid) { + candidateForArgumentError = instantiatedCandidate; + } + else { + candidateForTypeArgumentError = originalCandidate; + if (!typeArguments) { + resultOfFailedInference = inferenceContext; + } + } + } + else { + Debug.assert(originalCandidate === candidate); + candidateForArgumentError = originalCandidate; + } + } + + return undefined; + } + + } + + function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[]): Signature { + if (node.expression.kind === SyntaxKind.SuperKeyword) { + let superType = checkSuperExpression(node.expression); + if (superType !== unknownType) { + return resolveCall(node, getSignaturesOfType(superType, SignatureKind.Construct), candidatesOutArray); + } + return resolveUntypedCall(node); + } + + let funcType = checkExpression(node.expression); + let apparentType = getApparentType(funcType); + + if (apparentType === unknownType) { + // Another error has already been reported + return resolveErrorCall(node); + } + + // Technically, this signatures list may be incomplete. We are taking the apparent type, + // but we are not including call signatures that may have been added to the Object or + // Function interface, since they have none by default. This is a bit of a leap of faith + // that the user will not add any. + let callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); + + let constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct); + // TS 1.0 spec: 4.12 + // If FuncExpr is of type Any, or of an object type that has no call or construct signatures + // but is a subtype of the Function interface, the call is an untyped function call. In an + // untyped function call no TypeArgs are permitted, Args can be any argument list, no contextual + // types are provided for the argument expressions, and the result is always of type Any. + // We exclude union types because we may have a union of function types that happen to have + // no common signatures. + if (funcType === anyType || (!callSignatures.length && !constructSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) { + if (node.typeArguments) { + error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); + } + return resolveUntypedCall(node); + } + // If FuncExpr's apparent type(section 3.8.1) is a function type, the call is a typed function call. + // TypeScript employs overload resolution in typed function calls in order to support functions + // with multiple call signatures. + if (!callSignatures.length) { + if (constructSignatures.length) { + error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); + } + else { + error(node, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature); + } + return resolveErrorCall(node); + } + return resolveCall(node, callSignatures, candidatesOutArray); + } + + function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[]): Signature { + if (node.arguments && languageVersion < ScriptTarget.ES6) { + let spreadIndex = getSpreadArgumentIndex(node.arguments); + if (spreadIndex >= 0) { + error(node.arguments[spreadIndex], Diagnostics.Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_6_and_higher); + } + } + + let expressionType = checkExpression(node.expression); + // TS 1.0 spec: 4.11 + // If ConstructExpr is of type Any, Args can be any argument + // list and the result of the operation is of type Any. + if (expressionType === anyType) { + if (node.typeArguments) { + error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments); + } + return resolveUntypedCall(node); + } + + // If ConstructExpr's apparent type(section 3.8.1) is an object type with one or + // more construct signatures, the expression is processed in the same manner as a + // function call, but using the construct signatures as the initial set of candidate + // signatures for overload resolution.The result type of the function call becomes + // the result type of the operation. + expressionType = getApparentType(expressionType); + if (expressionType === unknownType) { + // Another error has already been reported + return resolveErrorCall(node); + } + + // Technically, this signatures list may be incomplete. We are taking the apparent type, + // but we are not including construct signatures that may have been added to the Object or + // Function interface, since they have none by default. This is a bit of a leap of faith + // that the user will not add any. + let constructSignatures = getSignaturesOfType(expressionType, SignatureKind.Construct); + if (constructSignatures.length) { + return resolveCall(node, constructSignatures, candidatesOutArray); + } + + // If ConstructExpr's apparent type is an object type with no construct signatures but + // one or more call signatures, the expression is processed as a function call. A compile-time + // error occurs if the result of the function call is not Void. The type of the result of the + // operation is Any. + let callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call); + if (callSignatures.length) { + let signature = resolveCall(node, callSignatures, candidatesOutArray); + if (getReturnTypeOfSignature(signature) !== voidType) { + error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword); + } + return signature; + } + + error(node, Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature); + return resolveErrorCall(node); + } + + function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[]): Signature { + let tagType = checkExpression(node.tag); + let apparentType = getApparentType(tagType); + + if (apparentType === unknownType) { + // Another error has already been reported + return resolveErrorCall(node); + } + + let callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); + + if (tagType === anyType || (!callSignatures.length && !(tagType.flags & TypeFlags.Union) && isTypeAssignableTo(tagType, globalFunctionType))) { + return resolveUntypedCall(node); + } + + if (!callSignatures.length) { + error(node, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature); + return resolveErrorCall(node); + } + + return resolveCall(node, callSignatures, candidatesOutArray); + } + + // candidatesOutArray is passed by signature help in the language service, and collectCandidates + // must fill it up with the appropriate candidate signatures + function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature { + let links = getNodeLinks(node); + // If getResolvedSignature has already been called, we will have cached the resolvedSignature. + // However, it is possible that either candidatesOutArray was not passed in the first time, + // or that a different candidatesOutArray was passed in. Therefore, we need to redo the work + // to correctly fill the candidatesOutArray. + if (!links.resolvedSignature || candidatesOutArray) { + links.resolvedSignature = anySignature; + + if (node.kind === SyntaxKind.CallExpression) { + links.resolvedSignature = resolveCallExpression(node, candidatesOutArray); + } + else if (node.kind === SyntaxKind.NewExpression) { + links.resolvedSignature = resolveNewExpression(node, candidatesOutArray); + } + else if (node.kind === SyntaxKind.TaggedTemplateExpression) { + links.resolvedSignature = resolveTaggedTemplateExpression(node, candidatesOutArray); + } + else { + Debug.fail("Branch in 'getResolvedSignature' should be unreachable."); + } + } + return links.resolvedSignature; + } + + function checkCallExpression(node: CallExpression): Type { + // Grammar checking; stop grammar-checking if checkGrammarTypeArguments return true + checkGrammarTypeArguments(node, node.typeArguments) || checkGrammarArguments(node, node.arguments); + + let signature = getResolvedSignature(node); + if (node.expression.kind === SyntaxKind.SuperKeyword) { + return voidType; + } + if (node.kind === SyntaxKind.NewExpression) { + let declaration = signature.declaration; + if (declaration && + declaration.kind !== SyntaxKind.Constructor && + declaration.kind !== SyntaxKind.ConstructSignature && + declaration.kind !== SyntaxKind.ConstructorType) { + + // When resolved signature is a call signature (and not a construct signature) the result type is any + if (compilerOptions.noImplicitAny) { + error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type); + } + return anyType; + } + } + return getReturnTypeOfSignature(signature); + } + + function checkTaggedTemplateExpression(node: TaggedTemplateExpression): Type { + return getReturnTypeOfSignature(getResolvedSignature(node)); + } + + function checkTypeAssertion(node: TypeAssertion): Type { + let exprType = checkExpression(node.expression); + let targetType = getTypeFromTypeNode(node.type); + if (produceDiagnostics && targetType !== unknownType) { + let widenedType = getWidenedType(exprType); + if (!(isTypeAssignableTo(targetType, widenedType))) { + checkTypeAssignableTo(exprType, targetType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other); + } + } + return targetType; + } + + function getTypeAtPosition(signature: Signature, pos: number): Type { + return signature.hasRestParameter ? + pos < signature.parameters.length - 1 ? getTypeOfSymbol(signature.parameters[pos]) : getRestTypeOfSignature(signature) : + pos < signature.parameters.length ? getTypeOfSymbol(signature.parameters[pos]) : anyType; + } + + function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) { + let len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0); + for (let i = 0; i < len; i++) { + let parameter = signature.parameters[i]; + let links = getSymbolLinks(parameter); + links.type = instantiateType(getTypeAtPosition(context, i), mapper); + } + if (signature.hasRestParameter && context.hasRestParameter && signature.parameters.length >= context.parameters.length) { + let parameter = signature.parameters[signature.parameters.length - 1]; + let links = getSymbolLinks(parameter); + links.type = instantiateType(getTypeOfSymbol(context.parameters[context.parameters.length - 1]), mapper); + } + } + + function getReturnTypeFromBody(func: FunctionLikeDeclaration, contextualMapper?: TypeMapper): Type { + let contextualSignature = getContextualSignatureForFunctionLikeDeclaration(func); + if (!func.body) { + return unknownType; + } + let type: Type; + if (func.body.kind !== SyntaxKind.Block) { + type = checkExpressionCached(func.body, contextualMapper); + } + else { + // Aggregate the types of expressions within all the return statements. + let types = checkAndAggregateReturnExpressionTypes(func.body, contextualMapper); + if (types.length === 0) { + return voidType; + } + // When return statements are contextually typed we allow the return type to be a union type. Otherwise we require the + // return expressions to have a best common supertype. + type = contextualSignature ? getUnionType(types) : getCommonSupertype(types); + if (!type) { + error(func, Diagnostics.No_best_common_type_exists_among_return_expressions); + return unknownType; + } + } + if (!contextualSignature) { + reportErrorsFromWidening(func, type); + } + return getWidenedType(type); + } + + /// Returns a set of types relating to every return expression relating to a function block. + function checkAndAggregateReturnExpressionTypes(body: Block, contextualMapper?: TypeMapper): Type[] { + let aggregatedTypes: Type[] = []; + + forEachReturnStatement(body, returnStatement => { + let expr = returnStatement.expression; + if (expr) { + let type = checkExpressionCached(expr, contextualMapper); + if (!contains(aggregatedTypes, type)) { + aggregatedTypes.push(type); + } + } + }); + + return aggregatedTypes; + } + + function bodyContainsAReturnStatement(funcBody: Block) { + return forEachReturnStatement(funcBody, returnStatement => { + return true; + }); + } + + function bodyContainsSingleThrowStatement(body: Block) { + return (body.statements.length === 1) && (body.statements[0].kind === SyntaxKind.ThrowStatement); + } + + // TypeScript Specification 1.0 (6.3) - July 2014 + // An explicitly typed function whose return type isn't the Void or the Any type + // must have at least one return statement somewhere in its body. + // An exception to this rule is if the function implementation consists of a single 'throw' statement. + function checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(func: FunctionLikeDeclaration, returnType: Type): void { + if (!produceDiagnostics) { + return; + } + + // Functions that return 'void' or 'any' don't need any return expressions. + if (returnType === voidType || returnType === anyType) { + return; + } + + // If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check. + if (nodeIsMissing(func.body) || func.body.kind !== SyntaxKind.Block) { + return; + } + + let bodyBlock = func.body; + + // Ensure the body has at least one return expression. + if (bodyContainsAReturnStatement(bodyBlock)) { + return; + } + + // If there are no return expressions, then we need to check if + // the function body consists solely of a throw statement; + // this is to make an exception for unimplemented functions. + if (bodyContainsSingleThrowStatement(bodyBlock)) { + return; + } + + // This function does not conform to the specification. + error(func.type, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value_or_consist_of_a_single_throw_statement); + } + + function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, contextualMapper?: TypeMapper): Type { + Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + + // Grammar checking + let hasGrammarError = checkGrammarDeclarationNameInStrictMode(node) || checkGrammarFunctionLikeDeclaration(node); + if (!hasGrammarError && node.kind === SyntaxKind.FunctionExpression) { + checkGrammarFunctionName(node.name) || checkGrammarForGenerator(node); + } + + // The identityMapper object is used to indicate that function expressions are wildcards + if (contextualMapper === identityMapper && isContextSensitive(node)) { + return anyFunctionType; + } + let links = getNodeLinks(node); + let type = getTypeOfSymbol(node.symbol); + // Check if function expression is contextually typed and assign parameter types if so + if (!(links.flags & NodeCheckFlags.ContextChecked)) { + let contextualSignature = getContextualSignature(node); + // If a type check is started at a function expression that is an argument of a function call, obtaining the + // contextual type may recursively get back to here during overload resolution of the call. If so, we will have + // already assigned contextual types. + if (!(links.flags & NodeCheckFlags.ContextChecked)) { + links.flags |= NodeCheckFlags.ContextChecked; + if (contextualSignature) { + let signature = getSignaturesOfType(type, SignatureKind.Call)[0]; + if (isContextSensitive(node)) { + assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper); + } + if (!node.type) { + signature.resolvedReturnType = resolvingType; + let returnType = getReturnTypeFromBody(node, contextualMapper); + if (signature.resolvedReturnType === resolvingType) { + signature.resolvedReturnType = returnType; + } + } + } + checkSignatureDeclaration(node); + } + } + + if (produceDiagnostics && node.kind !== SyntaxKind.MethodDeclaration && node.kind !== SyntaxKind.MethodSignature) { + checkCollisionWithCapturedSuperVariable(node, (node).name); + checkCollisionWithCapturedThisVariable(node, (node).name); + } + + return type; + } + + function checkFunctionExpressionOrObjectLiteralMethodBody(node: FunctionExpression | MethodDeclaration) { + Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + if (node.type && !node.asteriskToken) { + checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type)); + } + + if (node.body) { + if (node.body.kind === SyntaxKind.Block) { + checkSourceElement(node.body); + } + else { + let exprType = checkExpression(node.body); + if (node.type) { + checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), node.body, /*headMessage*/ undefined); + } + checkFunctionExpressionBodies(node.body); + } + } + } + + function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage): boolean { + if (!allConstituentTypesHaveKind(type, TypeFlags.Any | TypeFlags.NumberLike)) { + error(operand, diagnostic); + return false; + } + return true; + } + + function checkReferenceExpression(n: Node, invalidReferenceMessage: DiagnosticMessage, constantVariableMessage: DiagnosticMessage): boolean { + function findSymbol(n: Node): Symbol { + let symbol = getNodeLinks(n).resolvedSymbol; + // Because we got the symbol from the resolvedSymbol property, it might be of kind + // SymbolFlags.ExportValue. In this case it is necessary to get the actual export + // symbol, which will have the correct flags set on it. + return symbol && getExportSymbolOfValueSymbolIfExported(symbol); + } + + function isReferenceOrErrorExpression(n: Node): boolean { + // TypeScript 1.0 spec (April 2014): + // Expressions are classified as values or references. + // References are the subset of expressions that are permitted as the target of an assignment. + // Specifically, references are combinations of identifiers(section 4.3), parentheses(section 4.7), + // and property accesses(section 4.10). + // All other expression constructs described in this chapter are classified as values. + switch (n.kind) { + case SyntaxKind.Identifier: { + let symbol = findSymbol(n); + // TypeScript 1.0 spec (April 2014): 4.3 + // An identifier expression that references a variable or parameter is classified as a reference. + // An identifier expression that references any other kind of entity is classified as a value(and therefore cannot be the target of an assignment). + return !symbol || symbol === unknownSymbol || symbol === argumentsSymbol || (symbol.flags & SymbolFlags.Variable) !== 0; + } + case SyntaxKind.PropertyAccessExpression: { + let symbol = findSymbol(n); + // TypeScript 1.0 spec (April 2014): 4.10 + // A property access expression is always classified as a reference. + // NOTE (not in spec): assignment to enum members should not be allowed + return !symbol || symbol === unknownSymbol || (symbol.flags & ~SymbolFlags.EnumMember) !== 0; + } + case SyntaxKind.ElementAccessExpression: + // old compiler doesn't check indexed assess + return true; + case SyntaxKind.ParenthesizedExpression: + return isReferenceOrErrorExpression((n).expression); + default: + return false; + } + } + + function isConstVariableReference(n: Node): boolean { + switch (n.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.PropertyAccessExpression: { + let symbol = findSymbol(n); + return symbol && (symbol.flags & SymbolFlags.Variable) !== 0 && (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0; + } + case SyntaxKind.ElementAccessExpression: { + let index = (n).argumentExpression; + let symbol = findSymbol((n).expression); + if (symbol && index && index.kind === SyntaxKind.StringLiteral) { + let name = (index).text; + let prop = getPropertyOfType(getTypeOfSymbol(symbol), name); + return prop && (prop.flags & SymbolFlags.Variable) !== 0 && (getDeclarationFlagsFromSymbol(prop) & NodeFlags.Const) !== 0; + } + return false; + } + case SyntaxKind.ParenthesizedExpression: + return isConstVariableReference((n).expression); + default: + return false; + } + } + + if (!isReferenceOrErrorExpression(n)) { + error(n, invalidReferenceMessage); + return false; + } + + if (isConstVariableReference(n)) { + error(n, constantVariableMessage); + return false; + } + + return true; + } + + function checkDeleteExpression(node: DeleteExpression): Type { + // Grammar checking + if (node.parserContextFlags & ParserContextFlags.StrictMode && node.expression.kind === SyntaxKind.Identifier) { + // When a delete operator occurs within strict mode code, a SyntaxError is thrown if its + // UnaryExpression is a direct reference to a variable, function argument, or function name + grammarErrorOnNode(node.expression, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode); + } + + let operandType = checkExpression(node.expression); + return booleanType; + } + + function checkTypeOfExpression(node: TypeOfExpression): Type { + let operandType = checkExpression(node.expression); + return stringType; + } + + function checkVoidExpression(node: VoidExpression): Type { + let operandType = checkExpression(node.expression); + return undefinedType; + } + + function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type { + // Grammar checking + // The identifier eval or arguments may not appear as the LeftHandSideExpression of an + // Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression + // operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator + if ((node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken)) { + checkGrammarEvalOrArgumentsInStrictMode(node, node.operand); + } + + let operandType = checkExpression(node.operand); + switch (node.operator) { + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + case SyntaxKind.TildeToken: + if (someConstituentTypeHasKind(operandType, TypeFlags.ESSymbol)) { + error(node.operand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(node.operator)); + } + return numberType; + case SyntaxKind.ExclamationToken: + return booleanType; + case SyntaxKind.PlusPlusToken: + case SyntaxKind.MinusMinusToken: + let ok = checkArithmeticOperandType(node.operand, operandType, Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type); + if (ok) { + // run check only if former checks succeeded to avoid reporting cascading errors + checkReferenceExpression(node.operand, + Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_property_or_indexer, + Diagnostics.The_operand_of_an_increment_or_decrement_operator_cannot_be_a_constant); + } + return numberType; + } + return unknownType; + } + + function checkPostfixUnaryExpression(node: PostfixUnaryExpression): Type { + // Grammar checking + // The identifier eval or arguments may not appear as the LeftHandSideExpression of an + // Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression + // operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator. + checkGrammarEvalOrArgumentsInStrictMode(node, node.operand); + + let operandType = checkExpression(node.operand); + let ok = checkArithmeticOperandType(node.operand, operandType, Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type); + if (ok) { + // run check only if former checks succeeded to avoid reporting cascading errors + checkReferenceExpression(node.operand, + Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_property_or_indexer, + Diagnostics.The_operand_of_an_increment_or_decrement_operator_cannot_be_a_constant); + } + return numberType; + } + + // Just like isTypeOfKind below, except that it returns true if *any* constituent + // has this kind. + function someConstituentTypeHasKind(type: Type, kind: TypeFlags): boolean { + if (type.flags & kind) { + return true; + } + if (type.flags & TypeFlags.Union) { + let types = (type).types; + for (let current of types) { + if (current.flags & kind) { + return true; + } + } + return false; + } + return false; + } + + // Return true if type has the given flags, or is a union type composed of types that all have those flags. + function allConstituentTypesHaveKind(type: Type, kind: TypeFlags): boolean { + if (type.flags & kind) { + return true; + } + if (type.flags & TypeFlags.Union) { + let types = (type).types; + for (let current of types) { + if (!(current.flags & kind)) { + return false; + } + } + return true; + } + return false; + } + + function isConstEnumObjectType(type: Type): boolean { + return type.flags & (TypeFlags.ObjectType | TypeFlags.Anonymous) && type.symbol && isConstEnumSymbol(type.symbol); + } + + function isConstEnumSymbol(symbol: Symbol): boolean { + return (symbol.flags & SymbolFlags.ConstEnum) !== 0; + } + + function checkInstanceOfExpression(node: BinaryExpression, leftType: Type, rightType: Type): Type { + // TypeScript 1.0 spec (April 2014): 4.15.4 + // The instanceof operator requires the left operand to be of type Any, an object type, or a type parameter type, + // and the right operand to be of type Any or a subtype of the 'Function' interface type. + // The result is always of the Boolean primitive type. + // NOTE: do not raise error if leftType is unknown as related error was already reported + if (allConstituentTypesHaveKind(leftType, TypeFlags.Primitive)) { + error(node.left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); + } + // NOTE: do not raise error if right is unknown as related error was already reported + if (!(rightType.flags & TypeFlags.Any || isTypeSubtypeOf(rightType, globalFunctionType))) { + error(node.right, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type); + } + return booleanType; + } + + function checkInExpression(node: BinaryExpression, leftType: Type, rightType: Type): Type { + // TypeScript 1.0 spec (April 2014): 4.15.5 + // The in operator requires the left operand to be of type Any, the String primitive type, or the Number primitive type, + // and the right operand to be of type Any, an object type, or a type parameter type. + // The result is always of the Boolean primitive type. + if (!allConstituentTypesHaveKind(leftType, TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbol)) { + error(node.left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol); + } + if (!allConstituentTypesHaveKind(rightType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter)) { + error(node.right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); + } + return booleanType; + } + + function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type { + let properties = node.properties; + for (let p of properties) { + if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { + // TODO(andersh): Computed property support + let name = (p).name; + let type = sourceType.flags & TypeFlags.Any ? sourceType : + getTypeOfPropertyOfType(sourceType, name.text) || + isNumericLiteralName(name.text) && getIndexTypeOfType(sourceType, IndexKind.Number) || + getIndexTypeOfType(sourceType, IndexKind.String); + if (type) { + checkDestructuringAssignment((p).initializer || name, type); + } + else { + error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(sourceType), declarationNameToString(name)); + } + } + else { + error(p, Diagnostics.Property_assignment_expected); + } + } + return sourceType; + } + + function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type { + // This elementType will be used if the specific property corresponding to this index is not + // present (aka the tuple element property). This call also checks that the parentType is in + // fact an iterable or array (depending on target language). + let elementType = checkIteratedTypeOrElementType(sourceType, node, /*allowStringInput*/ false) || unknownType; + let elements = node.elements; + for (let i = 0; i < elements.length; i++) { + let e = elements[i]; + if (e.kind !== SyntaxKind.OmittedExpression) { + if (e.kind !== SyntaxKind.SpreadElementExpression) { + let propName = "" + i; + let type = sourceType.flags & TypeFlags.Any ? sourceType : + isTupleLikeType(sourceType) + ? getTypeOfPropertyOfType(sourceType, propName) + : elementType; + if (type) { + checkDestructuringAssignment(e, type, contextualMapper); + } + else { + if (isTupleType(sourceType)) { + error(e, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), (sourceType).elementTypes.length, elements.length); + } + else { + error(e, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName); + } + } + } + else { + if (i < elements.length - 1) { + error(e, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern); + } + else { + let restExpression = (e).expression; + if (restExpression.kind === SyntaxKind.BinaryExpression && (restExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + error((restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer); + } + else { + checkDestructuringAssignment(restExpression, createArrayType(elementType), contextualMapper); + } + } + } + } + } + return sourceType; + } + + function checkDestructuringAssignment(target: Expression, sourceType: Type, contextualMapper?: TypeMapper): Type { + if (target.kind === SyntaxKind.BinaryExpression && (target).operatorToken.kind === SyntaxKind.EqualsToken) { + checkBinaryExpression(target, contextualMapper); + target = (target).left; + } + if (target.kind === SyntaxKind.ObjectLiteralExpression) { + return checkObjectLiteralAssignment(target, sourceType, contextualMapper); + } + if (target.kind === SyntaxKind.ArrayLiteralExpression) { + return checkArrayLiteralAssignment(target, sourceType, contextualMapper); + } + return checkReferenceAssignment(target, sourceType, contextualMapper); + } + + function checkReferenceAssignment(target: Expression, sourceType: Type, contextualMapper?: TypeMapper): Type { + let targetType = checkExpression(target, contextualMapper); + if (checkReferenceExpression(target, Diagnostics.Invalid_left_hand_side_of_assignment_expression, Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant)) { + checkTypeAssignableTo(sourceType, targetType, target, /*headMessage*/ undefined); + } + return sourceType; + } + + function checkBinaryExpression(node: BinaryExpression, contextualMapper?: TypeMapper) { + // Grammar checking + if (isLeftHandSideExpression(node.left) && isAssignmentOperator(node.operatorToken.kind)) { + // ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an + // Assignment operator(11.13) or of a PostfixExpression(11.3) + checkGrammarEvalOrArgumentsInStrictMode(node, node.left); + } + + let operator = node.operatorToken.kind; + if (operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { + return checkDestructuringAssignment(node.left, checkExpression(node.right, contextualMapper), contextualMapper); + } + let leftType = checkExpression(node.left, contextualMapper); + let rightType = checkExpression(node.right, contextualMapper); + switch (operator) { + case SyntaxKind.AsteriskToken: + case SyntaxKind.AsteriskEqualsToken: + case SyntaxKind.SlashToken: + case SyntaxKind.SlashEqualsToken: + case SyntaxKind.PercentToken: + case SyntaxKind.PercentEqualsToken: + case SyntaxKind.MinusToken: + case SyntaxKind.MinusEqualsToken: + case SyntaxKind.LessThanLessThanToken: + case SyntaxKind.LessThanLessThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + case SyntaxKind.BarToken: + case SyntaxKind.BarEqualsToken: + case SyntaxKind.CaretToken: + case SyntaxKind.CaretEqualsToken: + case SyntaxKind.AmpersandToken: + case SyntaxKind.AmpersandEqualsToken: + // TypeScript 1.0 spec (April 2014): 4.15.1 + // These operators require their operands to be of type Any, the Number primitive type, + // or an enum type. Operands of an enum type are treated + // as having the primitive type Number. If one operand is the null or undefined value, + // it is treated as having the type of the other operand. + // The result is always of the Number primitive type. + if (leftType.flags & (TypeFlags.Undefined | TypeFlags.Null)) leftType = rightType; + if (rightType.flags & (TypeFlags.Undefined | TypeFlags.Null)) rightType = leftType; + + let suggestedOperator: SyntaxKind; + // if a user tries to apply a bitwise operator to 2 boolean operands + // try and return them a helpful suggestion + if ((leftType.flags & TypeFlags.Boolean) && + (rightType.flags & TypeFlags.Boolean) && + (suggestedOperator = getSuggestedBooleanOperator(node.operatorToken.kind)) !== undefined) { + error(node, Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, tokenToString(node.operatorToken.kind), tokenToString(suggestedOperator)); + } + else { + // otherwise just check each operand separately and report errors as normal + let leftOk = checkArithmeticOperandType(node.left, leftType, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type); + let rightOk = checkArithmeticOperandType(node.right, rightType, Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type); + if (leftOk && rightOk) { + checkAssignmentOperator(numberType); + } + } + + return numberType; + case SyntaxKind.PlusToken: + case SyntaxKind.PlusEqualsToken: + // TypeScript 1.0 spec (April 2014): 4.15.2 + // The binary + operator requires both operands to be of the Number primitive type or an enum type, + // or at least one of the operands to be of type Any or the String primitive type. + + // If one operand is the null or undefined value, it is treated as having the type of the other operand. + if (leftType.flags & (TypeFlags.Undefined | TypeFlags.Null)) leftType = rightType; + if (rightType.flags & (TypeFlags.Undefined | TypeFlags.Null)) rightType = leftType; + + let resultType: Type; + if (allConstituentTypesHaveKind(leftType, TypeFlags.NumberLike) && allConstituentTypesHaveKind(rightType, TypeFlags.NumberLike)) { + // Operands of an enum type are treated as having the primitive type Number. + // If both operands are of the Number primitive type, the result is of the Number primitive type. + resultType = numberType; + } + else { + if (allConstituentTypesHaveKind(leftType, TypeFlags.StringLike) || allConstituentTypesHaveKind(rightType, TypeFlags.StringLike)) { + // If one or both operands are of the String primitive type, the result is of the String primitive type. + resultType = stringType; + } + else if (leftType.flags & TypeFlags.Any || rightType.flags & TypeFlags.Any) { + // Otherwise, the result is of type Any. + // NOTE: unknown type here denotes error type. Old compiler treated this case as any type so do we. + resultType = anyType; + } + + // Symbols are not allowed at all in arithmetic expressions + if (resultType && !checkForDisallowedESSymbolOperand(operator)) { + return resultType; + } + } + + if (!resultType) { + reportOperatorError(); + return anyType; + } + + if (operator === SyntaxKind.PlusEqualsToken) { + checkAssignmentOperator(resultType); + } + return resultType; + case SyntaxKind.LessThanToken: + case SyntaxKind.GreaterThanToken: + case SyntaxKind.LessThanEqualsToken: + case SyntaxKind.GreaterThanEqualsToken: + if (!checkForDisallowedESSymbolOperand(operator)) { + return booleanType; + } + // Fall through + case SyntaxKind.EqualsEqualsToken: + case SyntaxKind.ExclamationEqualsToken: + case SyntaxKind.EqualsEqualsEqualsToken: + case SyntaxKind.ExclamationEqualsEqualsToken: + if (!isTypeAssignableTo(leftType, rightType) && !isTypeAssignableTo(rightType, leftType)) { + reportOperatorError(); + } + return booleanType; + case SyntaxKind.InstanceOfKeyword: + return checkInstanceOfExpression(node, leftType, rightType); + case SyntaxKind.InKeyword: + return checkInExpression(node, leftType, rightType); + case SyntaxKind.AmpersandAmpersandToken: + return rightType; + case SyntaxKind.BarBarToken: + return getUnionType([leftType, rightType]); + case SyntaxKind.EqualsToken: + checkAssignmentOperator(rightType); + return rightType; + case SyntaxKind.CommaToken: + return rightType; + } + + // Return true if there was no error, false if there was an error. + function checkForDisallowedESSymbolOperand(operator: SyntaxKind): boolean { + let offendingSymbolOperand = + someConstituentTypeHasKind(leftType, TypeFlags.ESSymbol) ? node.left : + someConstituentTypeHasKind(rightType, TypeFlags.ESSymbol) ? node.right : + undefined; + if (offendingSymbolOperand) { + error(offendingSymbolOperand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(operator)); + return false; + } + + return true; + } + + function getSuggestedBooleanOperator(operator: SyntaxKind): SyntaxKind { + switch (operator) { + case SyntaxKind.BarToken: + case SyntaxKind.BarEqualsToken: + return SyntaxKind.BarBarToken; + case SyntaxKind.CaretToken: + case SyntaxKind.CaretEqualsToken: + return SyntaxKind.ExclamationEqualsEqualsToken; + case SyntaxKind.AmpersandToken: + case SyntaxKind.AmpersandEqualsToken: + return SyntaxKind.AmpersandAmpersandToken; + default: + return undefined; + } + } + + function checkAssignmentOperator(valueType: Type): void { + if (produceDiagnostics && operator >= SyntaxKind.FirstAssignment && operator <= SyntaxKind.LastAssignment) { + // TypeScript 1.0 spec (April 2014): 4.17 + // An assignment of the form + // VarExpr = ValueExpr + // requires VarExpr to be classified as a reference + // A compound assignment furthermore requires VarExpr to be classified as a reference (section 4.1) + // and the type of the non - compound operation to be assignable to the type of VarExpr. + let ok = checkReferenceExpression(node.left, Diagnostics.Invalid_left_hand_side_of_assignment_expression, Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant); + // Use default messages + if (ok) { + // to avoid cascading errors check assignability only if 'isReference' check succeeded and no errors were reported + checkTypeAssignableTo(valueType, leftType, node.left, /*headMessage*/ undefined); + } + } + } + + function reportOperatorError() { + error(node, Diagnostics.Operator_0_cannot_be_applied_to_types_1_and_2, tokenToString(node.operatorToken.kind), typeToString(leftType), typeToString(rightType)); + } + } + + function checkYieldExpression(node: YieldExpression): void { + // Grammar checking + if (!(node.parserContextFlags & ParserContextFlags.Yield)) { + grammarErrorOnFirstToken(node, Diagnostics.yield_expression_must_be_contained_within_a_generator_declaration); + } + else { + grammarErrorOnFirstToken(node, Diagnostics.yield_expressions_are_not_currently_supported); + } + } + + function checkConditionalExpression(node: ConditionalExpression, contextualMapper?: TypeMapper): Type { + checkExpression(node.condition); + let type1 = checkExpression(node.whenTrue, contextualMapper); + let type2 = checkExpression(node.whenFalse, contextualMapper); + return getUnionType([type1, type2]); + } + + function checkTemplateExpression(node: TemplateExpression): Type { + // We just want to check each expressions, but we are unconcerned with + // the type of each expression, as any value may be coerced into a string. + // It is worth asking whether this is what we really want though. + // A place where we actually *are* concerned with the expressions' types are + // in tagged templates. + forEach((node).templateSpans, templateSpan => { + checkExpression(templateSpan.expression); + }); + + return stringType; + } + + function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper?: TypeMapper): Type { + let saveContextualType = node.contextualType; + node.contextualType = contextualType; + let result = checkExpression(node, contextualMapper); + node.contextualType = saveContextualType; + return result; + } + + function checkExpressionCached(node: Expression, contextualMapper?: TypeMapper): Type { + let links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = checkExpression(node, contextualMapper); + } + return links.resolvedType; + } + + function checkPropertyAssignment(node: PropertyAssignment, contextualMapper?: TypeMapper): Type { + // Do not use hasDynamicName here, because that returns false for well known symbols. + // We want to perform checkComputedPropertyName for all computed properties, including + // well known symbols. + if (node.name.kind === SyntaxKind.ComputedPropertyName) { + checkComputedPropertyName(node.name); + } + + return checkExpression((node).initializer, contextualMapper); + } + + function checkObjectLiteralMethod(node: MethodDeclaration, contextualMapper?: TypeMapper): Type { + // Grammar checking + checkGrammarMethod(node); + + // Do not use hasDynamicName here, because that returns false for well known symbols. + // We want to perform checkComputedPropertyName for all computed properties, including + // well known symbols. + if (node.name.kind === SyntaxKind.ComputedPropertyName) { + checkComputedPropertyName(node.name); + } + + let uninstantiatedType = checkFunctionExpressionOrObjectLiteralMethod(node, contextualMapper); + return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, contextualMapper); + } + + function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, contextualMapper?: TypeMapper) { + if (contextualMapper && contextualMapper !== identityMapper) { + let signature = getSingleCallSignature(type); + if (signature && signature.typeParameters) { + let contextualType = getContextualType(node); + if (contextualType) { + let contextualSignature = getSingleCallSignature(contextualType); + if (contextualSignature && !contextualSignature.typeParameters) { + return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, contextualMapper)); + } + } + } + } + + return type; + } + + function checkExpression(node: Expression, contextualMapper?: TypeMapper): Type { + checkGrammarIdentifierInStrictMode(node); + return checkExpressionOrQualifiedName(node, contextualMapper); + } + + // Checks an expression and returns its type. The contextualMapper parameter serves two purposes: When + // contextualMapper is not undefined and not equal to the identityMapper function object it indicates that the + // expression is being inferentially typed (section 4.12.2 in spec) and provides the type mapper to use in + // conjunction with the generic contextual type. When contextualMapper is equal to the identityMapper function + // object, it serves as an indicator that all contained function and arrow expressions should be considered to + // have the wildcard function type; this form of type check is used during overload resolution to exclude + // contextually typed function and arrow expressions in the initial phase. + function checkExpressionOrQualifiedName(node: Expression | QualifiedName, contextualMapper?: TypeMapper): Type { + let type: Type; + if (node.kind == SyntaxKind.QualifiedName) { + type = checkQualifiedName(node); + } + else { + let uninstantiatedType = checkExpressionWorker(node, contextualMapper); + type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, contextualMapper); + } + + if (isConstEnumObjectType(type)) { + // enum object type for const enums are only permitted in: + // - 'left' in property access + // - 'object' in indexed access + // - target in rhs of import statement + let ok = + (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent).expression === node) || + (node.parent.kind === SyntaxKind.ElementAccessExpression && (node.parent).expression === node) || + ((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(node)); + + if (!ok) { + error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment); + } + } + return type; + } + + function checkNumericLiteral(node: LiteralExpression): Type { + // Grammar checking + checkGrammarNumericLiteral(node); + return numberType; + } + + function checkExpressionWorker(node: Expression, contextualMapper: TypeMapper): Type { + switch (node.kind) { + case SyntaxKind.Identifier: + return checkIdentifier(node); + case SyntaxKind.ThisKeyword: + return checkThisExpression(node); + case SyntaxKind.SuperKeyword: + return checkSuperExpression(node); + case SyntaxKind.NullKeyword: + return nullType; + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + return booleanType; + case SyntaxKind.NumericLiteral: + return checkNumericLiteral(node); + case SyntaxKind.TemplateExpression: + return checkTemplateExpression(node); + case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + return stringType; + case SyntaxKind.RegularExpressionLiteral: + return globalRegExpType; + case SyntaxKind.ArrayLiteralExpression: + return checkArrayLiteral(node, contextualMapper); + case SyntaxKind.ObjectLiteralExpression: + return checkObjectLiteral(node, contextualMapper); + case SyntaxKind.PropertyAccessExpression: + return checkPropertyAccessExpression(node); + case SyntaxKind.ElementAccessExpression: + return checkIndexedAccess(node); + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + return checkCallExpression(node); + case SyntaxKind.TaggedTemplateExpression: + return checkTaggedTemplateExpression(node); + case SyntaxKind.TypeAssertionExpression: + return checkTypeAssertion(node); + case SyntaxKind.ParenthesizedExpression: + return checkExpression((node).expression, contextualMapper); + case SyntaxKind.ClassExpression: + return checkClassExpression(node); + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + return checkFunctionExpressionOrObjectLiteralMethod(node, contextualMapper); + case SyntaxKind.TypeOfExpression: + return checkTypeOfExpression(node); + case SyntaxKind.DeleteExpression: + return checkDeleteExpression(node); + case SyntaxKind.VoidExpression: + return checkVoidExpression(node); + case SyntaxKind.PrefixUnaryExpression: + return checkPrefixUnaryExpression(node); + case SyntaxKind.PostfixUnaryExpression: + return checkPostfixUnaryExpression(node); + case SyntaxKind.BinaryExpression: + return checkBinaryExpression(node, contextualMapper); + case SyntaxKind.ConditionalExpression: + return checkConditionalExpression(node, contextualMapper); + case SyntaxKind.SpreadElementExpression: + return checkSpreadElementExpression(node, contextualMapper); + case SyntaxKind.OmittedExpression: + return undefinedType; + case SyntaxKind.YieldExpression: + checkYieldExpression(node); + return unknownType; + } + return unknownType; + } + + // DECLARATION AND STATEMENT TYPE CHECKING + + function checkTypeParameter(node: TypeParameterDeclaration) { + checkGrammarDeclarationNameInStrictMode(node); + + // Grammar Checking + if (node.expression) { + grammarErrorOnFirstToken(node.expression, Diagnostics.Type_expected); + } + + checkSourceElement(node.constraint); + if (produceDiagnostics) { + checkTypeParameterHasIllegalReferencesInConstraint(node); + checkTypeNameIsReserved(node.name, Diagnostics.Type_parameter_name_cannot_be_0); + } + // TODO: Check multiple declarations are identical + } + + function checkParameter(node: ParameterDeclaration) { + // Grammar checking + // It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the + // Identifier in a PropertySetParameterList of a PropertyAssignment that is contained in strict code + // or if its FunctionBody is strict code(11.1.5). + // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a + // strict mode FunctionLikeDeclaration or FunctionExpression(13.1) + + // Grammar checking + checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarEvalOrArgumentsInStrictMode(node, node.name); + + checkVariableLikeDeclaration(node); + let func = getContainingFunction(node); + if (node.flags & NodeFlags.AccessibilityModifier) { + func = getContainingFunction(node); + if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) { + error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); + } + } + if (node.questionToken && isBindingPattern(node.name) && func.body) { + error(node, Diagnostics.A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature); + } + + // Only check rest parameter type if it's not a binding pattern. Since binding patterns are + // not allowed in a rest parameter, we already have an error from checkGrammarParameterList. + if (node.dotDotDotToken && !isBindingPattern(node.name) && !isArrayType(getTypeOfSymbol(node.symbol))) { + error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type); + } + } + + function checkSignatureDeclaration(node: SignatureDeclaration) { + // Grammar checking + if (node.kind === SyntaxKind.IndexSignature) { + checkGrammarIndexSignature(node); + } + // TODO (yuisu): Remove this check in else-if when SyntaxKind.Construct is moved and ambient context is handled + else if (node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.ConstructorType || + node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.Constructor || + node.kind === SyntaxKind.ConstructSignature) { + checkGrammarFunctionLikeDeclaration(node); + } + + checkTypeParameters(node.typeParameters); + + forEach(node.parameters, checkParameter); + + if (node.type) { + checkSourceElement(node.type); + } + + if (produceDiagnostics) { + checkCollisionWithArgumentsInGeneratedCode(node); + if (compilerOptions.noImplicitAny && !node.type) { + switch (node.kind) { + case SyntaxKind.ConstructSignature: + error(node, Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); + break; + case SyntaxKind.CallSignature: + error(node, Diagnostics.Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); + break; + } + } + } + + checkSpecializedSignatureDeclaration(node); + } + + function checkTypeForDuplicateIndexSignatures(node: Node) { + if (node.kind === SyntaxKind.InterfaceDeclaration) { + let nodeSymbol = getSymbolOfNode(node); + // in case of merging interface declaration it is possible that we'll enter this check procedure several times for every declaration + // to prevent this run check only for the first declaration of a given kind + if (nodeSymbol.declarations.length > 0 && nodeSymbol.declarations[0] !== node) { + return; + } + } + + // TypeScript 1.0 spec (April 2014) + // 3.7.4: An object type can contain at most one string index signature and one numeric index signature. + // 8.5: A class declaration can have at most one string index member declaration and one numeric index member declaration + let indexSymbol = getIndexSymbol(getSymbolOfNode(node)); + if (indexSymbol) { + let seenNumericIndexer = false; + let seenStringIndexer = false; + for (let decl of indexSymbol.declarations) { + let declaration = decl; + if (declaration.parameters.length === 1 && declaration.parameters[0].type) { + switch (declaration.parameters[0].type.kind) { + case SyntaxKind.StringKeyword: + if (!seenStringIndexer) { + seenStringIndexer = true; + } + else { + error(declaration, Diagnostics.Duplicate_string_index_signature); + } + break; + case SyntaxKind.NumberKeyword: + if (!seenNumericIndexer) { + seenNumericIndexer = true; + } + else { + error(declaration, Diagnostics.Duplicate_number_index_signature); + } + break; + } + } + } + } + } + + function checkPropertyDeclaration(node: PropertyDeclaration) { + // Grammar checking + checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarProperty(node) || checkGrammarComputedPropertyName(node.name); + + checkVariableLikeDeclaration(node); + } + + function checkMethodDeclaration(node: MethodDeclaration) { + // Grammar checking + checkGrammarMethod(node) || checkGrammarComputedPropertyName(node.name); + + // Grammar checking for modifiers is done inside the function checkGrammarFunctionLikeDeclaration + checkFunctionLikeDeclaration(node); + } + + function checkConstructorDeclaration(node: ConstructorDeclaration) { + // Grammar check on signature of constructor and modifier of the constructor is done in checkSignatureDeclaration function. + checkSignatureDeclaration(node); + // Grammar check for checking only related to constructoDeclaration + checkGrammarConstructorTypeParameters(node) || checkGrammarConstructorTypeAnnotation(node); + + checkSourceElement(node.body); + + let symbol = getSymbolOfNode(node); + let firstDeclaration = getDeclarationOfKind(symbol, node.kind); + // Only type check the symbol once + if (node === firstDeclaration) { + checkFunctionOrConstructorSymbol(symbol); + } + + // exit early in the case of signature - super checks are not relevant to them + if (nodeIsMissing(node.body)) { + return; + } + + if (!produceDiagnostics) { + return; + } + + function isSuperCallExpression(n: Node): boolean { + return n.kind === SyntaxKind.CallExpression && (n).expression.kind === SyntaxKind.SuperKeyword; + } + + function containsSuperCall(n: Node): boolean { + if (isSuperCallExpression(n)) { + return true; + } + switch (n.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + case SyntaxKind.ObjectLiteralExpression: return false; + default: return forEachChild(n, containsSuperCall); + } + } + + function markThisReferencesAsErrors(n: Node): void { + if (n.kind === SyntaxKind.ThisKeyword) { + error(n, Diagnostics.this_cannot_be_referenced_in_current_location); + } + else if (n.kind !== SyntaxKind.FunctionExpression && n.kind !== SyntaxKind.FunctionDeclaration) { + forEachChild(n, markThisReferencesAsErrors); + } + } + + function isInstancePropertyWithInitializer(n: Node): boolean { + return n.kind === SyntaxKind.PropertyDeclaration && + !(n.flags & NodeFlags.Static) && + !!(n).initializer; + } + + // TS 1.0 spec (April 2014): 8.3.2 + // Constructors of classes with no extends clause may not contain super calls, whereas + // constructors of derived classes must contain at least one super call somewhere in their function body. + if (getClassExtendsHeritageClauseElement(node.parent)) { + + if (containsSuperCall(node.body)) { + // The first statement in the body of a constructor must be a super call if both of the following are true: + // - The containing class is a derived class. + // - The constructor declares parameter properties + // or the containing class declares instance member variables with initializers. + let superCallShouldBeFirst = + forEach((node.parent).members, isInstancePropertyWithInitializer) || + forEach(node.parameters, p => p.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)); + + if (superCallShouldBeFirst) { + let statements = (node.body).statements; + if (!statements.length || statements[0].kind !== SyntaxKind.ExpressionStatement || !isSuperCallExpression((statements[0]).expression)) { + error(node, Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties); + } + else { + // In such a required super call, it is a compile-time error for argument expressions to reference this. + markThisReferencesAsErrors((statements[0]).expression); + } + } + } + else { + error(node, Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call); + } + } + } + + function checkAccessorDeclaration(node: AccessorDeclaration) { + if (produceDiagnostics) { + // Grammar checking accessors + checkGrammarFunctionLikeDeclaration(node) || checkGrammarAccessor(node) || checkGrammarComputedPropertyName(node.name); + + if (node.kind === SyntaxKind.GetAccessor) { + if (!isInAmbientContext(node) && nodeIsPresent(node.body) && !(bodyContainsAReturnStatement(node.body) || bodyContainsSingleThrowStatement(node.body))) { + error(node.name, Diagnostics.A_get_accessor_must_return_a_value_or_consist_of_a_single_throw_statement); + } + } + + if (!hasDynamicName(node)) { + // TypeScript 1.0 spec (April 2014): 8.4.3 + // Accessors for the same member name must specify the same accessibility. + let otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; + let otherAccessor = getDeclarationOfKind(node.symbol, otherKind); + if (otherAccessor) { + if (((node.flags & NodeFlags.AccessibilityModifier) !== (otherAccessor.flags & NodeFlags.AccessibilityModifier))) { + error(node.name, Diagnostics.Getter_and_setter_accessors_do_not_agree_in_visibility); + } + + let currentAccessorType = getAnnotatedAccessorType(node); + let otherAccessorType = getAnnotatedAccessorType(otherAccessor); + // TypeScript 1.0 spec (April 2014): 4.5 + // If both accessors include type annotations, the specified types must be identical. + if (currentAccessorType && otherAccessorType) { + if (!isTypeIdenticalTo(currentAccessorType, otherAccessorType)) { + error(node, Diagnostics.get_and_set_accessor_must_have_the_same_type); + } + } + } + } + + checkAndStoreTypeOfAccessors(getSymbolOfNode(node)); + } + + checkFunctionLikeDeclaration(node); + } + + function checkMissingDeclaration(node: Node) { + checkDecorators(node); + } + + function checkTypeReferenceNode(node: TypeReferenceNode) { + checkGrammarTypeReferenceInStrictMode(node.typeName); + return checkTypeReferenceOrHeritageClauseElement(node); + } + + function checkHeritageClauseElement(node: HeritageClauseElement) { + checkGrammarHeritageClauseElementInStrictMode(node.expression); + + return checkTypeReferenceOrHeritageClauseElement(node); + } + + function checkTypeReferenceOrHeritageClauseElement(node: TypeReferenceNode | HeritageClauseElement) { + // Grammar checking + checkGrammarTypeArguments(node, node.typeArguments); + + let type = getTypeFromTypeReferenceOrHeritageClauseElement(node); + if (type !== unknownType && node.typeArguments) { + // Do type argument local checks only if referenced type is successfully resolved + let len = node.typeArguments.length; + for (let i = 0; i < len; i++) { + checkSourceElement(node.typeArguments[i]); + let constraint = getConstraintOfTypeParameter((type).target.typeParameters[i]); + if (produceDiagnostics && constraint) { + let typeArgument = (type).typeArguments[i]; + checkTypeAssignableTo(typeArgument, constraint, node, Diagnostics.Type_0_does_not_satisfy_the_constraint_1); + } + } + } + } + + function checkTypeQuery(node: TypeQueryNode) { + getTypeFromTypeQueryNode(node); + } + + function checkTypeLiteral(node: TypeLiteralNode) { + forEach(node.members, checkSourceElement); + if (produceDiagnostics) { + let type = getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); + checkIndexConstraints(type); + checkTypeForDuplicateIndexSignatures(node); + } + } + + function checkArrayType(node: ArrayTypeNode) { + checkSourceElement(node.elementType); + } + + function checkTupleType(node: TupleTypeNode) { + // Grammar checking + let hasErrorFromDisallowedTrailingComma = checkGrammarForDisallowedTrailingComma(node.elementTypes); + if (!hasErrorFromDisallowedTrailingComma && node.elementTypes.length === 0) { + grammarErrorOnNode(node, Diagnostics.A_tuple_type_element_list_cannot_be_empty); + } + + forEach(node.elementTypes, checkSourceElement); + } + + function checkUnionType(node: UnionTypeNode) { + forEach(node.types, checkSourceElement); + } + + function isPrivateWithinAmbient(node: Node): boolean { + return (node.flags & NodeFlags.Private) && isInAmbientContext(node); + } + + function checkSpecializedSignatureDeclaration(signatureDeclarationNode: SignatureDeclaration): void { + if (!produceDiagnostics) { + return; + } + let signature = getSignatureFromDeclaration(signatureDeclarationNode); + if (!signature.hasStringLiterals) { + return; + } + + // TypeScript 1.0 spec (April 2014): 3.7.2.2 + // Specialized signatures are not permitted in conjunction with a function body + if (nodeIsPresent((signatureDeclarationNode).body)) { + error(signatureDeclarationNode, Diagnostics.A_signature_with_an_implementation_cannot_use_a_string_literal_type); + return; + } + + // TypeScript 1.0 spec (April 2014): 3.7.2.4 + // Every specialized call or construct signature in an object type must be assignable + // to at least one non-specialized call or construct signature in the same object type + let signaturesToCheck: Signature[]; + // Unnamed (call\construct) signatures in interfaces are inherited and not shadowed so examining just node symbol won't give complete answer. + // Use declaring type to obtain full list of signatures. + if (!signatureDeclarationNode.name && signatureDeclarationNode.parent && signatureDeclarationNode.parent.kind === SyntaxKind.InterfaceDeclaration) { + Debug.assert(signatureDeclarationNode.kind === SyntaxKind.CallSignature || signatureDeclarationNode.kind === SyntaxKind.ConstructSignature); + let signatureKind = signatureDeclarationNode.kind === SyntaxKind.CallSignature ? SignatureKind.Call : SignatureKind.Construct; + let containingSymbol = getSymbolOfNode(signatureDeclarationNode.parent); + let containingType = getDeclaredTypeOfSymbol(containingSymbol); + signaturesToCheck = getSignaturesOfType(containingType, signatureKind); + } + else { + signaturesToCheck = getSignaturesOfSymbol(getSymbolOfNode(signatureDeclarationNode)); + } + + for (let otherSignature of signaturesToCheck) { + if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature)) { + return; + } + } + + error(signatureDeclarationNode, Diagnostics.Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature); + } + + function getEffectiveDeclarationFlags(n: Node, flagsToCheck: NodeFlags) { + let flags = getCombinedNodeFlags(n); + if (n.parent.kind !== SyntaxKind.InterfaceDeclaration && isInAmbientContext(n)) { + if (!(flags & NodeFlags.Ambient)) { + // It is nested in an ambient context, which means it is automatically exported + flags |= NodeFlags.Export; + } + flags |= NodeFlags.Ambient; + } + + return flags & flagsToCheck; + } + + function checkFunctionOrConstructorSymbol(symbol: Symbol): void { + if (!produceDiagnostics) { + return; + } + + function getCanonicalOverload(overloads: Declaration[], implementation: FunctionLikeDeclaration) { + // Consider the canonical set of flags to be the flags of the bodyDeclaration or the first declaration + // Error on all deviations from this canonical set of flags + // The caveat is that if some overloads are defined in lib.d.ts, we don't want to + // report the errors on those. To achieve this, we will say that the implementation is + // the canonical signature only if it is in the same container as the first overload + let implementationSharesContainerWithFirstOverload = implementation !== undefined && implementation.parent === overloads[0].parent; + return implementationSharesContainerWithFirstOverload ? implementation : overloads[0]; + } + + function checkFlagAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration, flagsToCheck: NodeFlags, someOverloadFlags: NodeFlags, allOverloadFlags: NodeFlags): void { + // Error if some overloads have a flag that is not shared by all overloads. To find the + // deviations, we XOR someOverloadFlags with allOverloadFlags + let someButNotAllOverloadFlags = someOverloadFlags ^ allOverloadFlags; + if (someButNotAllOverloadFlags !== 0) { + let canonicalFlags = getEffectiveDeclarationFlags(getCanonicalOverload(overloads, implementation), flagsToCheck); + + forEach(overloads, o => { + let deviation = getEffectiveDeclarationFlags(o, flagsToCheck) ^ canonicalFlags; + if (deviation & NodeFlags.Export) { + error(o.name, Diagnostics.Overload_signatures_must_all_be_exported_or_not_exported); + } + else if (deviation & NodeFlags.Ambient) { + error(o.name, Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient); + } + else if (deviation & (NodeFlags.Private | NodeFlags.Protected)) { + error(o.name, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected); + } + }); + } + } + + function checkQuestionTokenAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration, someHaveQuestionToken: boolean, allHaveQuestionToken: boolean): void { + if (someHaveQuestionToken !== allHaveQuestionToken) { + let canonicalHasQuestionToken = hasQuestionToken(getCanonicalOverload(overloads, implementation)); + forEach(overloads, o => { + let deviation = hasQuestionToken(o) !== canonicalHasQuestionToken; + if (deviation) { + error(o.name, Diagnostics.Overload_signatures_must_all_be_optional_or_required); + } + }); + } + } + + let flagsToCheck: NodeFlags = NodeFlags.Export | NodeFlags.Ambient | NodeFlags.Private | NodeFlags.Protected; + let someNodeFlags: NodeFlags = 0; + let allNodeFlags = flagsToCheck; + let someHaveQuestionToken = false; + let allHaveQuestionToken = true; + let hasOverloads = false; + let bodyDeclaration: FunctionLikeDeclaration; + let lastSeenNonAmbientDeclaration: FunctionLikeDeclaration; + let previousDeclaration: FunctionLikeDeclaration; + + let declarations = symbol.declarations; + let isConstructor = (symbol.flags & SymbolFlags.Constructor) !== 0; + + function reportImplementationExpectedError(node: FunctionLikeDeclaration): void { + if (node.name && nodeIsMissing(node.name)) { + return; + } + + let seen = false; + let subsequentNode = forEachChild(node.parent, c => { + if (seen) { + return c; + } + else { + seen = c === node; + } + }); + if (subsequentNode) { + if (subsequentNode.kind === node.kind) { + let errorNode: Node = (subsequentNode).name || subsequentNode; + // TODO(jfreeman): These are methods, so handle computed name case + if (node.name && (subsequentNode).name && (node.name).text === ((subsequentNode).name).text) { + // the only situation when this is possible (same kind\same name but different symbol) - mixed static and instance class members + Debug.assert(node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature); + Debug.assert((node.flags & NodeFlags.Static) !== (subsequentNode.flags & NodeFlags.Static)); + let diagnostic = node.flags & NodeFlags.Static ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static; + error(errorNode, diagnostic); + return; + } + else if (nodeIsPresent((subsequentNode).body)) { + error(errorNode, Diagnostics.Function_implementation_name_must_be_0, declarationNameToString(node.name)); + return; + } + } + } + let errorNode: Node = node.name || node; + if (isConstructor) { + error(errorNode, Diagnostics.Constructor_implementation_is_missing); + } + else { + error(errorNode, Diagnostics.Function_implementation_is_missing_or_not_immediately_following_the_declaration); + } + } + + // when checking exported function declarations across modules check only duplicate implementations + // names and consistency of modifiers are verified when we check local symbol + let isExportSymbolInsideModule = symbol.parent && symbol.parent.flags & SymbolFlags.Module; + let duplicateFunctionDeclaration = false; + let multipleConstructorImplementation = false; + for (let current of declarations) { + let node = current; + let inAmbientContext = isInAmbientContext(node); + let inAmbientContextOrInterface = node.parent.kind === SyntaxKind.InterfaceDeclaration || node.parent.kind === SyntaxKind.TypeLiteral || inAmbientContext; + if (inAmbientContextOrInterface) { + // check if declarations are consecutive only if they are non-ambient + // 1. ambient declarations can be interleaved + // i.e. this is legal + // declare function foo(); + // declare function bar(); + // declare function foo(); + // 2. mixing ambient and non-ambient declarations is a separate error that will be reported - do not want to report an extra one + previousDeclaration = undefined; + } + + if (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature || node.kind === SyntaxKind.Constructor) { + let currentNodeFlags = getEffectiveDeclarationFlags(node, flagsToCheck); + someNodeFlags |= currentNodeFlags; + allNodeFlags &= currentNodeFlags; + someHaveQuestionToken = someHaveQuestionToken || hasQuestionToken(node); + allHaveQuestionToken = allHaveQuestionToken && hasQuestionToken(node); + + if (nodeIsPresent(node.body) && bodyDeclaration) { + if (isConstructor) { + multipleConstructorImplementation = true; + } + else { + duplicateFunctionDeclaration = true; + } + } + else if (!isExportSymbolInsideModule && previousDeclaration && previousDeclaration.parent === node.parent && previousDeclaration.end !== node.pos) { + reportImplementationExpectedError(previousDeclaration); + } + + if (nodeIsPresent(node.body)) { + if (!bodyDeclaration) { + bodyDeclaration = node; + } + } + else { + hasOverloads = true; + } + + previousDeclaration = node; + + if (!inAmbientContextOrInterface) { + lastSeenNonAmbientDeclaration = node; + } + } + } + + if (multipleConstructorImplementation) { + forEach(declarations, declaration => { + error(declaration, Diagnostics.Multiple_constructor_implementations_are_not_allowed); + }); + } + + if (duplicateFunctionDeclaration) { + forEach(declarations, declaration => { + error(declaration.name, Diagnostics.Duplicate_function_implementation); + }); + } + + if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body) { + reportImplementationExpectedError(lastSeenNonAmbientDeclaration); + } + + if (hasOverloads) { + checkFlagAgreementBetweenOverloads(declarations, bodyDeclaration, flagsToCheck, someNodeFlags, allNodeFlags); + checkQuestionTokenAgreementBetweenOverloads(declarations, bodyDeclaration, someHaveQuestionToken, allHaveQuestionToken); + + if (bodyDeclaration) { + let signatures = getSignaturesOfSymbol(symbol); + let bodySignature = getSignatureFromDeclaration(bodyDeclaration); + // If the implementation signature has string literals, we will have reported an error in + // checkSpecializedSignatureDeclaration + if (!bodySignature.hasStringLiterals) { + // TypeScript 1.0 spec (April 2014): 6.1 + // If a function declaration includes overloads, the overloads determine the call + // signatures of the type given to the function object + // and the function implementation signature must be assignable to that type + // + // TypeScript 1.0 spec (April 2014): 3.8.4 + // Note that specialized call and construct signatures (section 3.7.2.4) are not significant when determining assignment compatibility + // Consider checking against specialized signatures too. Not doing so creates a type hole: + // + // function g(x: "hi", y: boolean); + // function g(x: string, y: {}); + // function g(x: string, y: string) { } + // + // The implementation is completely unrelated to the specialized signature, yet we do not check this. + for (let signature of signatures) { + if (!signature.hasStringLiterals && !isSignatureAssignableTo(bodySignature, signature)) { + error(signature.declaration, Diagnostics.Overload_signature_is_not_compatible_with_function_implementation); + break; + } + } + } + } + } + } + + function checkExportsOnMergedDeclarations(node: Node): void { + if (!produceDiagnostics) { + return; + } + + // Exports should be checked only if enclosing module contains both exported and non exported declarations. + // In case if all declarations are non-exported check is unnecessary. + + // if localSymbol is defined on node then node itself is exported - check is required + let symbol = node.localSymbol; + if (!symbol) { + // local symbol is undefined => this declaration is non-exported. + // however symbol might contain other declarations that are exported + symbol = getSymbolOfNode(node); + if (!(symbol.flags & SymbolFlags.Export)) { + // this is a pure local symbol (all declarations are non-exported) - no need to check anything + return; + } + } + + // run the check only for the first declaration in the list + if (getDeclarationOfKind(symbol, node.kind) !== node) { + return; + } + + // we use SymbolFlags.ExportValue, SymbolFlags.ExportType and SymbolFlags.ExportNamespace + // to denote disjoint declarationSpaces (without making new enum type). + let exportedDeclarationSpaces: SymbolFlags = 0; + let nonExportedDeclarationSpaces: SymbolFlags = 0; + forEach(symbol.declarations, d => { + let declarationSpaces = getDeclarationSpaces(d); + if (getEffectiveDeclarationFlags(d, NodeFlags.Export)) { + exportedDeclarationSpaces |= declarationSpaces; + } + else { + nonExportedDeclarationSpaces |= declarationSpaces; + } + }); + + let commonDeclarationSpace = exportedDeclarationSpaces & nonExportedDeclarationSpaces; + + if (commonDeclarationSpace) { + // declaration spaces for exported and non-exported declarations intersect + forEach(symbol.declarations, d => { + if (getDeclarationSpaces(d) & commonDeclarationSpace) { + error(d.name, Diagnostics.Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local, declarationNameToString(d.name)); + } + }); + } + + function getDeclarationSpaces(d: Declaration): SymbolFlags { + switch (d.kind) { + case SyntaxKind.InterfaceDeclaration: + return SymbolFlags.ExportType; + case SyntaxKind.ModuleDeclaration: + return (d).name.kind === SyntaxKind.StringLiteral || getModuleInstanceState(d) !== ModuleInstanceState.NonInstantiated + ? SymbolFlags.ExportNamespace | SymbolFlags.ExportValue + : SymbolFlags.ExportNamespace; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + return SymbolFlags.ExportType | SymbolFlags.ExportValue; + case SyntaxKind.ImportEqualsDeclaration: + let result: SymbolFlags = 0; + let target = resolveAlias(getSymbolOfNode(d)); + forEach(target.declarations, d => { result |= getDeclarationSpaces(d); }); + return result; + default: + return SymbolFlags.ExportValue; + } + } + } + + /** Check a decorator */ + function checkDecorator(node: Decorator): void { + let expression: Expression = node.expression; + let exprType = checkExpression(expression); + + switch (node.parent.kind) { + case SyntaxKind.ClassDeclaration: + let classSymbol = getSymbolOfNode(node.parent); + let classConstructorType = getTypeOfSymbol(classSymbol); + let classDecoratorType = instantiateSingleCallFunctionType(getGlobalClassDecoratorType(), [classConstructorType]); + checkTypeAssignableTo(exprType, classDecoratorType, node); + break; + + case SyntaxKind.PropertyDeclaration: + checkTypeAssignableTo(exprType, getGlobalPropertyDecoratorType(), node); + break; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + let methodType = getTypeOfNode(node.parent); + let methodDecoratorType = instantiateSingleCallFunctionType(getGlobalMethodDecoratorType(), [methodType]); + checkTypeAssignableTo(exprType, methodDecoratorType, node); + break; + + case SyntaxKind.Parameter: + checkTypeAssignableTo(exprType, getGlobalParameterDecoratorType(), node); + break; + } + } + + /** Checks a type reference node as an expression. */ + function checkTypeNodeAsExpression(node: TypeNode) { + // When we are emitting type metadata for decorators, we need to try to check the type + // as if it were an expression so that we can emit the type in a value position when we + // serialize the type metadata. + if (node && node.kind === SyntaxKind.TypeReference) { + let type = getTypeFromTypeNode(node); + let shouldCheckIfUnknownType = type === unknownType && compilerOptions.separateCompilation; + if (!type || (!shouldCheckIfUnknownType && type.flags & (TypeFlags.Intrinsic | TypeFlags.NumberLike | TypeFlags.StringLike))) { + return; + } + if (shouldCheckIfUnknownType || type.symbol.valueDeclaration) { + checkExpressionOrQualifiedName((node).typeName); + } + } + } + + /** + * Checks the type annotation of an accessor declaration or property declaration as + * an expression if it is a type reference to a type with a value declaration. + */ + function checkTypeAnnotationAsExpression(node: AccessorDeclaration | PropertyDeclaration | ParameterDeclaration | MethodDeclaration) { + switch (node.kind) { + case SyntaxKind.PropertyDeclaration: + checkTypeNodeAsExpression((node).type); + break; + case SyntaxKind.Parameter: + checkTypeNodeAsExpression((node).type); + break; + case SyntaxKind.MethodDeclaration: + checkTypeNodeAsExpression((node).type); + break; + case SyntaxKind.GetAccessor: + checkTypeNodeAsExpression((node).type); + break; + case SyntaxKind.SetAccessor: + checkTypeNodeAsExpression(getSetAccessorTypeAnnotationNode(node)); + break; + } + } + + /** Checks the type annotation of the parameters of a function/method or the constructor of a class as expressions */ + function checkParameterTypeAnnotationsAsExpressions(node: FunctionLikeDeclaration) { + // ensure all type annotations with a value declaration are checked as an expression + for (let parameter of node.parameters) { + checkTypeAnnotationAsExpression(parameter); + } + } + + /** Check the decorators of a node */ + function checkDecorators(node: Node): void { + if (!node.decorators) { + return; + } + + // skip this check for nodes that cannot have decorators. These should have already had an error reported by + // checkGrammarDecorators. + if (!nodeCanBeDecorated(node)) { + return; + } + + if (compilerOptions.emitDecoratorMetadata) { + // we only need to perform these checks if we are emitting serialized type metadata for the target of a decorator. + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + var constructor = getFirstConstructorWithBody(node); + if (constructor) { + checkParameterTypeAnnotationsAsExpressions(constructor); + } + break; + + case SyntaxKind.MethodDeclaration: + checkParameterTypeAnnotationsAsExpressions(node); + // fall-through + + case SyntaxKind.SetAccessor: + case SyntaxKind.GetAccessor: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.Parameter: + checkTypeAnnotationAsExpression(node); + break; + } + } + + emitDecorate = true; + if (node.kind === SyntaxKind.Parameter) { + emitParam = true; + } + + forEach(node.decorators, checkDecorator); + } + + function checkFunctionDeclaration(node: FunctionDeclaration): void { + if (produceDiagnostics) { + checkFunctionLikeDeclaration(node) || + checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) || + checkGrammarFunctionName(node.name) || + checkGrammarForGenerator(node); + + checkCollisionWithCapturedSuperVariable(node, node.name); + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + } + } + + function checkFunctionLikeDeclaration(node: FunctionLikeDeclaration): void { + checkGrammarDeclarationNameInStrictMode(node); + checkDecorators(node); + checkSignatureDeclaration(node); + + // Do not use hasDynamicName here, because that returns false for well known symbols. + // We want to perform checkComputedPropertyName for all computed properties, including + // well known symbols. + if (node.name && node.name.kind === SyntaxKind.ComputedPropertyName) { + // This check will account for methods in class/interface declarations, + // as well as accessors in classes/object literals + checkComputedPropertyName(node.name); + } + + if (!hasDynamicName(node)) { + // first we want to check the local symbol that contain this declaration + // - if node.localSymbol !== undefined - this is current declaration is exported and localSymbol points to the local symbol + // - if node.localSymbol === undefined - this node is non-exported so we can just pick the result of getSymbolOfNode + let symbol = getSymbolOfNode(node); + let localSymbol = node.localSymbol || symbol; + + let firstDeclaration = getDeclarationOfKind(localSymbol, node.kind); + // Only type check the symbol once + if (node === firstDeclaration) { + checkFunctionOrConstructorSymbol(localSymbol); + } + + if (symbol.parent) { + // run check once for the first declaration + if (getDeclarationOfKind(symbol, node.kind) === node) { + // run check on export symbol to check that modifiers agree across all exported declarations + checkFunctionOrConstructorSymbol(symbol); + } + } + } + + checkSourceElement(node.body); + if (node.type && !isAccessor(node.kind) && !node.asteriskToken) { + checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type)); + } + + // Report an implicit any error if there is no body, no explicit return type, and node is not a private method + // in an ambient context + if (compilerOptions.noImplicitAny && nodeIsMissing(node.body) && !node.type && !isPrivateWithinAmbient(node)) { + reportImplicitAnyError(node, anyType); + } + } + + function checkBlock(node: Block) { + // Grammar checking for SyntaxKind.Block + if (node.kind === SyntaxKind.Block) { + checkGrammarStatementInAmbientContext(node); + } + + forEach(node.statements, checkSourceElement); + if (isFunctionBlock(node) || node.kind === SyntaxKind.ModuleBlock) { + checkFunctionExpressionBodies(node); + } + } + + function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { + // no rest parameters \ declaration context \ overload - no codegen impact + if (!hasRestParameters(node) || isInAmbientContext(node) || nodeIsMissing((node).body)) { + return; + } + + forEach(node.parameters, p => { + if (p.name && !isBindingPattern(p.name) && (p.name).text === argumentsSymbol.name) { + error(p, Diagnostics.Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters); + } + }); + } + + function needCollisionCheckForIdentifier(node: Node, identifier: Identifier, name: string): boolean { + if (!(identifier && identifier.text === name)) { + return false; + } + + if (node.kind === SyntaxKind.PropertyDeclaration || + node.kind === SyntaxKind.PropertySignature || + node.kind === SyntaxKind.MethodDeclaration || + node.kind === SyntaxKind.MethodSignature || + node.kind === SyntaxKind.GetAccessor || + node.kind === SyntaxKind.SetAccessor) { + // it is ok to have member named '_super' or '_this' - member access is always qualified + return false; + } + + if (isInAmbientContext(node)) { + // ambient context - no codegen impact + return false; + } + + let root = getRootDeclaration(node); + if (root.kind === SyntaxKind.Parameter && nodeIsMissing((root.parent).body)) { + // just an overload - no codegen impact + return false; + } + + return true; + } + + function checkCollisionWithCapturedThisVariable(node: Node, name: Identifier): void { + if (needCollisionCheckForIdentifier(node, name, "_this")) { + potentialThisCollisions.push(node); + } + } + + // this function will run after checking the source file so 'CaptureThis' is correct for all nodes + function checkIfThisIsCapturedInEnclosingScope(node: Node): void { + let current = node; + while (current) { + if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureThis) { + let isDeclaration = node.kind !== SyntaxKind.Identifier; + if (isDeclaration) { + error((node).name, Diagnostics.Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference); + } + else { + error(node, Diagnostics.Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference); + } + return; + } + current = current.parent; + } + } + + function checkCollisionWithCapturedSuperVariable(node: Node, name: Identifier) { + if (!needCollisionCheckForIdentifier(node, name, "_super")) { + return; + } + + // bubble up and find containing type + let enclosingClass = getAncestor(node, SyntaxKind.ClassDeclaration); + // if containing type was not found or it is ambient - exit (no codegen) + if (!enclosingClass || isInAmbientContext(enclosingClass)) { + return; + } + + if (getClassExtendsHeritageClauseElement(enclosingClass)) { + let isDeclaration = node.kind !== SyntaxKind.Identifier; + if (isDeclaration) { + error(node, Diagnostics.Duplicate_identifier_super_Compiler_uses_super_to_capture_base_class_reference); + } + else { + error(node, Diagnostics.Expression_resolves_to_super_that_compiler_uses_to_capture_base_class_reference); + } + } + } + + function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier) { + if (!needCollisionCheckForIdentifier(node, name, "require") && !needCollisionCheckForIdentifier(node, name, "exports")) { + return; + } + + // Uninstantiated modules shouldnt do this check + if (node.kind === SyntaxKind.ModuleDeclaration && getModuleInstanceState(node) !== ModuleInstanceState.Instantiated) { + return; + } + + // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent + let parent = getDeclarationContainer(node); + if (parent.kind === SyntaxKind.SourceFile && isExternalModule(parent)) { + // If the declaration happens to be in external module, report error that require and exports are reserved keywords + error(name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_an_external_module, + declarationNameToString(name), declarationNameToString(name)); + } + } + + function checkVarDeclaredNamesNotShadowed(node: VariableDeclaration | BindingElement) { + // - ScriptBody : StatementList + // It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList + // also occurs in the VarDeclaredNames of StatementList. + + // - Block : { StatementList } + // It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList + // also occurs in the VarDeclaredNames of StatementList. + + // Variable declarations are hoisted to the top of their function scope. They can shadow + // block scoped declarations, which bind tighter. this will not be flagged as duplicate definition + // by the binder as the declaration scope is different. + // A non-initialized declaration is a no-op as the block declaration will resolve before the var + // declaration. the problem is if the declaration has an initializer. this will act as a write to the + // block declared value. this is fine for let, but not const. + // Only consider declarations with initializers, uninitialized let declarations will not + // step on a let/const variable. + // Do not consider let and const declarations, as duplicate block-scoped declarations + // are handled by the binder. + // We are only looking for let declarations that step on let\const declarations from a + // different scope. e.g.: + // { + // const x = 0; // localDeclarationSymbol obtained after name resolution will correspond to this declaration + // let x = 0; // symbol for this declaration will be 'symbol' + // } + + // skip block-scoped variables and parameters + if ((getCombinedNodeFlags(node) & NodeFlags.BlockScoped) !== 0 || isParameterDeclaration(node)) { + return; + } + + // skip variable declarations that don't have initializers + // NOTE: in ES6 spec initializer is required in variable declarations where name is binding pattern + // so we'll always treat binding elements as initialized + if (node.kind === SyntaxKind.VariableDeclaration && !node.initializer) { + return; + } + + var symbol = getSymbolOfNode(node); + if (symbol.flags & SymbolFlags.FunctionScopedVariable) { + let localDeclarationSymbol = resolveName(node, (node.name).text, SymbolFlags.Variable, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined); + if (localDeclarationSymbol && + localDeclarationSymbol !== symbol && + localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable) { + if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.BlockScoped) { + let varDeclList = getAncestor(localDeclarationSymbol.valueDeclaration, SyntaxKind.VariableDeclarationList); + let container = + varDeclList.parent.kind === SyntaxKind.VariableStatement && varDeclList.parent.parent + ? varDeclList.parent.parent + : undefined; + + // names of block-scoped and function scoped variables can collide only + // if block scoped variable is defined in the function\module\source file scope (because of variable hoisting) + let namesShareScope = + container && + (container.kind === SyntaxKind.Block && isFunctionLike(container.parent) || + container.kind === SyntaxKind.ModuleBlock || + container.kind === SyntaxKind.ModuleDeclaration || + container.kind === SyntaxKind.SourceFile); + + // here we know that function scoped variable is shadowed by block scoped one + // if they are defined in the same scope - binder has already reported redeclaration error + // otherwise if variable has an initializer - show error that initialization will fail + // since LHS will be block scoped name instead of function scoped + if (!namesShareScope) { + let name = symbolToString(localDeclarationSymbol); + error(node, Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name, name); + } + } + } + } + } + + function isParameterDeclaration(node: VariableLikeDeclaration) { + while (node.kind === SyntaxKind.BindingElement) { + node = node.parent.parent; + } + return node.kind === SyntaxKind.Parameter; + } + + // Check that a parameter initializer contains no references to parameters declared to the right of itself + function checkParameterInitializer(node: VariableLikeDeclaration): void { + if (getRootDeclaration(node).kind !== SyntaxKind.Parameter) { + return; + } + + let func = getContainingFunction(node); + visit(node.initializer); + + function visit(n: Node) { + if (n.kind === SyntaxKind.Identifier) { + let referencedSymbol = getNodeLinks(n).resolvedSymbol; + // check FunctionLikeDeclaration.locals (stores parameters\function local variable) + // if it contains entry with a specified name and if this entry matches the resolved symbol + if (referencedSymbol && referencedSymbol !== unknownSymbol && getSymbol(func.locals, referencedSymbol.name, SymbolFlags.Value) === referencedSymbol) { + if (referencedSymbol.valueDeclaration.kind === SyntaxKind.Parameter) { + if (referencedSymbol.valueDeclaration === node) { + error(n, Diagnostics.Parameter_0_cannot_be_referenced_in_its_initializer, declarationNameToString(node.name)); + return; + } + if (referencedSymbol.valueDeclaration.pos < node.pos) { + // legal case - parameter initializer references some parameter strictly on left of current parameter declaration + return; + } + // fall through to error reporting + } + error(n, Diagnostics.Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(node.name), declarationNameToString(n)); + } + } + else { + forEachChild(n, visit); + } + } + } + + // Check variable, parameter, or property declaration + function checkVariableLikeDeclaration(node: VariableLikeDeclaration) { + checkGrammarDeclarationNameInStrictMode(node); + checkDecorators(node); + checkSourceElement(node.type); + // For a computed property, just check the initializer and exit + // Do not use hasDynamicName here, because that returns false for well known symbols. + // We want to perform checkComputedPropertyName for all computed properties, including + // well known symbols. + if (node.name.kind === SyntaxKind.ComputedPropertyName) { + checkComputedPropertyName(node.name); + if (node.initializer) { + checkExpressionCached(node.initializer); + } + } + // For a binding pattern, check contained binding elements + if (isBindingPattern(node.name)) { + forEach((node.name).elements, checkSourceElement); + } + // For a parameter declaration with an initializer, error and exit if the containing function doesn't have a body + if (node.initializer && getRootDeclaration(node).kind === SyntaxKind.Parameter && nodeIsMissing(getContainingFunction(node).body)) { + error(node, Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation); + return; + } + // For a binding pattern, validate the initializer and exit + if (isBindingPattern(node.name)) { + if (node.initializer) { + checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined); + checkParameterInitializer(node); + } + return; + } + let symbol = getSymbolOfNode(node); + let type = getTypeOfVariableOrParameterOrProperty(symbol); + if (node === symbol.valueDeclaration) { + // Node is the primary declaration of the symbol, just validate the initializer + if (node.initializer) { + checkTypeAssignableTo(checkExpressionCached(node.initializer), type, node, /*headMessage*/ undefined); + checkParameterInitializer(node); + } + } + else { + // Node is a secondary declaration, check that type is identical to primary declaration and check that + // initializer is consistent with type associated with the node + let declarationType = getWidenedTypeForVariableLikeDeclaration(node); + if (type !== unknownType && declarationType !== unknownType && !isTypeIdenticalTo(type, declarationType)) { + error(node.name, Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2, declarationNameToString(node.name), typeToString(type), typeToString(declarationType)); + } + if (node.initializer) { + checkTypeAssignableTo(checkExpressionCached(node.initializer), declarationType, node, /*headMessage*/ undefined); + } + } + if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature) { + // We know we don't have a binding pattern or computed name here + checkExportsOnMergedDeclarations(node); + if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { + checkVarDeclaredNamesNotShadowed(node); + } + checkCollisionWithCapturedSuperVariable(node, node.name); + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + } + } + + function checkVariableDeclaration(node: VariableDeclaration) { + checkGrammarVariableDeclaration(node); + return checkVariableLikeDeclaration(node); + } + + function checkBindingElement(node: BindingElement) { + checkGrammarBindingElement(node); + return checkVariableLikeDeclaration(node); + } + + function checkVariableStatement(node: VariableStatement) { + // Grammar checking + checkGrammarDecorators(node) || checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) || checkGrammarModifiers(node) || checkGrammarVariableDeclarationList(node.declarationList) || checkGrammarForDisallowedLetOrConstStatement(node); + + forEach(node.declarationList.declarations, checkSourceElement); + } + + function checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node: Node) { + if (node.modifiers) { + if (inBlockOrObjectLiteralExpression(node)) { + return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here); + } + } + } + + function inBlockOrObjectLiteralExpression(node: Node) { + while (node) { + if (node.kind === SyntaxKind.Block || node.kind === SyntaxKind.ObjectLiteralExpression) { + return true; + } + + node = node.parent; + } + } + + function checkExpressionStatement(node: ExpressionStatement) { + // Grammar checking + checkGrammarStatementInAmbientContext(node) + + checkExpression(node.expression); + } + + function checkIfStatement(node: IfStatement) { + // Grammar checking + checkGrammarStatementInAmbientContext(node); + + checkExpression(node.expression); + checkSourceElement(node.thenStatement); + checkSourceElement(node.elseStatement); + } + + function checkDoStatement(node: DoStatement) { + // Grammar checking + checkGrammarStatementInAmbientContext(node); + + checkSourceElement(node.statement); + checkExpression(node.expression); + } + + function checkWhileStatement(node: WhileStatement) { + // Grammar checking + checkGrammarStatementInAmbientContext(node); + + checkExpression(node.expression); + checkSourceElement(node.statement); + } + + function checkForStatement(node: ForStatement) { + // Grammar checking + if (!checkGrammarStatementInAmbientContext(node)) { + if (node.initializer && node.initializer.kind == SyntaxKind.VariableDeclarationList) { + checkGrammarVariableDeclarationList(node.initializer); + } + } + + if (node.initializer) { + if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { + forEach((node.initializer).declarations, checkVariableDeclaration) + } + else { + checkExpression(node.initializer) + } + } + + if (node.condition) checkExpression(node.condition); + if (node.incrementor) checkExpression(node.incrementor); + checkSourceElement(node.statement); + } + + function checkForOfStatement(node: ForOfStatement): void { + checkGrammarForInOrForOfStatement(node) + + // Check the LHS and RHS + // If the LHS is a declaration, just check it as a variable declaration, which will in turn check the RHS + // via checkRightHandSideOfForOf. + // If the LHS is an expression, check the LHS, as a destructuring assignment or as a reference. + // Then check that the RHS is assignable to it. + if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { + checkForInOrForOfVariableDeclaration(node); + } + else { + let varExpr = node.initializer; + let iteratedType = checkRightHandSideOfForOf(node.expression); + + // There may be a destructuring assignment on the left side + if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { + // iteratedType may be undefined. In this case, we still want to check the structure of + // varExpr, in particular making sure it's a valid LeftHandSideExpression. But we'd like + // to short circuit the type relation checking as much as possible, so we pass the unknownType. + checkDestructuringAssignment(varExpr, iteratedType || unknownType); + } + else { + let leftType = checkExpression(varExpr); + checkReferenceExpression(varExpr, /*invalidReferenceMessage*/ Diagnostics.Invalid_left_hand_side_in_for_of_statement, + /*constantVariableMessage*/ Diagnostics.The_left_hand_side_of_a_for_of_statement_cannot_be_a_previously_defined_constant); + + // iteratedType will be undefined if the rightType was missing properties/signatures + // required to get its iteratedType (like [Symbol.iterator] or next). This may be + // because we accessed properties from anyType, or it may have led to an error inside + // getIteratedType. + if (iteratedType) { + checkTypeAssignableTo(iteratedType, leftType, varExpr, /*headMessage*/ undefined); + } + } + } + + checkSourceElement(node.statement); + } + + function checkForInStatement(node: ForInStatement) { + // Grammar checking + checkGrammarForInOrForOfStatement(node); + + // TypeScript 1.0 spec (April 2014): 5.4 + // In a 'for-in' statement of the form + // for (let VarDecl in Expr) Statement + // VarDecl must be a variable declaration without a type annotation that declares a variable of type Any, + // and Expr must be an expression of type Any, an object type, or a type parameter type. + if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { + let variable = (node.initializer).declarations[0]; + if (variable && isBindingPattern(variable.name)) { + error(variable.name, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); + } + + checkForInOrForOfVariableDeclaration(node); + } + else { + // In a 'for-in' statement of the form + // for (Var in Expr) Statement + // Var must be an expression classified as a reference of type Any or the String primitive type, + // and Expr must be an expression of type Any, an object type, or a type parameter type. + let varExpr = node.initializer; + let leftType = checkExpression(varExpr); + if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { + error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); + } + else if (!allConstituentTypesHaveKind(leftType, TypeFlags.Any | TypeFlags.StringLike)) { + error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any); + } + else { + // run check only former check succeeded to avoid cascading errors + checkReferenceExpression(varExpr, Diagnostics.Invalid_left_hand_side_in_for_in_statement, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_previously_defined_constant); + } + } + + let rightType = checkExpression(node.expression); + // unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved + // in this case error about missing name is already reported - do not report extra one + if (!allConstituentTypesHaveKind(rightType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter)) { + error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter); + } + + checkSourceElement(node.statement); + } + + function checkForInOrForOfVariableDeclaration(iterationStatement: ForInStatement | ForOfStatement): void { + let variableDeclarationList = iterationStatement.initializer; + // checkGrammarForInOrForOfStatement will check that there is exactly one declaration. + if (variableDeclarationList.declarations.length >= 1) { + let decl = variableDeclarationList.declarations[0]; + checkVariableDeclaration(decl); + } + } + + function checkRightHandSideOfForOf(rhsExpression: Expression): Type { + let expressionType = getTypeOfExpression(rhsExpression); + return checkIteratedTypeOrElementType(expressionType, rhsExpression, /*allowStringInput*/ true); + } + + function checkIteratedTypeOrElementType(inputType: Type, errorNode: Node, allowStringInput: boolean): Type { + if (inputType.flags & TypeFlags.Any) { + return inputType; + } + + if (languageVersion >= ScriptTarget.ES6) { + return checkIteratedType(inputType, errorNode) || anyType; + } + + if (allowStringInput) { + return checkElementTypeOfArrayOrString(inputType, errorNode); + } + + if (isArrayLikeType(inputType)) { + let indexType = getIndexTypeOfType(inputType, IndexKind.Number); + if (indexType) { + return indexType; + } + } + + error(errorNode, Diagnostics.Type_0_is_not_an_array_type, typeToString(inputType)); + return unknownType; + } + + /** + * When errorNode is undefined, it means we should not report any errors. + */ + function checkIteratedType(iterable: Type, errorNode: Node): Type { + Debug.assert(languageVersion >= ScriptTarget.ES6); + let iteratedType = getIteratedType(iterable, errorNode); + // Now even though we have extracted the iteratedType, we will have to validate that the type + // passed in is actually an Iterable. + if (errorNode && iteratedType) { + checkTypeAssignableTo(iterable, createIterableType(iteratedType), errorNode); + } + + return iteratedType; + + function getIteratedType(iterable: Type, errorNode: Node) { + // We want to treat type as an iterable, and get the type it is an iterable of. The iterable + // must have the following structure (annotated with the names of the variables below): + // + // { // iterable + // [Symbol.iterator]: { // iteratorFunction + // (): { // iterator + // next: { // iteratorNextFunction + // (): { // iteratorNextResult + // value: T // iteratorNextValue + // } + // } + // } + // } + // } + // + // T is the type we are after. At every level that involves analyzing return types + // of signatures, we union the return types of all the signatures. + // + // Another thing to note is that at any step of this process, we could run into a dead end, + // meaning either the property is missing, or we run into the anyType. If either of these things + // happens, we return undefined to signal that we could not find the iterated type. If a property + // is missing, and the previous step did not result in 'any', then we also give an error if the + // caller requested it. Then the caller can decide what to do in the case where there is no iterated + // type. This is different from returning anyType, because that would signify that we have matched the + // whole pattern and that T (above) is 'any'. + + if (allConstituentTypesHaveKind(iterable, TypeFlags.Any)) { + return undefined; + } + + // As an optimization, if the type is instantiated directly using the globalIterableType (Iterable), + // then just grab its type argument. + if ((iterable.flags & TypeFlags.Reference) && (iterable).target === globalIterableType) { + return (iterable).typeArguments[0]; + } + + let iteratorFunction = getTypeOfPropertyOfType(iterable, getPropertyNameForKnownSymbolName("iterator")); + if (iteratorFunction && allConstituentTypesHaveKind(iteratorFunction, TypeFlags.Any)) { + return undefined; + } + + let iteratorFunctionSignatures = iteratorFunction ? getSignaturesOfType(iteratorFunction, SignatureKind.Call) : emptyArray; + if (iteratorFunctionSignatures.length === 0) { + if (errorNode) { + error(errorNode, Diagnostics.Type_must_have_a_Symbol_iterator_method_that_returns_an_iterator); + } + return undefined; + } + + let iterator = getUnionType(map(iteratorFunctionSignatures, getReturnTypeOfSignature)); + if (allConstituentTypesHaveKind(iterator, TypeFlags.Any)) { + return undefined; + } + + let iteratorNextFunction = getTypeOfPropertyOfType(iterator, "next"); + if (iteratorNextFunction && allConstituentTypesHaveKind(iteratorNextFunction, TypeFlags.Any)) { + return undefined; + } + + let iteratorNextFunctionSignatures = iteratorNextFunction ? getSignaturesOfType(iteratorNextFunction, SignatureKind.Call) : emptyArray; + if (iteratorNextFunctionSignatures.length === 0) { + if (errorNode) { + error(errorNode, Diagnostics.An_iterator_must_have_a_next_method); + } + return undefined; + } + + let iteratorNextResult = getUnionType(map(iteratorNextFunctionSignatures, getReturnTypeOfSignature)); + if (allConstituentTypesHaveKind(iteratorNextResult, TypeFlags.Any)) { + return undefined; + } + + let iteratorNextValue = getTypeOfPropertyOfType(iteratorNextResult, "value"); + if (!iteratorNextValue) { + if (errorNode) { + error(errorNode, Diagnostics.The_type_returned_by_the_next_method_of_an_iterator_must_have_a_value_property); + } + return undefined; + } + + return iteratorNextValue; + } + } + + /** + * This function does the following steps: + * 1. Break up arrayOrStringType (possibly a union) into its string constituents and array constituents. + * 2. Take the element types of the array constituents. + * 3. Return the union of the element types, and string if there was a string constitutent. + * + * For example: + * string -> string + * number[] -> number + * string[] | number[] -> string | number + * string | number[] -> string | number + * string | string[] | number[] -> string | number + * + * It also errors if: + * 1. Some constituent is neither a string nor an array. + * 2. Some constituent is a string and target is less than ES5 (because in ES3 string is not indexable). + */ + function checkElementTypeOfArrayOrString(arrayOrStringType: Type, errorNode: Node): Type { + Debug.assert(languageVersion < ScriptTarget.ES6); + + // After we remove all types that are StringLike, we will know if there was a string constituent + // based on whether the remaining type is the same as the initial type. + let arrayType = removeTypesFromUnionType(arrayOrStringType, TypeFlags.StringLike, /*isTypeOfKind*/ true, /*allowEmptyUnionResult*/ true); + let hasStringConstituent = arrayOrStringType !== arrayType; + + let reportedError = false; + if (hasStringConstituent) { + if (languageVersion < ScriptTarget.ES5) { + error(errorNode, Diagnostics.Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher); + reportedError = true; + } + + // Now that we've removed all the StringLike types, if no constituents remain, then the entire + // arrayOrStringType was a string. + if (arrayType === emptyObjectType) { + return stringType; + } + } + + if (!isArrayLikeType(arrayType)) { + if (!reportedError) { + // Which error we report depends on whether there was a string constituent. For example, + // if the input type is number | string, we want to say that number is not an array type. + // But if the input was just number, we want to say that number is not an array type + // or a string type. + let diagnostic = hasStringConstituent + ? Diagnostics.Type_0_is_not_an_array_type + : Diagnostics.Type_0_is_not_an_array_type_or_a_string_type; + error(errorNode, diagnostic, typeToString(arrayType)); + } + return hasStringConstituent ? stringType : unknownType; + } + + let arrayElementType = getIndexTypeOfType(arrayType, IndexKind.Number) || unknownType; + if (hasStringConstituent) { + // This is just an optimization for the case where arrayOrStringType is string | string[] + if (arrayElementType.flags & TypeFlags.StringLike) { + return stringType; + } + + return getUnionType([arrayElementType, stringType]); + } + + return arrayElementType; + } + + function checkBreakOrContinueStatement(node: BreakOrContinueStatement) { + // Grammar checking + checkGrammarStatementInAmbientContext(node) || checkGrammarBreakOrContinueStatement(node); + + // TODO: Check that target label is valid + } + + function isGetAccessorWithAnnotatatedSetAccessor(node: FunctionLikeDeclaration) { + return !!(node.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(node.symbol, SyntaxKind.SetAccessor))); + } + + function checkReturnStatement(node: ReturnStatement) { + // Grammar checking + if (!checkGrammarStatementInAmbientContext(node)) { + let functionBlock = getContainingFunction(node); + if (!functionBlock) { + grammarErrorOnFirstToken(node, Diagnostics.A_return_statement_can_only_be_used_within_a_function_body); + } + } + + if (node.expression) { + let func = getContainingFunction(node); + if (func) { + let returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func)); + let exprType = checkExpressionCached(node.expression); + if (func.kind === SyntaxKind.SetAccessor) { + error(node.expression, Diagnostics.Setters_cannot_return_a_value); + } + else { + if (func.kind === SyntaxKind.Constructor) { + if (!isTypeAssignableTo(exprType, returnType)) { + error(node.expression, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); + } + } + else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func)) { + checkTypeAssignableTo(exprType, returnType, node.expression, /*headMessage*/ undefined); + } + } + } + } + } + + function checkWithStatement(node: WithStatement) { + // Grammar checking for withStatement + if (!checkGrammarStatementInAmbientContext(node)) { + if (node.parserContextFlags & ParserContextFlags.StrictMode) { + grammarErrorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode); + } + } + + checkExpression(node.expression); + error(node.expression, Diagnostics.All_symbols_within_a_with_block_will_be_resolved_to_any); + } + + function checkSwitchStatement(node: SwitchStatement) { + // Grammar checking + checkGrammarStatementInAmbientContext(node); + + let firstDefaultClause: CaseOrDefaultClause; + let hasDuplicateDefaultClause = false; + + let expressionType = checkExpression(node.expression); + forEach(node.caseBlock.clauses, clause => { + // Grammar check for duplicate default clauses, skip if we already report duplicate default clause + if (clause.kind === SyntaxKind.DefaultClause && !hasDuplicateDefaultClause) { + if (firstDefaultClause === undefined) { + firstDefaultClause = clause; + } + else { + let sourceFile = getSourceFileOfNode(node); + let start = skipTrivia(sourceFile.text, clause.pos); + let end = clause.statements.length > 0 ? clause.statements[0].pos : clause.end; + grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement); + hasDuplicateDefaultClause = true; + } + } + + if (produceDiagnostics && clause.kind === SyntaxKind.CaseClause) { + let caseClause = clause; + // TypeScript 1.0 spec (April 2014):5.9 + // In a 'switch' statement, each 'case' expression must be of a type that is assignable to or from the type of the 'switch' expression. + let caseType = checkExpression(caseClause.expression); + if (!isTypeAssignableTo(expressionType, caseType)) { + // check 'expressionType isAssignableTo caseType' failed, try the reversed check and report errors if it fails + checkTypeAssignableTo(caseType, expressionType, caseClause.expression, /*headMessage*/ undefined); + } + } + forEach(clause.statements, checkSourceElement); + }); + } + + function checkLabeledStatement(node: LabeledStatement) { + // Grammar checking + if (!checkGrammarStatementInAmbientContext(node)) { + let current = node.parent; + while (current) { + if (isFunctionLike(current)) { + break; + } + if (current.kind === SyntaxKind.LabeledStatement && (current).label.text === node.label.text) { + let sourceFile = getSourceFileOfNode(node); + grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getTextOfNodeFromSourceText(sourceFile.text, node.label)); + break; + } + current = current.parent; + } + } + + // ensure that label is unique + checkSourceElement(node.statement); + } + + function checkThrowStatement(node: ThrowStatement) { + // Grammar checking + if (!checkGrammarStatementInAmbientContext(node)) { + if (node.expression === undefined) { + grammarErrorAfterFirstToken(node, Diagnostics.Line_break_not_permitted_here); + } + } + + if (node.expression) { + checkExpression(node.expression); + } + } + + function checkTryStatement(node: TryStatement) { + // Grammar checking + checkGrammarStatementInAmbientContext(node); + + checkBlock(node.tryBlock); + let catchClause = node.catchClause; + if (catchClause) { + // Grammar checking + if (catchClause.variableDeclaration) { + if (catchClause.variableDeclaration.name.kind !== SyntaxKind.Identifier) { + grammarErrorOnFirstToken(catchClause.variableDeclaration.name, Diagnostics.Catch_clause_variable_name_must_be_an_identifier); + } + else if (catchClause.variableDeclaration.type) { + grammarErrorOnFirstToken(catchClause.variableDeclaration.type, Diagnostics.Catch_clause_variable_cannot_have_a_type_annotation); + } + else if (catchClause.variableDeclaration.initializer) { + grammarErrorOnFirstToken(catchClause.variableDeclaration.initializer, Diagnostics.Catch_clause_variable_cannot_have_an_initializer); + } + else { + let identifierName = (catchClause.variableDeclaration.name).text; + let locals = catchClause.block.locals; + if (locals && hasProperty(locals, identifierName)) { + let localSymbol = locals[identifierName] + if (localSymbol && (localSymbol.flags & SymbolFlags.BlockScopedVariable) !== 0) { + grammarErrorOnNode(localSymbol.valueDeclaration, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, identifierName); + } + } + + // It is a SyntaxError if a TryStatement with a Catch occurs within strict code and the Identifier of the + // Catch production is eval or arguments + checkGrammarEvalOrArgumentsInStrictMode(node, catchClause.variableDeclaration.name); + } + } + + checkBlock(catchClause.block); + } + + if (node.finallyBlock) { + checkBlock(node.finallyBlock); + } + } + + function checkIndexConstraints(type: Type) { + let declaredNumberIndexer = getIndexDeclarationOfSymbol(type.symbol, IndexKind.Number); + let declaredStringIndexer = getIndexDeclarationOfSymbol(type.symbol, IndexKind.String); + + let stringIndexType = getIndexTypeOfType(type, IndexKind.String); + let numberIndexType = getIndexTypeOfType(type, IndexKind.Number); + + if (stringIndexType || numberIndexType) { + forEach(getPropertiesOfObjectType(type), prop => { + let propType = getTypeOfSymbol(prop); + checkIndexConstraintForProperty(prop, propType, type, declaredStringIndexer, stringIndexType, IndexKind.String); + checkIndexConstraintForProperty(prop, propType, type, declaredNumberIndexer, numberIndexType, IndexKind.Number); + }); + + if (type.flags & TypeFlags.Class && type.symbol.valueDeclaration.kind === SyntaxKind.ClassDeclaration) { + let classDeclaration = type.symbol.valueDeclaration; + for (let member of classDeclaration.members) { + // Only process instance properties with computed names here. + // Static properties cannot be in conflict with indexers, + // and properties with literal names were already checked. + if (!(member.flags & NodeFlags.Static) && hasDynamicName(member)) { + let propType = getTypeOfSymbol(member.symbol); + checkIndexConstraintForProperty(member.symbol, propType, type, declaredStringIndexer, stringIndexType, IndexKind.String); + checkIndexConstraintForProperty(member.symbol, propType, type, declaredNumberIndexer, numberIndexType, IndexKind.Number); + } + } + } + } + + let errorNode: Node; + if (stringIndexType && numberIndexType) { + errorNode = declaredNumberIndexer || declaredStringIndexer; + // condition 'errorNode === undefined' may appear if types does not declare nor string neither number indexer + if (!errorNode && (type.flags & TypeFlags.Interface)) { + let someBaseTypeHasBothIndexers = forEach(getBaseTypes(type), base => getIndexTypeOfType(base, IndexKind.String) && getIndexTypeOfType(base, IndexKind.Number)); + errorNode = someBaseTypeHasBothIndexers ? undefined : type.symbol.declarations[0]; + } + } + + if (errorNode && !isTypeAssignableTo(numberIndexType, stringIndexType)) { + error(errorNode, Diagnostics.Numeric_index_type_0_is_not_assignable_to_string_index_type_1, + typeToString(numberIndexType), typeToString(stringIndexType)); + } + + function checkIndexConstraintForProperty( + prop: Symbol, + propertyType: Type, + containingType: Type, + indexDeclaration: Declaration, + indexType: Type, + indexKind: IndexKind): void { + + if (!indexType) { + return; + } + + // index is numeric and property name is not valid numeric literal + if (indexKind === IndexKind.Number && !isNumericName(prop.valueDeclaration.name)) { + return; + } + + // perform property check if property or indexer is declared in 'type' + // this allows to rule out cases when both property and indexer are inherited from the base class + let errorNode: Node; + if (prop.valueDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol) { + errorNode = prop.valueDeclaration; + } + else if (indexDeclaration) { + errorNode = indexDeclaration; + } + else if (containingType.flags & TypeFlags.Interface) { + // for interfaces property and indexer might be inherited from different bases + // check if any base class already has both property and indexer. + // check should be performed only if 'type' is the first type that brings property\indexer together + let someBaseClassHasBothPropertyAndIndexer = forEach(getBaseTypes(containingType), base => getPropertyOfObjectType(base, prop.name) && getIndexTypeOfType(base, indexKind)); + errorNode = someBaseClassHasBothPropertyAndIndexer ? undefined : containingType.symbol.declarations[0]; + } + + if (errorNode && !isTypeAssignableTo(propertyType, indexType)) { + let errorMessage = + indexKind === IndexKind.String + ? Diagnostics.Property_0_of_type_1_is_not_assignable_to_string_index_type_2 + : Diagnostics.Property_0_of_type_1_is_not_assignable_to_numeric_index_type_2; + error(errorNode, errorMessage, symbolToString(prop), typeToString(propertyType), typeToString(indexType)); + } + } + } + + function checkTypeNameIsReserved(name: DeclarationName, message: DiagnosticMessage): void { + // TS 1.0 spec (April 2014): 3.6.1 + // The predefined type keywords are reserved and cannot be used as names of user defined types. + switch ((name).text) { + case "any": + case "number": + case "boolean": + case "string": + case "symbol": + case "void": + error(name, message, (name).text); + } + } + + // Check each type parameter and check that list has no duplicate type parameter declarations + function checkTypeParameters(typeParameterDeclarations: TypeParameterDeclaration[]) { + if (typeParameterDeclarations) { + for (let i = 0, n = typeParameterDeclarations.length; i < n; i++) { + let node = typeParameterDeclarations[i]; + checkTypeParameter(node); + + if (produceDiagnostics) { + for (let j = 0; j < i; j++) { + if (typeParameterDeclarations[j].symbol === node.symbol) { + error(node.name, Diagnostics.Duplicate_identifier_0, declarationNameToString(node.name)); + } + } + } + } + } + } + + function checkClassExpression(node: ClassExpression): Type { + grammarErrorOnNode(node, Diagnostics.class_expressions_are_not_currently_supported); + forEach(node.members, checkSourceElement); + return unknownType; + } + + function checkClassDeclaration(node: ClassDeclaration) { + checkGrammarDeclarationNameInStrictMode(node); + // Grammar checking + if (node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) { + grammarErrorOnNode(node, Diagnostics.class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration); + } + + if (!node.name && !(node.flags & NodeFlags.Default)) { + grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); + } + + checkGrammarClassDeclarationHeritageClauses(node); + checkDecorators(node); + if (node.name) { + checkTypeNameIsReserved(node.name, Diagnostics.Class_name_cannot_be_0); + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + } + checkTypeParameters(node.typeParameters); + checkExportsOnMergedDeclarations(node); + let symbol = getSymbolOfNode(node); + let type = getDeclaredTypeOfSymbol(symbol); + let staticType = getTypeOfSymbol(symbol); + let baseTypeNode = getClassExtendsHeritageClauseElement(node); + if (baseTypeNode) { + if (!isSupportedHeritageClauseElement(baseTypeNode)) { + error(baseTypeNode.expression, Diagnostics.Only_identifiers_Slashqualified_names_with_optional_type_arguments_are_currently_supported_in_a_class_extends_clauses); + } + + emitExtends = emitExtends || !isInAmbientContext(node); + checkHeritageClauseElement(baseTypeNode); + } + let baseTypes = getBaseTypes(type); + if (baseTypes.length) { + if (produceDiagnostics) { + let baseType = baseTypes[0]; + checkTypeAssignableTo(type, baseType, node.name || node, Diagnostics.Class_0_incorrectly_extends_base_class_1); + let staticBaseType = getTypeOfSymbol(baseType.symbol); + checkTypeAssignableTo(staticType, getTypeWithoutConstructors(staticBaseType), node.name || node, + Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1); + + if (baseType.symbol !== resolveEntityName(baseTypeNode.expression, SymbolFlags.Value)) { + error(baseTypeNode, Diagnostics.Type_name_0_in_extends_clause_does_not_reference_constructor_function_for_0, typeToString(baseType)); + } + + checkKindsOfPropertyMemberOverrides(type, baseType); + } + } + + if (baseTypes.length || (baseTypeNode && compilerOptions.separateCompilation)) { + // Check that base type can be evaluated as expression + checkExpressionOrQualifiedName(baseTypeNode.expression); + } + + let implementedTypeNodes = getClassImplementsHeritageClauseElements(node); + if (implementedTypeNodes) { + forEach(implementedTypeNodes, typeRefNode => { + if (!isSupportedHeritageClauseElement(typeRefNode)) { + error(typeRefNode.expression, Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments); + } + + checkHeritageClauseElement(typeRefNode); + if (produceDiagnostics) { + let t = getTypeFromHeritageClauseElement(typeRefNode); + if (t !== unknownType) { + let declaredType = (t.flags & TypeFlags.Reference) ? (t).target : t; + if (declaredType.flags & (TypeFlags.Class | TypeFlags.Interface)) { + checkTypeAssignableTo(type, t, node.name || node, Diagnostics.Class_0_incorrectly_implements_interface_1); + } + else { + error(typeRefNode, Diagnostics.A_class_may_only_implement_another_class_or_interface); + } + } + } + }); + } + + forEach(node.members, checkSourceElement); + if (produceDiagnostics) { + checkIndexConstraints(type); + checkTypeForDuplicateIndexSignatures(node); + } + } + + function getTargetSymbol(s: Symbol) { + // if symbol is instantiated its flags are not copied from the 'target' + // so we'll need to get back original 'target' symbol to work with correct set of flags + return s.flags & SymbolFlags.Instantiated ? getSymbolLinks(s).target : s; + } + + function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: ObjectType): void { + + // TypeScript 1.0 spec (April 2014): 8.2.3 + // A derived class inherits all members from its base class it doesn't override. + // Inheritance means that a derived class implicitly contains all non - overridden members of the base class. + // Both public and private property members are inherited, but only public property members can be overridden. + // A property member in a derived class is said to override a property member in a base class + // when the derived class property member has the same name and kind(instance or static) + // as the base class property member. + // The type of an overriding property member must be assignable(section 3.8.4) + // to the type of the overridden property member, or otherwise a compile - time error occurs. + // Base class instance member functions can be overridden by derived class instance member functions, + // but not by other kinds of members. + // Base class instance member variables and accessors can be overridden by + // derived class instance member variables and accessors, but not by other kinds of members. + + // NOTE: assignability is checked in checkClassDeclaration + let baseProperties = getPropertiesOfObjectType(baseType); + for (let baseProperty of baseProperties) { + let base = getTargetSymbol(baseProperty); + + if (base.flags & SymbolFlags.Prototype) { + continue; + } + + let derived = getTargetSymbol(getPropertyOfObjectType(type, base.name)); + if (derived) { + let baseDeclarationFlags = getDeclarationFlagsFromSymbol(base); + let derivedDeclarationFlags = getDeclarationFlagsFromSymbol(derived); + if ((baseDeclarationFlags & NodeFlags.Private) || (derivedDeclarationFlags & NodeFlags.Private)) { + // either base or derived property is private - not override, skip it + continue; + } + + if ((baseDeclarationFlags & NodeFlags.Static) !== (derivedDeclarationFlags & NodeFlags.Static)) { + // value of 'static' is not the same for properties - not override, skip it + continue; + } + + if ((base.flags & derived.flags & SymbolFlags.Method) || ((base.flags & SymbolFlags.PropertyOrAccessor) && (derived.flags & SymbolFlags.PropertyOrAccessor))) { + // method is overridden with method or property/accessor is overridden with property/accessor - correct case + continue; + } + + let errorMessage: DiagnosticMessage; + if (base.flags & SymbolFlags.Method) { + if (derived.flags & SymbolFlags.Accessor) { + errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor; + } + else { + Debug.assert((derived.flags & SymbolFlags.Property) !== 0); + errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property; + } + } + else if (base.flags & SymbolFlags.Property) { + Debug.assert((derived.flags & SymbolFlags.Method) !== 0); + errorMessage = Diagnostics.Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function; + } + else { + Debug.assert((base.flags & SymbolFlags.Accessor) !== 0); + Debug.assert((derived.flags & SymbolFlags.Method) !== 0); + errorMessage = Diagnostics.Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function; + } + + error(derived.valueDeclaration.name, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type)); + } + } + } + + function isAccessor(kind: SyntaxKind): boolean { + return kind === SyntaxKind.GetAccessor || kind === SyntaxKind.SetAccessor; + } + + function areTypeParametersIdentical(list1: TypeParameterDeclaration[], list2: TypeParameterDeclaration[]) { + if (!list1 && !list2) { + return true; + } + if (!list1 || !list2 || list1.length !== list2.length) { + return false; + } + // TypeScript 1.0 spec (April 2014): + // When a generic interface has multiple declarations, all declarations must have identical type parameter + // lists, i.e. identical type parameter names with identical constraints in identical order. + for (let i = 0, len = list1.length; i < len; i++) { + let tp1 = list1[i]; + let tp2 = list2[i]; + if (tp1.name.text !== tp2.name.text) { + return false; + } + if (!tp1.constraint && !tp2.constraint) { + continue; + } + if (!tp1.constraint || !tp2.constraint) { + return false; + } + if (!isTypeIdenticalTo(getTypeFromTypeNode(tp1.constraint), getTypeFromTypeNode(tp2.constraint))) { + return false; + } + } + return true; + } + + function checkInheritedPropertiesAreIdentical(type: InterfaceType, typeNode: Node): boolean { + let baseTypes = getBaseTypes(type); + if (baseTypes.length < 2) { + return true; + } + + let seen: Map<{ prop: Symbol; containingType: Type }> = {}; + forEach(resolveDeclaredMembers(type).declaredProperties, p => { seen[p.name] = { prop: p, containingType: type }; }); + let ok = true; + + for (let base of baseTypes) { + let properties = getPropertiesOfObjectType(base); + for (let prop of properties) { + if (!hasProperty(seen, prop.name)) { + seen[prop.name] = { prop: prop, containingType: base }; + } + else { + let existing = seen[prop.name]; + let isInheritedProperty = existing.containingType !== type; + if (isInheritedProperty && !isPropertyIdenticalTo(existing.prop, prop)) { + ok = false; + + let typeName1 = typeToString(existing.containingType); + let typeName2 = typeToString(base); + + let errorInfo = chainDiagnosticMessages(undefined, Diagnostics.Named_property_0_of_types_1_and_2_are_not_identical, symbolToString(prop), typeName1, typeName2); + errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, typeToString(type), typeName1, typeName2); + diagnostics.add(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo)); + } + } + } + } + + return ok; + } + + function checkInterfaceDeclaration(node: InterfaceDeclaration) { + // Grammar checking + checkGrammarDeclarationNameInStrictMode(node) || checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarInterfaceDeclaration(node); + + checkTypeParameters(node.typeParameters); + if (produceDiagnostics) { + checkTypeNameIsReserved(node.name, Diagnostics.Interface_name_cannot_be_0); + + checkExportsOnMergedDeclarations(node); + let symbol = getSymbolOfNode(node); + let firstInterfaceDecl = getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); + if (symbol.declarations.length > 1) { + if (node !== firstInterfaceDecl && !areTypeParametersIdentical(firstInterfaceDecl.typeParameters, node.typeParameters)) { + error(node.name, Diagnostics.All_declarations_of_an_interface_must_have_identical_type_parameters); + } + } + + // Only check this symbol once + if (node === firstInterfaceDecl) { + let type = getDeclaredTypeOfSymbol(symbol); + // run subsequent checks only if first set succeeded + if (checkInheritedPropertiesAreIdentical(type, node.name)) { + forEach(getBaseTypes(type), baseType => { + checkTypeAssignableTo(type, baseType, node.name, Diagnostics.Interface_0_incorrectly_extends_interface_1); + }); + checkIndexConstraints(type); + } + } + } + forEach(getInterfaceBaseTypeNodes(node), heritageElement => { + if (!isSupportedHeritageClauseElement(heritageElement)) { + error(heritageElement.expression, Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments); + } + + checkHeritageClauseElement(heritageElement); + }); + forEach(node.members, checkSourceElement); + + if (produceDiagnostics) { + checkTypeForDuplicateIndexSignatures(node); + } + } + + function checkTypeAliasDeclaration(node: TypeAliasDeclaration) { + // Grammar checking + checkGrammarDecorators(node) || checkGrammarModifiers(node); + + checkTypeNameIsReserved(node.name, Diagnostics.Type_alias_name_cannot_be_0); + checkSourceElement(node.type); + } + + function computeEnumMemberValues(node: EnumDeclaration) { + let nodeLinks = getNodeLinks(node); + + if (!(nodeLinks.flags & NodeCheckFlags.EnumValuesComputed)) { + let enumSymbol = getSymbolOfNode(node); + let enumType = getDeclaredTypeOfSymbol(enumSymbol); + let autoValue = 0; + let ambient = isInAmbientContext(node); + let enumIsConst = isConst(node); + + forEach(node.members, member => { + if (member.name.kind !== SyntaxKind.ComputedPropertyName && isNumericLiteralName((member.name).text)) { + error(member.name, Diagnostics.An_enum_member_cannot_have_a_numeric_name); + } + let initializer = member.initializer; + if (initializer) { + autoValue = getConstantValueForEnumMemberInitializer(initializer); + if (autoValue === undefined) { + if (enumIsConst) { + error(initializer, Diagnostics.In_const_enum_declarations_member_initializer_must_be_constant_expression); + } + else if (!ambient) { + // Only here do we need to check that the initializer is assignable to the enum type. + // If it is a constant value (not undefined), it is syntactically constrained to be a number. + // Also, we do not need to check this for ambients because there is already + // a syntax error if it is not a constant. + checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*headMessage*/ undefined); + } + } + else if (enumIsConst) { + if (isNaN(autoValue)) { + error(initializer, Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN); + } + else if (!isFinite(autoValue)) { + error(initializer, Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value); + } + } + + } + else if (ambient && !enumIsConst) { + autoValue = undefined; + } + + if (autoValue !== undefined) { + getNodeLinks(member).enumMemberValue = autoValue++; + } + }); + + nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed; + } + + function getConstantValueForEnumMemberInitializer(initializer: Expression): number { + return evalConstant(initializer); + + function evalConstant(e: Node): number { + switch (e.kind) { + case SyntaxKind.PrefixUnaryExpression: + let value = evalConstant((e).operand); + if (value === undefined) { + return undefined; + } + switch ((e).operator) { + case SyntaxKind.PlusToken: return value; + case SyntaxKind.MinusToken: return -value; + case SyntaxKind.TildeToken: return ~value; + } + return undefined; + case SyntaxKind.BinaryExpression: + let left = evalConstant((e).left); + if (left === undefined) { + return undefined; + } + let right = evalConstant((e).right); + if (right === undefined) { + return undefined; + } + switch ((e).operatorToken.kind) { + case SyntaxKind.BarToken: return left | right; + case SyntaxKind.AmpersandToken: return left & right; + case SyntaxKind.GreaterThanGreaterThanToken: return left >> right; + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return left >>> right; + case SyntaxKind.LessThanLessThanToken: return left << right; + case SyntaxKind.CaretToken: return left ^ right; + case SyntaxKind.AsteriskToken: return left * right; + case SyntaxKind.SlashToken: return left / right; + case SyntaxKind.PlusToken: return left + right; + case SyntaxKind.MinusToken: return left - right; + case SyntaxKind.PercentToken: return left % right; + } + return undefined; + case SyntaxKind.NumericLiteral: + return +(e).text; + case SyntaxKind.ParenthesizedExpression: + return evalConstant((e).expression); + case SyntaxKind.Identifier: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.PropertyAccessExpression: + let member = initializer.parent; + let currentType = getTypeOfSymbol(getSymbolOfNode(member.parent)); + let enumType: Type; + let propertyName: string; + + if (e.kind === SyntaxKind.Identifier) { + // unqualified names can refer to member that reside in different declaration of the enum so just doing name resolution won't work. + // instead pick current enum type and later try to fetch member from the type + enumType = currentType; + propertyName = (e).text; + } + else { + let expression: Expression; + if (e.kind === SyntaxKind.ElementAccessExpression) { + if ((e).argumentExpression === undefined || + (e).argumentExpression.kind !== SyntaxKind.StringLiteral) { + return undefined; + } + expression = (e).expression; + propertyName = ((e).argumentExpression).text; + } + else { + expression = (e).expression; + propertyName = (e).name.text; + } + + // expression part in ElementAccess\PropertyAccess should be either identifier or dottedName + var current = expression; + while (current) { + if (current.kind === SyntaxKind.Identifier) { + break; + } + else if (current.kind === SyntaxKind.PropertyAccessExpression) { + current = (current).expression; + } + else { + return undefined; + } + } + + enumType = checkExpression(expression); + // allow references to constant members of other enums + if (!(enumType.symbol && (enumType.symbol.flags & SymbolFlags.Enum))) { + return undefined; + } + } + + if (propertyName === undefined) { + return undefined; + } + + let property = getPropertyOfObjectType(enumType, propertyName); + if (!property || !(property.flags & SymbolFlags.EnumMember)) { + return undefined; + } + + let propertyDecl = property.valueDeclaration; + // self references are illegal + if (member === propertyDecl) { + return undefined; + } + + // illegal case: forward reference + if (!isDefinedBefore(propertyDecl, member)) { + return undefined; + } + + return getNodeLinks(propertyDecl).enumMemberValue; + } + } + } + } + + function checkEnumDeclaration(node: EnumDeclaration) { + if (!produceDiagnostics) { + return; + } + + // Grammar checking + checkGrammarDeclarationNameInStrictMode(node) || checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarEnumDeclaration(node); + + checkTypeNameIsReserved(node.name, Diagnostics.Enum_name_cannot_be_0); + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + checkExportsOnMergedDeclarations(node); + + computeEnumMemberValues(node); + + let enumIsConst = isConst(node); + if (compilerOptions.separateCompilation && enumIsConst && isInAmbientContext(node)) { + error(node.name, Diagnostics.Ambient_const_enums_are_not_allowed_when_the_separateCompilation_flag_is_provided); + } + + // Spec 2014 - Section 9.3: + // It isn't possible for one enum declaration to continue the automatic numbering sequence of another, + // and when an enum type has multiple declarations, only one declaration is permitted to omit a value + // for the first member. + // + // Only perform this check once per symbol + let enumSymbol = getSymbolOfNode(node); + let firstDeclaration = getDeclarationOfKind(enumSymbol, node.kind); + if (node === firstDeclaration) { + if (enumSymbol.declarations.length > 1) { + // check that const is placed\omitted on all enum declarations + forEach(enumSymbol.declarations, decl => { + if (isConstEnumDeclaration(decl) !== enumIsConst) { + error(decl.name, Diagnostics.Enum_declarations_must_all_be_const_or_non_const); + } + }); + } + + let seenEnumMissingInitialInitializer = false; + forEach(enumSymbol.declarations, declaration => { + // return true if we hit a violation of the rule, false otherwise + if (declaration.kind !== SyntaxKind.EnumDeclaration) { + return false; + } + + let enumDeclaration = declaration; + if (!enumDeclaration.members.length) { + return false; + } + + let firstEnumMember = enumDeclaration.members[0]; + if (!firstEnumMember.initializer) { + if (seenEnumMissingInitialInitializer) { + error(firstEnumMember.name, Diagnostics.In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element); + } + else { + seenEnumMissingInitialInitializer = true; + } + } + }); + } + } + + function getFirstNonAmbientClassOrFunctionDeclaration(symbol: Symbol): Declaration { + let declarations = symbol.declarations; + for (let declaration of declarations) { + if ((declaration.kind === SyntaxKind.ClassDeclaration || + (declaration.kind === SyntaxKind.FunctionDeclaration && nodeIsPresent((declaration).body))) && + !isInAmbientContext(declaration)) { + return declaration; + } + } + return undefined; + } + + function inSameLexicalScope(node1: Node, node2: Node) { + let container1 = getEnclosingBlockScopeContainer(node1); + let container2 = getEnclosingBlockScopeContainer(node2); + if (isGlobalSourceFile(container1)) { + return isGlobalSourceFile(container2); + } + else if (isGlobalSourceFile(container2)) { + return false; + } + else { + return container1 === container2; + } + } + + function checkModuleDeclaration(node: ModuleDeclaration) { + if (produceDiagnostics) { + // Grammar checking + if (!checkGrammarDeclarationNameInStrictMode(node) && !checkGrammarDecorators(node) && !checkGrammarModifiers(node)) { + if (!isInAmbientContext(node) && node.name.kind === SyntaxKind.StringLiteral) { + grammarErrorOnNode(node.name, Diagnostics.Only_ambient_modules_can_use_quoted_names); + } + } + + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + checkExportsOnMergedDeclarations(node); + let symbol = getSymbolOfNode(node); + + // The following checks only apply on a non-ambient instantiated module declaration. + if (symbol.flags & SymbolFlags.ValueModule + && symbol.declarations.length > 1 + && !isInAmbientContext(node) + && isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.separateCompilation)) { + let firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol); + if (firstNonAmbientClassOrFunc) { + if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) { + error(node.name, Diagnostics.A_module_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged); + } + else if (node.pos < firstNonAmbientClassOrFunc.pos) { + error(node.name, Diagnostics.A_module_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged); + } + } + + // if the module merges with a class declaration in the same lexical scope, + // we need to track this to ensure the correct emit. + let mergedClass = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration); + if (mergedClass && + inSameLexicalScope(node, mergedClass)) { + getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass; + } + } + + // Checks for ambient external modules. + if (node.name.kind === SyntaxKind.StringLiteral) { + if (!isGlobalSourceFile(node.parent)) { + error(node.name, Diagnostics.Ambient_external_modules_cannot_be_nested_in_other_modules); + } + if (isExternalModuleNameRelative(node.name.text)) { + error(node.name, Diagnostics.Ambient_external_module_declaration_cannot_specify_relative_module_name); + } + } + } + checkSourceElement(node.body); + } + + function getFirstIdentifier(node: EntityName | Expression): Identifier { + while (true) { + if (node.kind === SyntaxKind.QualifiedName) { + node = (node).left; + } + else if (node.kind === SyntaxKind.PropertyAccessExpression) { + node = (node).expression; + } + else { + break; + } + } + Debug.assert(node.kind === SyntaxKind.Identifier); + return node; + } + + function checkExternalImportOrExportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): boolean { + let moduleName = getExternalModuleName(node); + if (!nodeIsMissing(moduleName) && moduleName.kind !== SyntaxKind.StringLiteral) { + error(moduleName, Diagnostics.String_literal_expected); + return false; + } + let inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && (node.parent.parent).name.kind === SyntaxKind.StringLiteral; + if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule) { + error(moduleName, node.kind === SyntaxKind.ExportDeclaration ? + Diagnostics.Export_declarations_are_not_permitted_in_an_internal_module : + Diagnostics.Import_declarations_in_an_internal_module_cannot_reference_an_external_module); + return false; + } + if (inAmbientExternalModule && isExternalModuleNameRelative((moduleName).text)) { + // TypeScript 1.0 spec (April 2013): 12.1.6 + // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference + // other external modules only through top - level external module names. + // Relative external module names are not permitted. + error(node, Diagnostics.Import_or_export_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name); + return false; + } + return true; + } + + function checkAliasSymbol(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportSpecifier | ExportSpecifier) { + let symbol = getSymbolOfNode(node); + let target = resolveAlias(symbol); + if (target !== unknownSymbol) { + let excludedMeanings = + (symbol.flags & SymbolFlags.Value ? SymbolFlags.Value : 0) | + (symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) | + (symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0); + if (target.flags & excludedMeanings) { + let message = node.kind === SyntaxKind.ExportSpecifier ? + Diagnostics.Export_declaration_conflicts_with_exported_declaration_of_0 : + Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0; + error(node, message, symbolToString(symbol)); + } + } + } + + function checkImportBinding(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportSpecifier) { + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); + checkAliasSymbol(node); + } + + function checkImportDeclaration(node: ImportDeclaration) { + if (!checkGrammarImportDeclarationNameInStrictMode(node) && !checkGrammarDecorators(node) && !checkGrammarModifiers(node) && (node.flags & NodeFlags.Modifier)) { + grammarErrorOnFirstToken(node, Diagnostics.An_import_declaration_cannot_have_modifiers); + } + if (checkExternalImportOrExportDeclaration(node)) { + let importClause = node.importClause; + if (importClause) { + if (importClause.name) { + checkImportBinding(importClause); + } + if (importClause.namedBindings) { + if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + checkImportBinding(importClause.namedBindings); + } + else { + forEach((importClause.namedBindings).elements, checkImportBinding); + } + } + } + } + } + + function checkImportEqualsDeclaration(node: ImportEqualsDeclaration) { + checkGrammarDeclarationNameInStrictMode(node) || checkGrammarDecorators(node) || checkGrammarModifiers(node); + if (isInternalModuleImportEqualsDeclaration(node) || checkExternalImportOrExportDeclaration(node)) { + checkImportBinding(node); + if (node.flags & NodeFlags.Export) { + markExportAsReferenced(node); + } + if (isInternalModuleImportEqualsDeclaration(node)) { + let target = resolveAlias(getSymbolOfNode(node)); + if (target !== unknownSymbol) { + if (target.flags & SymbolFlags.Value) { + // Target is a value symbol, check that it is not hidden by a local declaration with the same name + let moduleName = getFirstIdentifier(node.moduleReference); + if (!(resolveEntityName(moduleName, SymbolFlags.Value | SymbolFlags.Namespace).flags & SymbolFlags.Namespace)) { + error(moduleName, Diagnostics.Module_0_is_hidden_by_a_local_declaration_with_the_same_name, declarationNameToString(moduleName)); + } + } + if (target.flags & SymbolFlags.Type) { + checkTypeNameIsReserved(node.name, Diagnostics.Import_name_cannot_be_0); + } + } + } + else { + if (languageVersion >= ScriptTarget.ES6) { + // Import equals declaration is deprecated in es6 or above + grammarErrorOnNode(node, Diagnostics.Import_assignment_cannot_be_used_when_targeting_ECMAScript_6_or_higher_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_or_import_d_from_mod_instead); + } + } + } + } + + function checkExportDeclaration(node: ExportDeclaration) { + if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && (node.flags & NodeFlags.Modifier)) { + grammarErrorOnFirstToken(node, Diagnostics.An_export_declaration_cannot_have_modifiers); + } + if (!node.moduleSpecifier || checkExternalImportOrExportDeclaration(node)) { + if (node.exportClause) { + // export { x, y } + // export { x, y } from "foo" + forEach(node.exportClause.elements, checkExportSpecifier); + + let inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && (node.parent.parent).name.kind === SyntaxKind.StringLiteral; + if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule) { + error(node, Diagnostics.Export_declarations_are_not_permitted_in_an_internal_module); + } + } + else { + // export * from "foo" + let moduleSymbol = resolveExternalModuleName(node, node.moduleSpecifier); + if (moduleSymbol && moduleSymbol.exports["export="]) { + error(node.moduleSpecifier, Diagnostics.External_module_0_uses_export_and_cannot_be_used_with_export_Asterisk, symbolToString(moduleSymbol)); + } + } + } + } + + function checkExportSpecifier(node: ExportSpecifier) { + checkAliasSymbol(node); + if (!(node.parent.parent).moduleSpecifier) { + markExportAsReferenced(node); + } + } + + function checkExportAssignment(node: ExportAssignment) { + let container = node.parent.kind === SyntaxKind.SourceFile ? node.parent : node.parent.parent; + if (container.kind === SyntaxKind.ModuleDeclaration && (container).name.kind === SyntaxKind.Identifier) { + error(node, Diagnostics.An_export_assignment_cannot_be_used_in_an_internal_module); + return; + } + // Grammar checking + if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && (node.flags & NodeFlags.Modifier)) { + grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers); + } + if (node.expression.kind === SyntaxKind.Identifier) { + markExportAsReferenced(node); + } + else { + checkExpressionCached(node.expression); + } + checkExternalModuleExports(container); + + if (node.isExportEquals && languageVersion >= ScriptTarget.ES6) { + // export assignment is deprecated in es6 or above + grammarErrorOnNode(node, Diagnostics.Export_assignment_cannot_be_used_when_targeting_ECMAScript_6_or_higher_Consider_using_export_default_instead); + } + } + + function getModuleStatements(node: Declaration): ModuleElement[] { + if (node.kind === SyntaxKind.SourceFile) { + return (node).statements; + } + if (node.kind === SyntaxKind.ModuleDeclaration && (node).body.kind === SyntaxKind.ModuleBlock) { + return ((node).body).statements; + } + return emptyArray; + } + + function hasExportedMembers(moduleSymbol: Symbol) { + for (var id in moduleSymbol.exports) { + if (id !== "export=") { + return true; + } + } + return false; + } + + function checkExternalModuleExports(node: SourceFile | ModuleDeclaration) { + let moduleSymbol = getSymbolOfNode(node); + let links = getSymbolLinks(moduleSymbol); + if (!links.exportsChecked) { + let exportEqualsSymbol = moduleSymbol.exports["export="]; + if (exportEqualsSymbol && hasExportedMembers(moduleSymbol)) { + let declaration = getDeclarationOfAliasSymbol(exportEqualsSymbol) || exportEqualsSymbol.valueDeclaration; + error(declaration, Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements); + } + links.exportsChecked = true; + } + } + + function checkSourceElement(node: Node): void { + if (!node) return; + switch (node.kind) { + case SyntaxKind.TypeParameter: + return checkTypeParameter(node); + case SyntaxKind.Parameter: + return checkParameter(node); + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + return checkPropertyDeclaration(node); + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + return checkSignatureDeclaration(node); + case SyntaxKind.IndexSignature: + return checkSignatureDeclaration(node); + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + return checkMethodDeclaration(node); + case SyntaxKind.Constructor: + return checkConstructorDeclaration(node); + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return checkAccessorDeclaration(node); + case SyntaxKind.TypeReference: + return checkTypeReferenceNode(node); + case SyntaxKind.TypeQuery: + return checkTypeQuery(node); + case SyntaxKind.TypeLiteral: + return checkTypeLiteral(node); + case SyntaxKind.ArrayType: + return checkArrayType(node); + case SyntaxKind.TupleType: + return checkTupleType(node); + case SyntaxKind.UnionType: + return checkUnionType(node); + case SyntaxKind.ParenthesizedType: + return checkSourceElement((node).type); + case SyntaxKind.FunctionDeclaration: + return checkFunctionDeclaration(node); + case SyntaxKind.Block: + case SyntaxKind.ModuleBlock: + return checkBlock(node); + case SyntaxKind.VariableStatement: + return checkVariableStatement(node); + case SyntaxKind.ExpressionStatement: + return checkExpressionStatement(node); + case SyntaxKind.IfStatement: + return checkIfStatement(node); + case SyntaxKind.DoStatement: + return checkDoStatement(node); + case SyntaxKind.WhileStatement: + return checkWhileStatement(node); + case SyntaxKind.ForStatement: + return checkForStatement(node); + case SyntaxKind.ForInStatement: + return checkForInStatement(node); + case SyntaxKind.ForOfStatement: + return checkForOfStatement(node); + case SyntaxKind.ContinueStatement: + case SyntaxKind.BreakStatement: + return checkBreakOrContinueStatement(node); + case SyntaxKind.ReturnStatement: + return checkReturnStatement(node); + case SyntaxKind.WithStatement: + return checkWithStatement(node); + case SyntaxKind.SwitchStatement: + return checkSwitchStatement(node); + case SyntaxKind.LabeledStatement: + return checkLabeledStatement(node); + case SyntaxKind.ThrowStatement: + return checkThrowStatement(node); + case SyntaxKind.TryStatement: + return checkTryStatement(node); + case SyntaxKind.VariableDeclaration: + return checkVariableDeclaration(node); + case SyntaxKind.BindingElement: + return checkBindingElement(node); + case SyntaxKind.ClassDeclaration: + return checkClassDeclaration(node); + case SyntaxKind.InterfaceDeclaration: + return checkInterfaceDeclaration(node); + case SyntaxKind.TypeAliasDeclaration: + return checkTypeAliasDeclaration(node); + case SyntaxKind.EnumDeclaration: + return checkEnumDeclaration(node); + case SyntaxKind.ModuleDeclaration: + return checkModuleDeclaration(node); + case SyntaxKind.ImportDeclaration: + return checkImportDeclaration(node); + case SyntaxKind.ImportEqualsDeclaration: + return checkImportEqualsDeclaration(node); + case SyntaxKind.ExportDeclaration: + return checkExportDeclaration(node); + case SyntaxKind.ExportAssignment: + return checkExportAssignment(node); + case SyntaxKind.EmptyStatement: + checkGrammarStatementInAmbientContext(node); + return; + case SyntaxKind.DebuggerStatement: + checkGrammarStatementInAmbientContext(node); + return; + case SyntaxKind.MissingDeclaration: + return checkMissingDeclaration(node); + } + } + + // Function expression bodies are checked after all statements in the enclosing body. This is to ensure + // constructs like the following are permitted: + // let foo = function () { + // let s = foo(); + // return "hello"; + // } + // Here, performing a full type check of the body of the function expression whilst in the process of + // determining the type of foo would cause foo to be given type any because of the recursive reference. + // Delaying the type check of the body ensures foo has been assigned a type. + function checkFunctionExpressionBodies(node: Node): void { + switch (node.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + forEach((node).parameters, checkFunctionExpressionBodies); + checkFunctionExpressionOrObjectLiteralMethodBody(node); + break; + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + forEach((node).parameters, checkFunctionExpressionBodies); + if (isObjectLiteralMethod(node)) { + checkFunctionExpressionOrObjectLiteralMethodBody(node); + } + break; + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionDeclaration: + forEach((node).parameters, checkFunctionExpressionBodies); + break; + case SyntaxKind.WithStatement: + checkFunctionExpressionBodies((node).expression); + break; + case SyntaxKind.Parameter: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.BindingElement: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + case SyntaxKind.TaggedTemplateExpression: + case SyntaxKind.TemplateExpression: + case SyntaxKind.TemplateSpan: + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.TypeOfExpression: + case SyntaxKind.VoidExpression: + case SyntaxKind.DeleteExpression: + case SyntaxKind.PrefixUnaryExpression: + case SyntaxKind.PostfixUnaryExpression: + case SyntaxKind.BinaryExpression: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.SpreadElementExpression: + case SyntaxKind.Block: + case SyntaxKind.ModuleBlock: + case SyntaxKind.VariableStatement: + case SyntaxKind.ExpressionStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.ContinueStatement: + case SyntaxKind.BreakStatement: + case SyntaxKind.ReturnStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.CaseBlock: + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + case SyntaxKind.LabeledStatement: + case SyntaxKind.ThrowStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.CatchClause: + case SyntaxKind.VariableDeclaration: + case SyntaxKind.VariableDeclarationList: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.EnumMember: + case SyntaxKind.ExportAssignment: + case SyntaxKind.SourceFile: + forEachChild(node, checkFunctionExpressionBodies); + break; + } + } + + function checkSourceFile(node: SourceFile) { + let start = new Date().getTime(); + checkSourceFileWorker(node); + checkTime += new Date().getTime() - start; + } + + // Fully type check a source file and collect the relevant diagnostics. + function checkSourceFileWorker(node: SourceFile) { + let links = getNodeLinks(node); + if (!(links.flags & NodeCheckFlags.TypeChecked)) { + // Grammar checking + checkGrammarSourceFile(node); + + emitExtends = false; + emitDecorate = false; + emitParam = false; + potentialThisCollisions.length = 0; + + forEach(node.statements, checkSourceElement); + checkFunctionExpressionBodies(node); + + if (isExternalModule(node)) { + checkExternalModuleExports(node); + } + + if (potentialThisCollisions.length) { + forEach(potentialThisCollisions, checkIfThisIsCapturedInEnclosingScope); + potentialThisCollisions.length = 0; + } + + if (emitExtends) { + links.flags |= NodeCheckFlags.EmitExtends; + } + + if (emitDecorate) { + links.flags |= NodeCheckFlags.EmitDecorate; + } + + if (emitParam) { + links.flags |= NodeCheckFlags.EmitParam; + } + + links.flags |= NodeCheckFlags.TypeChecked; + } + } + + function getDiagnostics(sourceFile?: SourceFile): Diagnostic[] { + throwIfNonDiagnosticsProducing(); + if (sourceFile) { + checkSourceFile(sourceFile); + return diagnostics.getDiagnostics(sourceFile.fileName); + } + forEach(host.getSourceFiles(), checkSourceFile); + return diagnostics.getDiagnostics(); + } + + function getGlobalDiagnostics(): Diagnostic[] { + throwIfNonDiagnosticsProducing(); + return diagnostics.getGlobalDiagnostics(); + } + + function throwIfNonDiagnosticsProducing() { + if (!produceDiagnostics) { + throw new Error("Trying to get diagnostics from a type checker that does not produce them."); + } + } + + // Language service support + + function isInsideWithStatementBody(node: Node): boolean { + if (node) { + while (node.parent) { + if (node.parent.kind === SyntaxKind.WithStatement && (node.parent).statement === node) { + return true; + } + node = node.parent; + } + } + + return false; + } + + function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[] { + let symbols: SymbolTable = {}; + let memberFlags: NodeFlags = 0; + + if (isInsideWithStatementBody(location)) { + // We cannot answer semantic questions within a with block, do not proceed any further + return []; + } + + populateSymbols(); + + return symbolsToArray(symbols); + + function populateSymbols() { + while (location) { + if (location.locals && !isGlobalSourceFile(location)) { + copySymbols(location.locals, meaning); + } + + switch (location.kind) { + case SyntaxKind.SourceFile: + if (!isExternalModule(location)) { + break; + } + case SyntaxKind.ModuleDeclaration: + copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.ModuleMember); + break; + case SyntaxKind.EnumDeclaration: + copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.EnumMember); + break; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + if (!(memberFlags & NodeFlags.Static)) { + copySymbols(getSymbolOfNode(location).members, meaning & SymbolFlags.Type); + } + break; + case SyntaxKind.FunctionExpression: + if ((location).name) { + copySymbol(location.symbol, meaning); + } + break; + } + + memberFlags = location.flags; + location = location.parent; + } + + copySymbols(globals, meaning); + } + + // Returns 'true' if we should stop processing symbols. + function copySymbol(symbol: Symbol, meaning: SymbolFlags): void { + if (symbol.flags & meaning) { + let id = symbol.name; + if (!isReservedMemberName(id) && !hasProperty(symbols, id)) { + symbols[id] = symbol; + } + } + } + + function copySymbols(source: SymbolTable, meaning: SymbolFlags): void { + if (meaning) { + for (let id in source) { + if (hasProperty(source, id)) { + copySymbol(source[id], meaning); + } + } + } + } + + if (isInsideWithStatementBody(location)) { + // We cannot answer semantic questions within a with block, do not proceed any further + return []; + } + + while (location) { + if (location.locals && !isGlobalSourceFile(location)) { + copySymbols(location.locals, meaning); + } + switch (location.kind) { + case SyntaxKind.SourceFile: + if (!isExternalModule(location)) break; + case SyntaxKind.ModuleDeclaration: + copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.ModuleMember); + break; + case SyntaxKind.EnumDeclaration: + copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.EnumMember); + break; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + if (!(memberFlags & NodeFlags.Static)) { + copySymbols(getSymbolOfNode(location).members, meaning & SymbolFlags.Type); + } + break; + case SyntaxKind.FunctionExpression: + if ((location).name) { + copySymbol(location.symbol, meaning); + } + break; + } + memberFlags = location.flags; + location = location.parent; + } + copySymbols(globals, meaning); + return symbolsToArray(symbols); + } + + function isTypeDeclarationName(name: Node): boolean { + return name.kind == SyntaxKind.Identifier && + isTypeDeclaration(name.parent) && + (name.parent).name === name; + } + + function isTypeDeclaration(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.TypeParameter: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.EnumDeclaration: + return true; + } + } + + // True if the given identifier is part of a type reference + function isTypeReferenceIdentifier(entityName: EntityName): boolean { + let node: Node = entityName; + while (node.parent && node.parent.kind === SyntaxKind.QualifiedName) { + node = node.parent; + } + + return node.parent && node.parent.kind === SyntaxKind.TypeReference; + } + + function isHeritageClauseElementIdentifier(entityName: Node): boolean { + let node = entityName; + while (node.parent && node.parent.kind === SyntaxKind.PropertyAccessExpression) { + node = node.parent; + } + + return node.parent && node.parent.kind === SyntaxKind.HeritageClauseElement; + } + + function isTypeNode(node: Node): boolean { + if (SyntaxKind.FirstTypeNode <= node.kind && node.kind <= SyntaxKind.LastTypeNode) { + return true; + } + + switch (node.kind) { + case SyntaxKind.AnyKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.SymbolKeyword: + return true; + case SyntaxKind.VoidKeyword: + return node.parent.kind !== SyntaxKind.VoidExpression; + case SyntaxKind.StringLiteral: + // Specialized signatures can have string literals as their parameters' type names + return node.parent.kind === SyntaxKind.Parameter; + case SyntaxKind.HeritageClauseElement: + return true; + + // Identifiers and qualified names may be type nodes, depending on their context. Climb + // above them to find the lowest container + case SyntaxKind.Identifier: + // If the identifier is the RHS of a qualified name, then it's a type iff its parent is. + if (node.parent.kind === SyntaxKind.QualifiedName && (node.parent).right === node) { + node = node.parent; + } + else if (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent).name === node) { + node = node.parent; + } + // fall through + case SyntaxKind.QualifiedName: + case SyntaxKind.PropertyAccessExpression: + // At this point, node is either a qualified name or an identifier + Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression, + "'node' was expected to be a qualified name, identifier or property access in 'isTypeNode'."); + + let parent = node.parent; + if (parent.kind === SyntaxKind.TypeQuery) { + return false; + } + // Do not recursively call isTypeNode on the parent. In the example: + // + // let a: A.B.C; + // + // Calling isTypeNode would consider the qualified name A.B a type node. Only C or + // A.B.C is a type node. + if (SyntaxKind.FirstTypeNode <= parent.kind && parent.kind <= SyntaxKind.LastTypeNode) { + return true; + } + switch (parent.kind) { + case SyntaxKind.HeritageClauseElement: + return true; + case SyntaxKind.TypeParameter: + return node === (parent).constraint; + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.Parameter: + case SyntaxKind.VariableDeclaration: + return node === (parent).type; + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.Constructor: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return node === (parent).type; + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + return node === (parent).type; + case SyntaxKind.TypeAssertionExpression: + return node === (parent).type; + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + return (parent).typeArguments && indexOf((parent).typeArguments, node) >= 0; + case SyntaxKind.TaggedTemplateExpression: + // TODO (drosen): TaggedTemplateExpressions may eventually support type arguments. + return false; + } + } + + return false; + } + + function getLeftSideOfImportEqualsOrExportAssignment(nodeOnRightSide: EntityName): ImportEqualsDeclaration | ExportAssignment { + while (nodeOnRightSide.parent.kind === SyntaxKind.QualifiedName) { + nodeOnRightSide = nodeOnRightSide.parent; + } + + if (nodeOnRightSide.parent.kind === SyntaxKind.ImportEqualsDeclaration) { + return (nodeOnRightSide.parent).moduleReference === nodeOnRightSide && nodeOnRightSide.parent; + } + + if (nodeOnRightSide.parent.kind === SyntaxKind.ExportAssignment) { + return (nodeOnRightSide.parent).expression === nodeOnRightSide && nodeOnRightSide.parent; + } + + return undefined; + } + + function isInRightSideOfImportOrExportAssignment(node: EntityName) { + return getLeftSideOfImportEqualsOrExportAssignment(node) !== undefined; + } + + function getSymbolOfEntityNameOrPropertyAccessExpression(entityName: EntityName | PropertyAccessExpression): Symbol { + if (isDeclarationName(entityName)) { + return getSymbolOfNode(entityName.parent); + } + + if (entityName.parent.kind === SyntaxKind.ExportAssignment) { + return resolveEntityName(entityName, + /*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); + } + + if (entityName.kind !== SyntaxKind.PropertyAccessExpression) { + if (isInRightSideOfImportOrExportAssignment(entityName)) { + // Since we already checked for ExportAssignment, this really could only be an Import + return getSymbolOfPartOfRightHandSideOfImportEquals(entityName); + } + } + + if (isRightSideOfQualifiedNameOrPropertyAccess(entityName)) { + entityName = entityName.parent; + } + + if (isHeritageClauseElementIdentifier(entityName)) { + let meaning = entityName.parent.kind === SyntaxKind.HeritageClauseElement ? SymbolFlags.Type : SymbolFlags.Namespace; + meaning |= SymbolFlags.Alias; + return resolveEntityName(entityName, meaning); + } + else if (isExpression(entityName)) { + if (nodeIsMissing(entityName)) { + // Missing entity name. + return undefined; + } + + if (entityName.kind === SyntaxKind.Identifier) { + // Include aliases in the meaning, this ensures that we do not follow aliases to where they point and instead + // return the alias symbol. + let meaning: SymbolFlags = SymbolFlags.Value | SymbolFlags.Alias; + return resolveEntityName(entityName, meaning); + } + else if (entityName.kind === SyntaxKind.PropertyAccessExpression) { + let symbol = getNodeLinks(entityName).resolvedSymbol; + if (!symbol) { + checkPropertyAccessExpression(entityName); + } + return getNodeLinks(entityName).resolvedSymbol; + } + else if (entityName.kind === SyntaxKind.QualifiedName) { + let symbol = getNodeLinks(entityName).resolvedSymbol; + if (!symbol) { + checkQualifiedName(entityName); + } + return getNodeLinks(entityName).resolvedSymbol; + } + } + else if (isTypeReferenceIdentifier(entityName)) { + let meaning = entityName.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace; + // Include aliases in the meaning, this ensures that we do not follow aliases to where they point and instead + // return the alias symbol. + meaning |= SymbolFlags.Alias; + return resolveEntityName(entityName, meaning); + } + + // Do we want to return undefined here? + return undefined; + } + + function getSymbolInfo(node: Node) { + if (isInsideWithStatementBody(node)) { + // We cannot answer semantic questions within a with block, do not proceed any further + return undefined; + } + + if (isDeclarationName(node)) { + // This is a declaration, call getSymbolOfNode + return getSymbolOfNode(node.parent); + } + + if (node.kind === SyntaxKind.Identifier && isInRightSideOfImportOrExportAssignment(node)) { + return node.parent.kind === SyntaxKind.ExportAssignment + ? getSymbolOfEntityNameOrPropertyAccessExpression(node) + : getSymbolOfPartOfRightHandSideOfImportEquals(node); + } + + switch (node.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.QualifiedName: + return getSymbolOfEntityNameOrPropertyAccessExpression(node); + + case SyntaxKind.ThisKeyword: + case SyntaxKind.SuperKeyword: + let type = checkExpression(node); + return type.symbol; + + case SyntaxKind.ConstructorKeyword: + // constructor keyword for an overload, should take us to the definition if it exist + let constructorDeclaration = node.parent; + if (constructorDeclaration && constructorDeclaration.kind === SyntaxKind.Constructor) { + return (constructorDeclaration.parent).symbol; + } + return undefined; + + case SyntaxKind.StringLiteral: + // External module name in an import declaration + let moduleName: Expression; + if ((isExternalModuleImportEqualsDeclaration(node.parent.parent) && + getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) || + ((node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration) && + (node.parent).moduleSpecifier === node)) { + return resolveExternalModuleName(node, node); + } + + // Intentional fall-through + case SyntaxKind.NumericLiteral: + // index access + if (node.parent.kind == SyntaxKind.ElementAccessExpression && (node.parent).argumentExpression === node) { + let objectType = checkExpression((node.parent).expression); + if (objectType === unknownType) return undefined; + let apparentType = getApparentType(objectType); + if (apparentType === unknownType) return undefined; + return getPropertyOfType(apparentType, (node).text); + } + break; + } + return undefined; + } + + function getShorthandAssignmentValueSymbol(location: Node): Symbol { + // The function returns a value symbol of an identifier in the short-hand property assignment. + // This is necessary as an identifier in short-hand property assignment can contains two meaning: + // property name and property value. + if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) { + return resolveEntityName((location).name, SymbolFlags.Value); + } + return undefined; + } + + function getTypeOfNode(node: Node): Type { + if (isInsideWithStatementBody(node)) { + // We cannot answer semantic questions within a with block, do not proceed any further + return unknownType; + } + + if (isTypeNode(node)) { + return getTypeFromTypeNode(node); + } + + if (isExpression(node)) { + return getTypeOfExpression(node); + } + + if (isTypeDeclaration(node)) { + // In this case, we call getSymbolOfNode instead of getSymbolInfo because it is a declaration + let symbol = getSymbolOfNode(node); + return getDeclaredTypeOfSymbol(symbol); + } + + if (isTypeDeclarationName(node)) { + let symbol = getSymbolInfo(node); + return symbol && getDeclaredTypeOfSymbol(symbol); + } + + if (isDeclaration(node)) { + // In this case, we call getSymbolOfNode instead of getSymbolInfo because it is a declaration + let symbol = getSymbolOfNode(node); + return getTypeOfSymbol(symbol); + } + + if (isDeclarationName(node)) { + let symbol = getSymbolInfo(node); + return symbol && getTypeOfSymbol(symbol); + } + + if (isInRightSideOfImportOrExportAssignment(node)) { + let symbol = getSymbolInfo(node); + let declaredType = symbol && getDeclaredTypeOfSymbol(symbol); + return declaredType !== unknownType ? declaredType : getTypeOfSymbol(symbol); + } + + return unknownType; + } + + function getTypeOfExpression(expr: Expression): Type { + if (isRightSideOfQualifiedNameOrPropertyAccess(expr)) { + expr = expr.parent; + } + return checkExpression(expr); + } + + // Return the list of properties of the given type, augmented with properties from Function + // if the type has call or construct signatures + function getAugmentedPropertiesOfType(type: Type): Symbol[] { + type = getApparentType(type); + let propsByName = createSymbolTable(getPropertiesOfType(type)); + if (getSignaturesOfType(type, SignatureKind.Call).length || getSignaturesOfType(type, SignatureKind.Construct).length) { + forEach(getPropertiesOfType(globalFunctionType), p => { + if (!hasProperty(propsByName, p.name)) { + propsByName[p.name] = p; + } + }); + } + return getNamedMembers(propsByName); + } + + function getRootSymbols(symbol: Symbol): Symbol[] { + if (symbol.flags & SymbolFlags.UnionProperty) { + let symbols: Symbol[] = []; + let name = symbol.name; + forEach(getSymbolLinks(symbol).unionType.types, t => { + symbols.push(getPropertyOfType(t, name)); + }); + return symbols; + } + else if (symbol.flags & SymbolFlags.Transient) { + let target = getSymbolLinks(symbol).target; + if (target) { + return [target]; + } + } + return [symbol]; + } + + // Emitter support + + function isExternalModuleSymbol(symbol: Symbol): boolean { + return symbol.flags & SymbolFlags.ValueModule && symbol.declarations.length === 1 && symbol.declarations[0].kind === SyntaxKind.SourceFile; + } + + function getAliasNameSubstitution(symbol: Symbol, getGeneratedNameForNode: (node: Node) => string): string { + // If this is es6 or higher, just use the name of the export + // no need to qualify it. + if (languageVersion >= ScriptTarget.ES6) { + return undefined; + } + + let node = getDeclarationOfAliasSymbol(symbol); + if (node) { + if (node.kind === SyntaxKind.ImportClause) { + let defaultKeyword: string; + + if (languageVersion === ScriptTarget.ES3) { + defaultKeyword = "[\"default\"]"; + } else { + defaultKeyword = ".default"; + } + return getGeneratedNameForNode(node.parent) + defaultKeyword; + } + if (node.kind === SyntaxKind.ImportSpecifier) { + let moduleName = getGeneratedNameForNode(node.parent.parent.parent); + let propertyName = (node).propertyName || (node).name; + return moduleName + "." + unescapeIdentifier(propertyName.text); + } + } + } + + function getExportNameSubstitution(symbol: Symbol, location: Node, getGeneratedNameForNode: (Node: Node) => string): string { + if (isExternalModuleSymbol(symbol.parent)) { + // If this is es6 or higher, just use the name of the export + // no need to qualify it. + if (languageVersion >= ScriptTarget.ES6) { + return undefined; + } + return "exports." + unescapeIdentifier(symbol.name); + } + let node = location; + let containerSymbol = getParentOfSymbol(symbol); + while (node) { + if ((node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.EnumDeclaration) && getSymbolOfNode(node) === containerSymbol) { + return getGeneratedNameForNode(node) + "." + unescapeIdentifier(symbol.name); + } + node = node.parent; + } + } + + function getExpressionNameSubstitution(node: Identifier, getGeneratedNameForNode: (Node: Node) => string): string { + let symbol = getNodeLinks(node).resolvedSymbol || (isDeclarationName(node) ? getSymbolOfNode(node.parent) : undefined); + if (symbol) { + // Whan an identifier resolves to a parented symbol, it references an exported entity from + // another declaration of the same internal module. + if (symbol.parent) { + return getExportNameSubstitution(symbol, node.parent, getGeneratedNameForNode); + } + // If we reference an exported entity within the same module declaration, then whether + // we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the + // kinds that we do NOT prefix. + let exportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); + if (symbol !== exportSymbol && !(exportSymbol.flags & SymbolFlags.ExportHasLocal)) { + return getExportNameSubstitution(exportSymbol, node.parent, getGeneratedNameForNode); + } + // Named imports from ES6 import declarations are rewritten + if (symbol.flags & SymbolFlags.Alias) { + return getAliasNameSubstitution(symbol, getGeneratedNameForNode); + } + } + } + + function isValueAliasDeclaration(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportClause: + case SyntaxKind.NamespaceImport: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ExportSpecifier: + return isAliasResolvedToValue(getSymbolOfNode(node)); + case SyntaxKind.ExportDeclaration: + let exportClause = (node).exportClause; + return exportClause && forEach(exportClause.elements, isValueAliasDeclaration); + case SyntaxKind.ExportAssignment: + return (node).expression && (node).expression.kind === SyntaxKind.Identifier ? isAliasResolvedToValue(getSymbolOfNode(node)) : true; + } + return false; + } + + function isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean { + if (node.parent.kind !== SyntaxKind.SourceFile || !isInternalModuleImportEqualsDeclaration(node)) { + // parent is not source file or it is not reference to internal module + return false; + } + + var isValue = isAliasResolvedToValue(getSymbolOfNode(node)); + return isValue && node.moduleReference && !nodeIsMissing(node.moduleReference); + } + + function isAliasResolvedToValue(symbol: Symbol): boolean { + let target = resolveAlias(symbol); + if (target === unknownSymbol && compilerOptions.separateCompilation) { + return true; + } + // const enums and modules that contain only const enums are not considered values from the emit perespective + return target !== unknownSymbol && target && target.flags & SymbolFlags.Value && !isConstEnumOrConstEnumOnlyModule(target); + } + + function isConstEnumOrConstEnumOnlyModule(s: Symbol): boolean { + return isConstEnumSymbol(s) || s.constEnumOnlyModule; + } + + function isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean { + if (isAliasSymbolDeclaration(node)) { + let symbol = getSymbolOfNode(node); + if (getSymbolLinks(symbol).referenced) { + return true; + } + } + + if (checkChildren) { + return forEachChild(node, node => isReferencedAliasDeclaration(node, checkChildren)); + } + return false; + } + + function isImplementationOfOverload(node: FunctionLikeDeclaration) { + if (nodeIsPresent(node.body)) { + let symbol = getSymbolOfNode(node); + let signaturesOfSymbol = getSignaturesOfSymbol(symbol); + // If this function body corresponds to function with multiple signature, it is implementation of overload + // e.g.: function foo(a: string): string; + // function foo(a: number): number; + // function foo(a: any) { // This is implementation of the overloads + // return a; + // } + return signaturesOfSymbol.length > 1 || + // If there is single signature for the symbol, it is overload if that signature isn't coming from the node + // e.g.: function foo(a: string): string; + // function foo(a: any) { // This is implementation of the overloads + // return a; + // } + (signaturesOfSymbol.length === 1 && signaturesOfSymbol[0].declaration !== node); + } + return false; + } + + function getNodeCheckFlags(node: Node): NodeCheckFlags { + return getNodeLinks(node).flags; + } + + function getEnumMemberValue(node: EnumMember): number { + computeEnumMemberValues(node.parent); + return getNodeLinks(node).enumMemberValue; + } + + function getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number { + if (node.kind === SyntaxKind.EnumMember) { + return getEnumMemberValue(node); + } + + let symbol = getNodeLinks(node).resolvedSymbol; + if (symbol && (symbol.flags & SymbolFlags.EnumMember)) { + // inline property\index accesses only for const enums + if (isConstEnumDeclaration(symbol.valueDeclaration.parent)) { + return getEnumMemberValue(symbol.valueDeclaration); + } + } + + return undefined; + } + + /** Serializes an EntityName (with substitutions) to an appropriate JS constructor value. Used by the __metadata decorator. */ + function serializeEntityName(node: EntityName, getGeneratedNameForNode: (Node: Node) => string, fallbackPath?: string[]): string { + if (node.kind === SyntaxKind.Identifier) { + var substitution = getExpressionNameSubstitution(node, getGeneratedNameForNode); + var text = substitution || (node).text; + if (fallbackPath) { + fallbackPath.push(text); + } + else { + return text; + } + } + else { + var left = serializeEntityName((node).left, getGeneratedNameForNode, fallbackPath); + var right = serializeEntityName((node).right, getGeneratedNameForNode, fallbackPath); + if (!fallbackPath) { + return left + "." + right; + } + } + } + + /** Serializes a TypeReferenceNode to an appropriate JS constructor value. Used by the __metadata decorator. */ + function serializeTypeReferenceNode(node: TypeReferenceNode, getGeneratedNameForNode: (Node: Node) => string): string | string[] { + // serialization of a TypeReferenceNode uses the following rules: + // + // * The serialized type of a TypeReference that is `void` is "void 0". + // * The serialized type of a TypeReference that is a `boolean` is "Boolean". + // * The serialized type of a TypeReference that is an enum or `number` is "Number". + // * The serialized type of a TypeReference that is a string literal or `string` is "String". + // * The serialized type of a TypeReference that is a tuple is "Array". + // * The serialized type of a TypeReference that is a `symbol` is "Symbol". + // * The serialized type of a TypeReference with a value declaration is its entity name. + // * The serialized type of a TypeReference with a call or construct signature is "Function". + // * The serialized type of any other type is "Object". + let type = getTypeFromTypeReference(node); + if (type.flags & TypeFlags.Void) { + return "void 0"; + } + else if (type.flags & TypeFlags.Boolean) { + return "Boolean"; + } + else if (type.flags & TypeFlags.NumberLike) { + return "Number"; + } + else if (type.flags & TypeFlags.StringLike) { + return "String"; + } + else if (type.flags & TypeFlags.Tuple) { + return "Array"; + } + else if (type.flags & TypeFlags.ESSymbol) { + return "Symbol"; + } + else if (type === unknownType) { + var fallbackPath: string[] = []; + serializeEntityName(node.typeName, getGeneratedNameForNode, fallbackPath); + return fallbackPath; + } + else if (type.symbol && type.symbol.valueDeclaration) { + return serializeEntityName(node.typeName, getGeneratedNameForNode); + } + else if (typeHasCallOrConstructSignatures(type)) { + return "Function"; + } + + return "Object"; + } + + /** Serializes a TypeNode to an appropriate JS constructor value. Used by the __metadata decorator. */ + function serializeTypeNode(node: TypeNode | LiteralExpression, getGeneratedNameForNode: (Node: Node) => string): string | string[] { + // serialization of a TypeNode uses the following rules: + // + // * The serialized type of `void` is "void 0" (undefined). + // * The serialized type of a parenthesized type is the serialized type of its nested type. + // * The serialized type of a Function or Constructor type is "Function". + // * The serialized type of an Array or Tuple type is "Array". + // * The serialized type of `boolean` is "Boolean". + // * The serialized type of `string` or a string-literal type is "String". + // * The serialized type of a type reference is handled by `serializeTypeReferenceNode`. + // * The serialized type of any other type node is "Object". + if (node) { + switch (node.kind) { + case SyntaxKind.VoidKeyword: + return "void 0"; + case SyntaxKind.ParenthesizedType: + return serializeTypeNode((node).type, getGeneratedNameForNode); + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + return "Function"; + case SyntaxKind.ArrayType: + case SyntaxKind.TupleType: + return "Array"; + case SyntaxKind.BooleanKeyword: + return "Boolean"; + case SyntaxKind.StringKeyword: + case SyntaxKind.StringLiteral: + return "String"; + case SyntaxKind.NumberKeyword: + return "Number"; + case SyntaxKind.TypeReference: + return serializeTypeReferenceNode(node, getGeneratedNameForNode); + case SyntaxKind.TypeQuery: + case SyntaxKind.TypeLiteral: + case SyntaxKind.UnionType: + case SyntaxKind.AnyKeyword: + break; + default: + Debug.fail("Cannot serialize unexpected type node."); + break; + } + } + + return "Object"; + } + + /** Serializes the type of a declaration to an appropriate JS constructor value. Used by the __metadata decorator for a class member. */ + function serializeTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[] { + // serialization of the type of a declaration uses the following rules: + // + // * The serialized type of a ClassDeclaration is "Function" + // * The serialized type of a ParameterDeclaration is the serialized type of its type annotation. + // * The serialized type of a PropertyDeclaration is the serialized type of its type annotation. + // * The serialized type of an AccessorDeclaration is the serialized type of the return type annotation of its getter or parameter type annotation of its setter. + // * The serialized type of any other FunctionLikeDeclaration is "Function". + // * The serialized type of any other node is "void 0". + // + // For rules on serializing type annotations, see `serializeTypeNode`. + switch (node.kind) { + case SyntaxKind.ClassDeclaration: return "Function"; + case SyntaxKind.PropertyDeclaration: return serializeTypeNode((node).type, getGeneratedNameForNode); + case SyntaxKind.Parameter: return serializeTypeNode((node).type, getGeneratedNameForNode); + case SyntaxKind.GetAccessor: return serializeTypeNode((node).type, getGeneratedNameForNode); + case SyntaxKind.SetAccessor: return serializeTypeNode(getSetAccessorTypeAnnotationNode(node), getGeneratedNameForNode); + } + if (isFunctionLike(node)) { + return "Function"; + } + return "void 0"; + } + + /** Serializes the parameter types of a function or the constructor of a class. Used by the __metadata decorator for a method or set accessor. */ + function serializeParameterTypesOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): (string | string[])[] { + // serialization of parameter types uses the following rules: + // + // * If the declaration is a class, the parameters of the first constructor with a body are used. + // * If the declaration is function-like and has a body, the parameters of the function are used. + // + // For the rules on serializing the type of each parameter declaration, see `serializeTypeOfDeclaration`. + if (node) { + var valueDeclaration: FunctionLikeDeclaration; + if (node.kind === SyntaxKind.ClassDeclaration) { + valueDeclaration = getFirstConstructorWithBody(node); + } + else if (isFunctionLike(node) && nodeIsPresent((node).body)) { + valueDeclaration = node; + } + if (valueDeclaration) { + var result: (string | string[])[]; + var parameters = valueDeclaration.parameters; + var parameterCount = parameters.length; + if (parameterCount > 0) { + result = new Array(parameterCount); + for (var i = 0; i < parameterCount; i++) { + if (parameters[i].dotDotDotToken) { + var parameterType = parameters[i].type; + if (parameterType.kind === SyntaxKind.ArrayType) { + parameterType = (parameterType).elementType; + } + else if (parameterType.kind === SyntaxKind.TypeReference && (parameterType).typeArguments && (parameterType).typeArguments.length === 1) { + parameterType = (parameterType).typeArguments[0]; + } + else { + parameterType = undefined; + } + result[i] = serializeTypeNode(parameterType, getGeneratedNameForNode); + } + else { + result[i] = serializeTypeOfNode(parameters[i], getGeneratedNameForNode); + } + } + return result; + } + } + } + return emptyArray; + } + + /** Serializes the return type of function. Used by the __metadata decorator for a method. */ + function serializeReturnTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[] { + if (node && isFunctionLike(node)) { + return serializeTypeNode((node).type, getGeneratedNameForNode); + } + return "void 0"; + } + + function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) { + // Get type of the symbol if this is the valid symbol otherwise get type at location + let symbol = getSymbolOfNode(declaration); + let type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature)) + ? getTypeOfSymbol(symbol) + : unknownType; + + getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); + } + + function writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) { + let signature = getSignatureFromDeclaration(signatureDeclaration); + getSymbolDisplayBuilder().buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags); + } + + function writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) { + var type = getTypeOfExpression(expr); + getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); + } + + function hasGlobalName(name: string): boolean { + return hasProperty(globals, name); + } + + function resolvesToSomeValue(location: Node, name: string): boolean { + Debug.assert(!nodeIsSynthesized(location), "resolvesToSomeValue called with a synthesized location"); + return !!resolveName(location, name, SymbolFlags.Value, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); + } + + function getBlockScopedVariableId(n: Identifier): number { + Debug.assert(!nodeIsSynthesized(n)); + + let isVariableDeclarationOrBindingElement = + n.parent.kind === SyntaxKind.BindingElement || (n.parent.kind === SyntaxKind.VariableDeclaration && (n.parent).name === n); + + let symbol = + (isVariableDeclarationOrBindingElement ? getSymbolOfNode(n.parent) : undefined) || + getNodeLinks(n).resolvedSymbol || + resolveName(n, n.text, SymbolFlags.Value | SymbolFlags.Alias, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); + + let isLetOrConst = + symbol && + (symbol.flags & SymbolFlags.BlockScopedVariable) && + symbol.valueDeclaration.parent.kind !== SyntaxKind.CatchClause; + + if (isLetOrConst) { + // side-effect of calling this method: + // assign id to symbol if it was not yet set + getSymbolLinks(symbol); + return symbol.id; + } + return undefined; + } + + function instantiateSingleCallFunctionType(functionType: Type, typeArguments: Type[]): Type { + if (functionType === unknownType) { + return unknownType; + } + + let signature = getSingleCallSignature(functionType); + if (!signature) { + return unknownType; + } + + let instantiatedSignature = getSignatureInstantiation(signature, typeArguments); + return getOrCreateTypeFromSignature(instantiatedSignature); + } + + function createResolver(): EmitResolver { + return { + getExpressionNameSubstitution, + isValueAliasDeclaration, + hasGlobalName, + isReferencedAliasDeclaration, + getNodeCheckFlags, + isTopLevelValueImportEqualsWithEntityName, + isDeclarationVisible, + isImplementationOfOverload, + writeTypeOfDeclaration, + writeReturnTypeOfSignatureDeclaration, + writeTypeOfExpression, + isSymbolAccessible, + isEntityNameVisible, + getConstantValue, + resolvesToSomeValue, + collectLinkedAliases, + getBlockScopedVariableId, + serializeTypeOfNode, + serializeParameterTypesOfNode, + serializeReturnTypeOfNode, + }; + } + + function initializeTypeChecker() { + // Bind all source files and propagate errors + forEach(host.getSourceFiles(), file => { + bindSourceFile(file); + }); + + // Initialize global symbol table + forEach(host.getSourceFiles(), file => { + if (!isExternalModule(file)) { + mergeSymbolTable(globals, file.locals); + } + }); + + // Initialize special symbols + getSymbolLinks(undefinedSymbol).type = undefinedType; + getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments"); + getSymbolLinks(unknownSymbol).type = unknownType; + globals[undefinedSymbol.name] = undefinedSymbol; + // Initialize special types + globalArraySymbol = getGlobalTypeSymbol("Array"); + globalArrayType = getTypeOfGlobalSymbol(globalArraySymbol, /*arity*/ 1); + globalObjectType = getGlobalType("Object"); + globalFunctionType = getGlobalType("Function"); + globalStringType = getGlobalType("String"); + globalNumberType = getGlobalType("Number"); + globalBooleanType = getGlobalType("Boolean"); + globalRegExpType = getGlobalType("RegExp"); + getGlobalClassDecoratorType = memoize(() => getGlobalType("ClassDecorator")); + getGlobalPropertyDecoratorType = memoize(() => getGlobalType("PropertyDecorator")); + getGlobalMethodDecoratorType = memoize(() => getGlobalType("MethodDecorator")); + getGlobalParameterDecoratorType = memoize(() => getGlobalType("ParameterDecorator")); + + // If we're in ES6 mode, load the TemplateStringsArray. + // Otherwise, default to 'unknown' for the purposes of type checking in LS scenarios. + if (languageVersion >= ScriptTarget.ES6) { + globalTemplateStringsArrayType = getGlobalType("TemplateStringsArray"); + globalESSymbolType = getGlobalType("Symbol"); + globalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol"); + globalIterableType = getGlobalType("Iterable", /*arity*/ 1); + } + else { + globalTemplateStringsArrayType = unknownType; + + // Consider putting Symbol interface in lib.d.ts. On the plus side, putting it in lib.d.ts would make it + // extensible for Polyfilling Symbols. But putting it into lib.d.ts could also break users that have + // a global Symbol already, particularly if it is a class. + globalESSymbolType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + globalESSymbolConstructorSymbol = undefined; + } + + anyArrayType = createArrayType(anyType); + } + + // GRAMMAR CHECKING + function isReservedWordInStrictMode(node: Identifier): boolean { + // Check that originalKeywordKind is less than LastFutureReservedWord to see if an Identifier is a strict-mode reserved word + return (node.parserContextFlags & ParserContextFlags.StrictMode) && + (SyntaxKind.FirstFutureReservedWord <= node.originalKeywordKind && node.originalKeywordKind <= SyntaxKind.LastFutureReservedWord); + } + + function reportStrictModeGrammarErrorInClassDeclaration(identifier: Identifier, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + // We are checking if this name is inside class declaration or class expression (which are under class definitions inside ES6 spec.) + // if so, we would like to give more explicit invalid usage error. + if (getAncestor(identifier, SyntaxKind.ClassDeclaration) || getAncestor(identifier, SyntaxKind.ClassExpression)) { + return grammarErrorOnNode(identifier, message, arg0); + } + return false; + } + + function checkGrammarImportDeclarationNameInStrictMode(node: ImportDeclaration): boolean { + // Check if the import declaration used strict-mode reserved word in its names bindings + if (node.importClause) { + let impotClause = node.importClause; + if (impotClause.namedBindings) { + let nameBindings = impotClause.namedBindings; + if (nameBindings.kind === SyntaxKind.NamespaceImport) { + let name = (nameBindings).name; + if (isReservedWordInStrictMode(name)) { + let nameText = declarationNameToString(name); + return grammarErrorOnNode(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + } + } + else if (nameBindings.kind === SyntaxKind.NamedImports) { + let reportError = false; + for (let element of (nameBindings).elements) { + let name = element.name; + if (isReservedWordInStrictMode(name)) { + let nameText = declarationNameToString(name); + reportError = reportError || grammarErrorOnNode(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + } + } + return reportError; + } + } + } + return false; + } + + function checkGrammarDeclarationNameInStrictMode(node: Declaration): boolean { + let name = node.name; + if (name && name.kind === SyntaxKind.Identifier && isReservedWordInStrictMode(name)) { + let nameText = declarationNameToString(name); + switch (node.kind) { + case SyntaxKind.Parameter: + case SyntaxKind.VariableDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.TypeParameter: + case SyntaxKind.BindingElement: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.EnumDeclaration: + return checkGrammarIdentifierInStrictMode(name); + + case SyntaxKind.ClassDeclaration: + // Report an error if the class declaration uses strict-mode reserved word. + return grammarErrorOnNode(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode, nameText); + + case SyntaxKind.ModuleDeclaration: + // Report an error if the module declaration uses strict-mode reserved word. + // TODO(yuisu): fix this when having external module in strict mode + return grammarErrorOnNode(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + + case SyntaxKind.ImportEqualsDeclaration: + // TODO(yuisu): fix this when having external module in strict mode + return grammarErrorOnNode(name, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + } + } + return false; + } + + function checkGrammarTypeReferenceInStrictMode(typeName: Identifier | QualifiedName) { + // Check if the type reference is using strict mode keyword + // Example: + // class C { + // foo(x: public){} // Error. + // } + if (typeName.kind === SyntaxKind.Identifier) { + checkGrammarTypeNameInStrictMode(typeName); + } + // Report an error for each identifier in QualifiedName + // Example: + // foo (x: B.private.bar) // error at private + // foo (x: public.private.package) // error at public, private, and package + else if (typeName.kind === SyntaxKind.QualifiedName) { + // Walk from right to left and report a possible error at each Identifier in QualifiedName + // Example: + // x1: public.private.package // error at public and private + checkGrammarTypeNameInStrictMode((typeName).right); + checkGrammarTypeReferenceInStrictMode((typeName).left); + } + } + + // This function will report an error for every identifier in property access expression + // whether it violates strict mode reserved words. + // Example: + // public // error at public + // public.private.package // error at public + // B.private.B // no error + function checkGrammarHeritageClauseElementInStrictMode(expression: Expression) { + // Example: + // class C extends public // error at public + if (expression && expression.kind === SyntaxKind.Identifier) { + return checkGrammarIdentifierInStrictMode(expression); + } + else if (expression && expression.kind === SyntaxKind.PropertyAccessExpression) { + // Walk from left to right in PropertyAccessExpression until we are at the left most expression + // in PropertyAccessExpression. According to grammar production of MemberExpression, + // the left component expression is a PrimaryExpression (i.e. Identifier) while the other + // component after dots can be IdentifierName. + checkGrammarHeritageClauseElementInStrictMode((expression).expression); + } + + } + + // The function takes an identifier itself or an expression which has SyntaxKind.Identifier. + function checkGrammarIdentifierInStrictMode(node: Expression | Identifier, nameText?: string): boolean { + if (node && node.kind === SyntaxKind.Identifier && isReservedWordInStrictMode(node)) { + if (!nameText) { + nameText = declarationNameToString(node); + } + + // TODO (yuisu): Fix when module is a strict mode + let errorReport = reportStrictModeGrammarErrorInClassDeclaration(node, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode, nameText)|| + grammarErrorOnNode(node, Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode, nameText); + return errorReport; + } + return false; + } + + // The function takes an identifier when uses as a typeName in TypeReferenceNode + function checkGrammarTypeNameInStrictMode(node: Identifier): boolean { + if (node && node.kind === SyntaxKind.Identifier && isReservedWordInStrictMode(node)) { + let nameText = declarationNameToString(node); + + // TODO (yuisu): Fix when module is a strict mode + let errorReport = reportStrictModeGrammarErrorInClassDeclaration(node, Diagnostics.Type_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode, nameText) || + grammarErrorOnNode(node, Diagnostics.Type_expected_0_is_a_reserved_word_in_strict_mode, nameText); + return errorReport; + } + return false; + } + + function checkGrammarDecorators(node: Node): boolean { + if (!node.decorators) { + return false; + } + if (!nodeCanBeDecorated(node)) { + return grammarErrorOnFirstToken(node, Diagnostics.Decorators_are_not_valid_here); + } + else if (languageVersion < ScriptTarget.ES5) { + return grammarErrorOnFirstToken(node, Diagnostics.Decorators_are_only_available_when_targeting_ECMAScript_5_and_higher); + } + else if (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor) { + let accessors = getAllAccessorDeclarations((node.parent).members, node); + if (accessors.firstAccessor.decorators && node === accessors.secondAccessor) { + return grammarErrorOnFirstToken(node, Diagnostics.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name); + } + } + return false; + } + + function checkGrammarModifiers(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.Constructor: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.VariableStatement: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ExportDeclaration: + case SyntaxKind.ExportAssignment: + case SyntaxKind.Parameter: + break; + default: + return false; + } + + if (!node.modifiers) { + return; + } + + let lastStatic: Node, lastPrivate: Node, lastProtected: Node, lastDeclare: Node; + let flags = 0; + for (let modifier of node.modifiers) { + switch (modifier.kind) { + case SyntaxKind.PublicKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.PrivateKeyword: + let text: string; + if (modifier.kind === SyntaxKind.PublicKeyword) { + text = "public"; + } + else if (modifier.kind === SyntaxKind.ProtectedKeyword) { + text = "protected"; + lastProtected = modifier; + } + else { + text = "private"; + lastPrivate = modifier; + } + + if (flags & NodeFlags.AccessibilityModifier) { + return grammarErrorOnNode(modifier, Diagnostics.Accessibility_modifier_already_seen); + } + else if (flags & NodeFlags.Static) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "static"); + } + else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_element, text); + } + flags |= modifierToFlag(modifier.kind); + break; + + case SyntaxKind.StaticKeyword: + if (flags & NodeFlags.Static) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "static"); + } + else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_element, "static"); + } + else if (node.kind === SyntaxKind.Parameter) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "static"); + } + flags |= NodeFlags.Static; + lastStatic = modifier; + break; + + case SyntaxKind.ExportKeyword: + if (flags & NodeFlags.Export) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "export"); + } + else if (flags & NodeFlags.Ambient) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "declare"); + } + else if (node.parent.kind === SyntaxKind.ClassDeclaration) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_class_element, "export"); + } + else if (node.kind === SyntaxKind.Parameter) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "export"); + } + flags |= NodeFlags.Export; + break; + + case SyntaxKind.DeclareKeyword: + if (flags & NodeFlags.Ambient) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "declare"); + } + else if (node.parent.kind === SyntaxKind.ClassDeclaration) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_class_element, "declare"); + } + else if (node.kind === SyntaxKind.Parameter) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "declare"); + } + else if (isInAmbientContext(node.parent) && node.parent.kind === SyntaxKind.ModuleBlock) { + return grammarErrorOnNode(modifier, Diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context); + } + flags |= NodeFlags.Ambient; + lastDeclare = modifier + break; + } + } + + if (node.kind === SyntaxKind.Constructor) { + if (flags & NodeFlags.Static) { + return grammarErrorOnNode(lastStatic, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "static"); + } + else if (flags & NodeFlags.Protected) { + return grammarErrorOnNode(lastProtected, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "protected"); + } + else if (flags & NodeFlags.Private) { + return grammarErrorOnNode(lastPrivate, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "private"); + } + } + else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && flags & NodeFlags.Ambient) { + return grammarErrorOnNode(lastDeclare, Diagnostics.A_declare_modifier_cannot_be_used_with_an_import_declaration, "declare"); + } + else if (node.kind === SyntaxKind.InterfaceDeclaration && flags & NodeFlags.Ambient) { + return grammarErrorOnNode(lastDeclare, Diagnostics.A_declare_modifier_cannot_be_used_with_an_interface_declaration, "declare"); + } + else if (node.kind === SyntaxKind.Parameter && (flags & NodeFlags.AccessibilityModifier) && isBindingPattern((node).name)) { + return grammarErrorOnNode(node, Diagnostics.A_parameter_property_may_not_be_a_binding_pattern); + } + } + + function checkGrammarForDisallowedTrailingComma(list: NodeArray): boolean { + if (list && list.hasTrailingComma) { + let start = list.end - ",".length; + let end = list.end; + let sourceFile = getSourceFileOfNode(list[0]); + return grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.Trailing_comma_not_allowed); + } + } + + function checkGrammarTypeParameterList(node: FunctionLikeDeclaration, typeParameters: NodeArray, file: SourceFile): boolean { + if (checkGrammarForDisallowedTrailingComma(typeParameters)) { + return true; + } + + if (typeParameters && typeParameters.length === 0) { + let start = typeParameters.pos - "<".length; + let end = skipTrivia(file.text, typeParameters.end) + ">".length; + return grammarErrorAtPos(file, start, end - start, Diagnostics.Type_parameter_list_cannot_be_empty); + } + } + + function checkGrammarParameterList(parameters: NodeArray) { + if (checkGrammarForDisallowedTrailingComma(parameters)) { + return true; + } + + let seenOptionalParameter = false; + let parameterCount = parameters.length; + + for (let i = 0; i < parameterCount; i++) { + let parameter = parameters[i]; + if (parameter.dotDotDotToken) { + if (i !== (parameterCount - 1)) { + return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); + } + + if (isBindingPattern(parameter.name)) { + return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_element_cannot_contain_a_binding_pattern); + } + + if (parameter.questionToken) { + return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_rest_parameter_cannot_be_optional); + } + + if (parameter.initializer) { + return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_have_an_initializer); + } + } + else if (parameter.questionToken || parameter.initializer) { + seenOptionalParameter = true; + + if (parameter.questionToken && parameter.initializer) { + return grammarErrorOnNode(parameter.name, Diagnostics.Parameter_cannot_have_question_mark_and_initializer); + } + } + else { + if (seenOptionalParameter) { + return grammarErrorOnNode(parameter.name, Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter); + } + } + } + } + + function checkGrammarFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { + // Prevent cascading error by short-circuit + let file = getSourceFileOfNode(node); + return checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarTypeParameterList(node, node.typeParameters, file) || + checkGrammarParameterList(node.parameters) || checkGrammarArrowFunction(node, file); + } + + function checkGrammarArrowFunction(node: FunctionLikeDeclaration, file: SourceFile): boolean { + if (node.kind === SyntaxKind.ArrowFunction) { + let arrowFunction = node; + let startLine = getLineAndCharacterOfPosition(file, arrowFunction.equalsGreaterThanToken.pos).line; + let endLine = getLineAndCharacterOfPosition(file, arrowFunction.equalsGreaterThanToken.end).line; + if (startLine !== endLine) { + return grammarErrorOnNode(arrowFunction.equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow); + } + } + return false; + } + + function checkGrammarIndexSignatureParameters(node: SignatureDeclaration): boolean { + let parameter = node.parameters[0]; + if (node.parameters.length !== 1) { + if (parameter) { + return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_must_have_exactly_one_parameter); + } + else { + return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_exactly_one_parameter); + } + } + if (parameter.dotDotDotToken) { + return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.An_index_signature_cannot_have_a_rest_parameter); + } + if (parameter.flags & NodeFlags.Modifier) { + return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier); + } + if (parameter.questionToken) { + return grammarErrorOnNode(parameter.questionToken, Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark); + } + if (parameter.initializer) { + return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_initializer); + } + if (!parameter.type) { + return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_must_have_a_type_annotation); + } + if (parameter.type.kind !== SyntaxKind.StringKeyword && parameter.type.kind !== SyntaxKind.NumberKeyword) { + return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_must_be_string_or_number); + } + if (!node.type) { + return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_a_type_annotation); + } + } + + function checkGrammarForIndexSignatureModifier(node: SignatureDeclaration): void { + if (node.flags & NodeFlags.Modifier) { + grammarErrorOnFirstToken(node, Diagnostics.Modifiers_not_permitted_on_index_signature_members); + } + } + + function checkGrammarIndexSignature(node: SignatureDeclaration) { + // Prevent cascading error by short-circuit + return checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarIndexSignatureParameters(node) || checkGrammarForIndexSignatureModifier(node); + } + + function checkGrammarForAtLeastOneTypeArgument(node: Node, typeArguments: NodeArray): boolean { + if (typeArguments && typeArguments.length === 0) { + let sourceFile = getSourceFileOfNode(node); + let start = typeArguments.pos - "<".length; + let end = skipTrivia(sourceFile.text, typeArguments.end) + ">".length; + return grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.Type_argument_list_cannot_be_empty); + } + } + + function checkGrammarTypeArguments(node: Node, typeArguments: NodeArray): boolean { + return checkGrammarForDisallowedTrailingComma(typeArguments) || + checkGrammarForAtLeastOneTypeArgument(node, typeArguments); + } + + function checkGrammarForOmittedArgument(node: CallExpression, arguments: NodeArray): boolean { + if (arguments) { + let sourceFile = getSourceFileOfNode(node); + for (let arg of arguments) { + if (arg.kind === SyntaxKind.OmittedExpression) { + return grammarErrorAtPos(sourceFile, arg.pos, 0, Diagnostics.Argument_expression_expected); + } + } + } + } + + function checkGrammarArguments(node: CallExpression, arguments: NodeArray): boolean { + return checkGrammarForDisallowedTrailingComma(arguments) || + checkGrammarForOmittedArgument(node, arguments); + } + + function checkGrammarHeritageClause(node: HeritageClause): boolean { + let types = node.types; + if (checkGrammarForDisallowedTrailingComma(types)) { + return true; + } + if (types && types.length === 0) { + let listType = tokenToString(node.token); + let sourceFile = getSourceFileOfNode(node); + return grammarErrorAtPos(sourceFile, types.pos, 0, Diagnostics._0_list_cannot_be_empty, listType) + } + } + + function checkGrammarClassDeclarationHeritageClauses(node: ClassDeclaration) { + let seenExtendsClause = false; + let seenImplementsClause = false; + + if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && node.heritageClauses) { + for (let heritageClause of node.heritageClauses) { + if (heritageClause.token === SyntaxKind.ExtendsKeyword) { + if (seenExtendsClause) { + return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_already_seen) + } + + if (seenImplementsClause) { + return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_must_precede_implements_clause); + } + + if (heritageClause.types.length > 1) { + return grammarErrorOnFirstToken(heritageClause.types[1], Diagnostics.Classes_can_only_extend_a_single_class); + } + + seenExtendsClause = true; + } + else { + Debug.assert(heritageClause.token === SyntaxKind.ImplementsKeyword); + if (seenImplementsClause) { + return grammarErrorOnFirstToken(heritageClause, Diagnostics.implements_clause_already_seen); + } + + seenImplementsClause = true; + } + + // Grammar checking heritageClause inside class declaration + checkGrammarHeritageClause(heritageClause); + } + } + } + + function checkGrammarInterfaceDeclaration(node: InterfaceDeclaration) { + let seenExtendsClause = false; + + if (node.heritageClauses) { + for (let heritageClause of node.heritageClauses) { + if (heritageClause.token === SyntaxKind.ExtendsKeyword) { + if (seenExtendsClause) { + return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_already_seen); + } + + seenExtendsClause = true; + } + else { + Debug.assert(heritageClause.token === SyntaxKind.ImplementsKeyword); + return grammarErrorOnFirstToken(heritageClause, Diagnostics.Interface_declaration_cannot_have_implements_clause); + } + + // Grammar checking heritageClause inside class declaration + checkGrammarHeritageClause(heritageClause); + } + } + + return false; + } + + function checkGrammarComputedPropertyName(node: Node): boolean { + // If node is not a computedPropertyName, just skip the grammar checking + if (node.kind !== SyntaxKind.ComputedPropertyName) { + return false; + } + + let computedPropertyName = node; + if (computedPropertyName.expression.kind === SyntaxKind.BinaryExpression && (computedPropertyName.expression).operatorToken.kind === SyntaxKind.CommaToken) { + return grammarErrorOnNode(computedPropertyName.expression, Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name); + } + } + + function checkGrammarForGenerator(node: FunctionLikeDeclaration) { + if (node.asteriskToken) { + return grammarErrorOnNode(node.asteriskToken, Diagnostics.Generators_are_not_currently_supported); + } + } + + function checkGrammarFunctionName(name: Node) { + // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression (13.1)) + return checkGrammarEvalOrArgumentsInStrictMode(name, name); + } + + function checkGrammarForInvalidQuestionMark(node: Declaration, questionToken: Node, message: DiagnosticMessage): boolean { + if (questionToken) { + return grammarErrorOnNode(questionToken, message); + } + } + + function checkGrammarObjectLiteralExpression(node: ObjectLiteralExpression) { + let seen: Map = {}; + let Property = 1; + let GetAccessor = 2; + let SetAccesor = 4; + let GetOrSetAccessor = GetAccessor | SetAccesor; + let inStrictMode = (node.parserContextFlags & ParserContextFlags.StrictMode) !== 0; + + for (let prop of node.properties) { + let name = prop.name; + if (prop.kind === SyntaxKind.OmittedExpression || + name.kind === SyntaxKind.ComputedPropertyName) { + // If the name is not a ComputedPropertyName, the grammar checking will skip it + checkGrammarComputedPropertyName(name); + continue; + } + + // ECMA-262 11.1.5 Object Initialiser + // If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true + // a.This production is contained in strict code and IsDataDescriptor(previous) is true and + // IsDataDescriptor(propId.descriptor) is true. + // b.IsDataDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true. + // c.IsAccessorDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true. + // d.IsAccessorDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true + // and either both previous and propId.descriptor have[[Get]] fields or both previous and propId.descriptor have[[Set]] fields + let currentKind: number; + if (prop.kind === SyntaxKind.PropertyAssignment || prop.kind === SyntaxKind.ShorthandPropertyAssignment) { + // Grammar checking for computedPropertName and shorthandPropertyAssignment + checkGrammarForInvalidQuestionMark(prop,(prop).questionToken, Diagnostics.An_object_member_cannot_be_declared_optional); + if (name.kind === SyntaxKind.NumericLiteral) { + checkGrammarNumericLiteral(name); + } + currentKind = Property; + } + else if ( prop.kind === SyntaxKind.MethodDeclaration) { + currentKind = Property; + } + else if (prop.kind === SyntaxKind.GetAccessor) { + currentKind = GetAccessor; + } + else if (prop.kind === SyntaxKind.SetAccessor) { + currentKind = SetAccesor; + } + else { + Debug.fail("Unexpected syntax kind:" + prop.kind); + } + + if (!hasProperty(seen, (name).text)) { + seen[(name).text] = currentKind; + } + else { + let existingKind = seen[(name).text]; + if (currentKind === Property && existingKind === Property) { + if (inStrictMode) { + grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode); + } + } + else if ((currentKind & GetOrSetAccessor) && (existingKind & GetOrSetAccessor)) { + if (existingKind !== GetOrSetAccessor && currentKind !== existingKind) { + seen[(name).text] = currentKind | existingKind; + } + else { + return grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name); + } + } + else { + return grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name); + } + } + } + } + + function checkGrammarForInOrForOfStatement(forInOrOfStatement: ForInStatement | ForOfStatement): boolean { + if (checkGrammarStatementInAmbientContext(forInOrOfStatement)) { + return true; + } + + if (forInOrOfStatement.initializer.kind === SyntaxKind.VariableDeclarationList) { + let variableList = forInOrOfStatement.initializer; + if (!checkGrammarVariableDeclarationList(variableList)) { + if (variableList.declarations.length > 1) { + let diagnostic = forInOrOfStatement.kind === SyntaxKind.ForInStatement + ? Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement + : Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement; + return grammarErrorOnFirstToken(variableList.declarations[1], diagnostic); + } + let firstDeclaration = variableList.declarations[0]; + if (firstDeclaration.initializer) { + let diagnostic = forInOrOfStatement.kind === SyntaxKind.ForInStatement + ? Diagnostics.The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer + : Diagnostics.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer; + return grammarErrorOnNode(firstDeclaration.name, diagnostic); + } + if (firstDeclaration.type) { + let diagnostic = forInOrOfStatement.kind === SyntaxKind.ForInStatement + ? Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation + : Diagnostics.The_left_hand_side_of_a_for_of_statement_cannot_use_a_type_annotation; + return grammarErrorOnNode(firstDeclaration, diagnostic); + } + } + } + + return false; + } + + function checkGrammarAccessor(accessor: MethodDeclaration): boolean { + let kind = accessor.kind; + if (languageVersion < ScriptTarget.ES5) { + return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher); + } + else if (isInAmbientContext(accessor)) { + return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_be_declared_in_an_ambient_context); + } + else if (accessor.body === undefined) { + return grammarErrorAtPos(getSourceFileOfNode(accessor), accessor.end - 1, ";".length, Diagnostics._0_expected, "{"); + } + else if (accessor.typeParameters) { + return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_have_type_parameters); + } + else if (kind === SyntaxKind.GetAccessor && accessor.parameters.length) { + return grammarErrorOnNode(accessor.name, Diagnostics.A_get_accessor_cannot_have_parameters); + } + else if (kind === SyntaxKind.SetAccessor) { + if (accessor.type) { + return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_cannot_have_a_return_type_annotation); + } + else if (accessor.parameters.length !== 1) { + return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_must_have_exactly_one_parameter); + } + else { + let parameter = accessor.parameters[0]; + if (parameter.dotDotDotToken) { + return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_set_accessor_cannot_have_rest_parameter); + } + else if (parameter.flags & NodeFlags.Modifier) { + return grammarErrorOnNode(accessor.name, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); + } + else if (parameter.questionToken) { + return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_set_accessor_cannot_have_an_optional_parameter); + } + else if (parameter.initializer) { + return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_parameter_cannot_have_an_initializer); + } + } + } + } + + function checkGrammarForNonSymbolComputedProperty(node: DeclarationName, message: DiagnosticMessage) { + if (node.kind === SyntaxKind.ComputedPropertyName && !isWellKnownSymbolSyntactically((node).expression)) { + return grammarErrorOnNode(node, message); + } + } + + function checkGrammarMethod(node: MethodDeclaration) { + if (checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) || + checkGrammarFunctionLikeDeclaration(node) || + checkGrammarForGenerator(node)) { + return true; + } + + if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) { + if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional)) { + return true; + } + else if (node.body === undefined) { + return grammarErrorAtPos(getSourceFile(node), node.end - 1, ";".length, Diagnostics._0_expected, "{"); + } + } + + if (node.parent.kind === SyntaxKind.ClassDeclaration) { + if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional)) { + return true; + } + // Technically, computed properties in ambient contexts is disallowed + // for property declarations and accessors too, not just methods. + // However, property declarations disallow computed names in general, + // and accessors are not allowed in ambient contexts in general, + // so this error only really matters for methods. + if (isInAmbientContext(node)) { + return checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_an_ambient_context_must_directly_refer_to_a_built_in_symbol); + } + else if (!node.body) { + return checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_a_method_overload_must_directly_refer_to_a_built_in_symbol); + } + } + else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { + return checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_an_interface_must_directly_refer_to_a_built_in_symbol); + } + else if (node.parent.kind === SyntaxKind.TypeLiteral) { + return checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_a_type_literal_must_directly_refer_to_a_built_in_symbol); + } + } + + function isIterationStatement(node: Node, lookInLabeledStatements: boolean): boolean { + switch (node.kind) { + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + return true; + case SyntaxKind.LabeledStatement: + return lookInLabeledStatements && isIterationStatement((node).statement, lookInLabeledStatements); + } + + return false; + } + + function checkGrammarBreakOrContinueStatement(node: BreakOrContinueStatement): boolean { + let current: Node = node; + while (current) { + if (isFunctionLike(current)) { + return grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary); + } + + switch (current.kind) { + case SyntaxKind.LabeledStatement: + if (node.label && (current).label.text === node.label.text) { + // found matching label - verify that label usage is correct + // continue can only target labels that are on iteration statements + let isMisplacedContinueLabel = node.kind === SyntaxKind.ContinueStatement + && !isIterationStatement((current).statement, /*lookInLabeledStatement*/ true); + + if (isMisplacedContinueLabel) { + return grammarErrorOnNode(node, Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement); + } + + return false; + } + break; + case SyntaxKind.SwitchStatement: + if (node.kind === SyntaxKind.BreakStatement && !node.label) { + // unlabeled break within switch statement - ok + return false; + } + break; + default: + if (isIterationStatement(current, /*lookInLabeledStatement*/ false) && !node.label) { + // unlabeled break or continue within iteration statement - ok + return false; + } + break; + } + + current = current.parent; + } + + if (node.label) { + let message = node.kind === SyntaxKind.BreakStatement + ? Diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement + : Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement; + + return grammarErrorOnNode(node, message) + } + else { + let message = node.kind === SyntaxKind.BreakStatement + ? Diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement + : Diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement; + return grammarErrorOnNode(node, message) + } + } + + function checkGrammarBindingElement(node: BindingElement) { + if (node.dotDotDotToken) { + let elements = (node.parent).elements; + if (node !== elements[elements.length - 1]) { + return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern); + } + + if (node.name.kind === SyntaxKind.ArrayBindingPattern || node.name.kind === SyntaxKind.ObjectBindingPattern) { + return grammarErrorOnNode(node.name, Diagnostics.A_rest_element_cannot_contain_a_binding_pattern); + } + + if (node.initializer) { + // Error on equals token which immediate precedes the initializer + return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer); + } + } + // It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code + // and its Identifier is eval or arguments + return checkGrammarEvalOrArgumentsInStrictMode(node, node.name); + } + + function checkGrammarVariableDeclaration(node: VariableDeclaration) { + if (node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) { + if (isInAmbientContext(node)) { + if (node.initializer) { + // Error on equals token which immediate precedes the initializer + let equalsTokenLength = "=".length; + return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - equalsTokenLength, + equalsTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); + } + } + else if (!node.initializer) { + if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) { + return grammarErrorOnNode(node, Diagnostics.A_destructuring_declaration_must_have_an_initializer); + } + if (isConst(node)) { + return grammarErrorOnNode(node, Diagnostics.const_declarations_must_be_initialized); + } + } + } + + let checkLetConstNames = languageVersion >= ScriptTarget.ES6 && (isLet(node) || isConst(node)); + + // 1. LexicalDeclaration : LetOrConst BindingList ; + // It is a Syntax Error if the BoundNames of BindingList contains "let". + // 2. ForDeclaration: ForDeclaration : LetOrConst ForBinding + // It is a Syntax Error if the BoundNames of ForDeclaration contains "let". + + // It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code + // and its Identifier is eval or arguments + return (checkLetConstNames && checkGrammarNameInLetOrConstDeclarations(node.name)) || + checkGrammarEvalOrArgumentsInStrictMode(node, node.name); + } + + function checkGrammarNameInLetOrConstDeclarations(name: Identifier | BindingPattern): boolean { + if (name.kind === SyntaxKind.Identifier) { + if ((name).text === "let") { + return grammarErrorOnNode(name, Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations); + } + } + else { + let elements = (name).elements; + for (let element of elements) { + if (element.kind !== SyntaxKind.OmittedExpression) { + checkGrammarNameInLetOrConstDeclarations(element.name); + } + } + } + } + + function checkGrammarVariableDeclarationList(declarationList: VariableDeclarationList): boolean { + let declarations = declarationList.declarations; + if (checkGrammarForDisallowedTrailingComma(declarationList.declarations)) { + return true; + } + + if (!declarationList.declarations.length) { + return grammarErrorAtPos(getSourceFileOfNode(declarationList), declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty); + } + } + + function allowLetAndConstDeclarations(parent: Node): boolean { + switch (parent.kind) { + case SyntaxKind.IfStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + return false; + case SyntaxKind.LabeledStatement: + return allowLetAndConstDeclarations(parent.parent); + } + + return true; + } + + function checkGrammarForDisallowedLetOrConstStatement(node: VariableStatement) { + if (!allowLetAndConstDeclarations(node.parent)) { + if (isLet(node.declarationList)) { + return grammarErrorOnNode(node, Diagnostics.let_declarations_can_only_be_declared_inside_a_block); + } + else if (isConst(node.declarationList)) { + return grammarErrorOnNode(node, Diagnostics.const_declarations_can_only_be_declared_inside_a_block); + } + } + } + + function isIntegerLiteral(expression: Expression): boolean { + if (expression.kind === SyntaxKind.PrefixUnaryExpression) { + let unaryExpression = expression; + if (unaryExpression.operator === SyntaxKind.PlusToken || unaryExpression.operator === SyntaxKind.MinusToken) { + expression = unaryExpression.operand; + } + } + if (expression.kind === SyntaxKind.NumericLiteral) { + // Allows for scientific notation since literalExpression.text was formed by + // coercing a number to a string. Sometimes this coercion can yield a string + // in scientific notation. + // We also don't need special logic for hex because a hex integer is converted + // to decimal when it is coerced. + return /^[0-9]+([eE]\+?[0-9]+)?$/.test((expression).text); + } + + return false; + } + + function checkGrammarEnumDeclaration(enumDecl: EnumDeclaration): boolean { + let enumIsConst = (enumDecl.flags & NodeFlags.Const) !== 0; + + let hasError = false; + + // skip checks below for const enums - they allow arbitrary initializers as long as they can be evaluated to constant expressions. + // since all values are known in compile time - it is not necessary to check that constant enum section precedes computed enum members. + if (!enumIsConst) { + let inConstantEnumMemberSection = true; + let inAmbientContext = isInAmbientContext(enumDecl); + for (let node of enumDecl.members) { + // Do not use hasDynamicName here, because that returns false for well known symbols. + // We want to perform checkComputedPropertyName for all computed properties, including + // well known symbols. + if (node.name.kind === SyntaxKind.ComputedPropertyName) { + hasError = grammarErrorOnNode(node.name, Diagnostics.Computed_property_names_are_not_allowed_in_enums); + } + else if (inAmbientContext) { + if (node.initializer && !isIntegerLiteral(node.initializer)) { + hasError = grammarErrorOnNode(node.name, Diagnostics.Ambient_enum_elements_can_only_have_integer_literal_initializers) || hasError; + } + } + else if (node.initializer) { + inConstantEnumMemberSection = isIntegerLiteral(node.initializer); + } + else if (!inConstantEnumMemberSection) { + hasError = grammarErrorOnNode(node.name, Diagnostics.Enum_member_must_have_initializer) || hasError; + } + } + } + + return hasError; + } + + function hasParseDiagnostics(sourceFile: SourceFile): boolean { + return sourceFile.parseDiagnostics.length > 0; + } + + function grammarErrorOnFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + let sourceFile = getSourceFileOfNode(node); + if (!hasParseDiagnostics(sourceFile)) { + let span = getSpanOfTokenAtPosition(sourceFile, node.pos); + diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2)); + return true; + } + } + + function grammarErrorAtPos(sourceFile: SourceFile, start: number, length: number, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + if (!hasParseDiagnostics(sourceFile)) { + diagnostics.add(createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2)); + return true; + } + } + + function grammarErrorOnNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + let sourceFile = getSourceFileOfNode(node); + if (!hasParseDiagnostics(sourceFile)) { + diagnostics.add(createDiagnosticForNode(node, message, arg0, arg1, arg2)); + return true; + } + } + + function checkGrammarEvalOrArgumentsInStrictMode(contextNode: Node, name: Node): boolean { + if (name && name.kind === SyntaxKind.Identifier) { + let identifier = name; + if (contextNode && (contextNode.parserContextFlags & ParserContextFlags.StrictMode) && isEvalOrArgumentsIdentifier(identifier)) { + let nameText = declarationNameToString(identifier); + + // We check first if the name is inside class declaration or class expression; if so give explicit message + // otherwise report generic error message. + // reportGrammarErrorInClassDeclaration only return true if grammar error is successfully reported and false otherwise + let reportErrorInClassDeclaration = reportStrictModeGrammarErrorInClassDeclaration(identifier, Diagnostics.Invalid_use_of_0_Class_definitions_are_automatically_in_strict_mode, nameText); + if (!reportErrorInClassDeclaration){ + return grammarErrorOnNode(identifier, Diagnostics.Invalid_use_of_0_in_strict_mode, nameText); + } + return reportErrorInClassDeclaration; + } + } + } + + function isEvalOrArgumentsIdentifier(node: Node): boolean { + return node.kind === SyntaxKind.Identifier && + ((node).text === "eval" || (node).text === "arguments"); + } + + function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) { + if (node.typeParameters) { + return grammarErrorAtPos(getSourceFileOfNode(node), node.typeParameters.pos, node.typeParameters.end - node.typeParameters.pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration); + } + } + + function checkGrammarConstructorTypeAnnotation(node: ConstructorDeclaration) { + if (node.type) { + return grammarErrorOnNode(node.type, Diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration); + } + } + + function checkGrammarProperty(node: PropertyDeclaration) { + if (node.parent.kind === SyntaxKind.ClassDeclaration) { + if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional) || + checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_a_class_property_declaration_must_directly_refer_to_a_built_in_symbol)) { + return true; + } + } + else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { + if (checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_an_interface_must_directly_refer_to_a_built_in_symbol)) { + return true; + } + } + else if (node.parent.kind === SyntaxKind.TypeLiteral) { + if (checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_a_type_literal_must_directly_refer_to_a_built_in_symbol)) { + return true; + } + } + + if (isInAmbientContext(node) && node.initializer) { + return grammarErrorOnFirstToken(node.initializer, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); + } + } + + function checkGrammarTopLevelElementForRequiredDeclareModifier(node: Node): boolean { + // A declare modifier is required for any top level .d.ts declaration except export=, export default, + // interfaces and imports categories: + // + // DeclarationElement: + // ExportAssignment + // export_opt InterfaceDeclaration + // export_opt ImportDeclaration + // export_opt ExternalImportDeclaration + // export_opt AmbientDeclaration + // + if (node.kind === SyntaxKind.InterfaceDeclaration || + node.kind === SyntaxKind.ImportDeclaration || + node.kind === SyntaxKind.ImportEqualsDeclaration || + node.kind === SyntaxKind.ExportDeclaration || + node.kind === SyntaxKind.ExportAssignment || + (node.flags & NodeFlags.Ambient) || + (node.flags & (NodeFlags.Export | NodeFlags.Default))) { + + return false; + } + + return grammarErrorOnFirstToken(node, Diagnostics.A_declare_modifier_is_required_for_a_top_level_declaration_in_a_d_ts_file); + } + + function checkGrammarTopLevelElementsForRequiredDeclareModifier(file: SourceFile): boolean { + for (let decl of file.statements) { + if (isDeclaration(decl) || decl.kind === SyntaxKind.VariableStatement) { + if (checkGrammarTopLevelElementForRequiredDeclareModifier(decl)) { + return true; + } + } + } + } + + function checkGrammarSourceFile(node: SourceFile): boolean { + return isInAmbientContext(node) && checkGrammarTopLevelElementsForRequiredDeclareModifier(node); + } + + function checkGrammarStatementInAmbientContext(node: Node): boolean { + if (isInAmbientContext(node)) { + // An accessors is already reported about the ambient context + if (isAccessor(node.parent.kind)) { + return getNodeLinks(node).hasReportedStatementInAmbientContext = true; + } + + // Find containing block which is either Block, ModuleBlock, SourceFile + let links = getNodeLinks(node); + if (!links.hasReportedStatementInAmbientContext && isFunctionLike(node.parent)) { + return getNodeLinks(node).hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts) + } + + // We are either parented by another statement, or some sort of block. + // If we're in a block, we only want to really report an error once + // to prevent noisyness. So use a bit on the block to indicate if + // this has already been reported, and don't report if it has. + // + if (node.parent.kind === SyntaxKind.Block || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { + let links = getNodeLinks(node.parent); + // Check if the containing block ever report this error + if (!links.hasReportedStatementInAmbientContext) { + return links.hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.Statements_are_not_allowed_in_ambient_contexts); + } + } + else { + // We must be parented by a statement. If so, there's no need + // to report the error as our parent will have already done it. + // Debug.assert(isStatement(node.parent)); + } + } + } + + function checkGrammarNumericLiteral(node: Identifier): boolean { + // Grammar checking + if (node.flags & NodeFlags.OctalLiteral) { + if (node.parserContextFlags & ParserContextFlags.StrictMode) { + return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode); + } + else if (languageVersion >= ScriptTarget.ES5) { + return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher); + } + } + } + + function grammarErrorAfterFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + let sourceFile = getSourceFileOfNode(node); + if (!hasParseDiagnostics(sourceFile)) { + let span = getSpanOfTokenAtPosition(sourceFile, node.pos); + diagnostics.add(createFileDiagnostic(sourceFile, textSpanEnd(span), /*length*/ 0, message, arg0, arg1, arg2)); + return true; + } + } + + initializeTypeChecker(); + + return checker; + } +} diff --git a/lib/typescript/compiler/commandLineParser.ts b/lib/typescript/compiler/commandLineParser.ts new file mode 100644 index 000000000..db2fb55d1 --- /dev/null +++ b/lib/typescript/compiler/commandLineParser.ts @@ -0,0 +1,388 @@ +/// +/// +/// +/// + +module ts { + /* @internal */ + export var optionDeclarations: CommandLineOption[] = [ + { + name: "charset", + type: "string", + }, + { + name: "declaration", + shortName: "d", + type: "boolean", + description: Diagnostics.Generates_corresponding_d_ts_file, + }, + { + name: "diagnostics", + type: "boolean", + }, + { + name: "emitBOM", + type: "boolean" + }, + { + name: "help", + shortName: "h", + type: "boolean", + description: Diagnostics.Print_this_message, + }, + { + name: "listFiles", + type: "boolean", + }, + { + name: "locale", + type: "string", + }, + { + name: "mapRoot", + type: "string", + isFilePath: true, + description: Diagnostics.Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations, + paramType: Diagnostics.LOCATION, + }, + { + name: "module", + shortName: "m", + type: { + "commonjs": ModuleKind.CommonJS, + "amd": ModuleKind.AMD, + "umd": ModuleKind.UMD + }, + description: Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_or_umd, + paramType: Diagnostics.KIND, + error: Diagnostics.Argument_for_module_option_must_be_commonjs_amd_or_umd + }, + { + name: "noEmit", + type: "boolean", + description: Diagnostics.Do_not_emit_outputs, + }, + { + name: "noEmitOnError", + type: "boolean", + description: Diagnostics.Do_not_emit_outputs_if_any_type_checking_errors_were_reported, + }, + { + name: "noImplicitAny", + type: "boolean", + description: Diagnostics.Raise_error_on_expressions_and_declarations_with_an_implied_any_type, + }, + { + name: "noLib", + type: "boolean", + }, + { + name: "noResolve", + type: "boolean", + }, + { + name: "out", + type: "string", + description: Diagnostics.Concatenate_and_emit_output_to_single_file, + paramType: Diagnostics.FILE, + }, + { + name: "outDir", + type: "string", + isFilePath: true, + description: Diagnostics.Redirect_output_structure_to_the_directory, + paramType: Diagnostics.DIRECTORY, + }, + { + name: "preserveConstEnums", + type: "boolean", + description: Diagnostics.Do_not_erase_const_enum_declarations_in_generated_code + }, + { + name: "project", + shortName: "p", + type: "string", + isFilePath: true, + description: Diagnostics.Compile_the_project_in_the_given_directory, + paramType: Diagnostics.DIRECTORY + }, + { + name: "removeComments", + type: "boolean", + description: Diagnostics.Do_not_emit_comments_to_output, + }, + { + name: "rootDir", + type: "string", + isFilePath: true, + description: Diagnostics.Specifies_the_root_directory_of_input_files_Use_to_control_the_output_directory_structure_with_outDir, + paramType: Diagnostics.LOCATION, + }, + { + name: "separateCompilation", + type: "boolean", + }, + { + name: "sourceMap", + type: "boolean", + description: Diagnostics.Generates_corresponding_map_file, + }, + { + name: "sourceRoot", + type: "string", + isFilePath: true, + description: Diagnostics.Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations, + paramType: Diagnostics.LOCATION, + }, + { + name: "suppressImplicitAnyIndexErrors", + type: "boolean", + description: Diagnostics.Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures, + }, + { + name: "stripInternal", + type: "boolean", + description: Diagnostics.Do_not_emit_declarations_for_code_that_has_an_internal_annotation, + experimental: true + }, + { + name: "target", + shortName: "t", + type: { "es3": ScriptTarget.ES3, "es5": ScriptTarget.ES5, "es6": ScriptTarget.ES6 }, + description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES6_experimental, + paramType: Diagnostics.VERSION, + error: Diagnostics.Argument_for_target_option_must_be_ES3_ES5_or_ES6 + }, + { + name: "version", + shortName: "v", + type: "boolean", + description: Diagnostics.Print_the_compiler_s_version, + }, + { + name: "watch", + shortName: "w", + type: "boolean", + description: Diagnostics.Watch_input_files, + }, + { + name: "emitDecoratorMetadata", + type: "boolean", + experimental: true + } + ]; + + export function parseCommandLine(commandLine: string[]): ParsedCommandLine { + var options: CompilerOptions = {}; + var fileNames: string[] = []; + var errors: Diagnostic[] = []; + var shortOptionNames: Map = {}; + var optionNameMap: Map = {}; + + forEach(optionDeclarations, option => { + optionNameMap[option.name.toLowerCase()] = option; + if (option.shortName) { + shortOptionNames[option.shortName] = option.name; + } + }); + parseStrings(commandLine); + return { + options, + fileNames, + errors + }; + + function parseStrings(args: string[]) { + var i = 0; + while (i < args.length) { + var s = args[i++]; + if (s.charCodeAt(0) === CharacterCodes.at) { + parseResponseFile(s.slice(1)); + } + else if (s.charCodeAt(0) === CharacterCodes.minus) { + s = s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase(); + + // Try to translate short option names to their full equivalents. + if (hasProperty(shortOptionNames, s)) { + s = shortOptionNames[s]; + } + + if (hasProperty(optionNameMap, s)) { + var opt = optionNameMap[s]; + + // Check to see if no argument was provided (e.g. "--locale" is the last command-line argument). + if (!args[i] && opt.type !== "boolean") { + errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_expects_an_argument, opt.name)); + } + + switch (opt.type) { + case "number": + options[opt.name] = parseInt(args[i++]); + break; + case "boolean": + options[opt.name] = true; + break; + case "string": + options[opt.name] = args[i++] || ""; + break; + // If not a primitive, the possible types are specified in what is effectively a map of options. + default: + var map = >opt.type; + var key = (args[i++] || "").toLowerCase(); + if (hasProperty(map, key)) { + options[opt.name] = map[key]; + } + else { + errors.push(createCompilerDiagnostic(opt.error)); + } + } + } + else { + errors.push(createCompilerDiagnostic(Diagnostics.Unknown_compiler_option_0, s)); + } + } + else { + fileNames.push(s); + } + } + } + + function parseResponseFile(fileName: string) { + var text = sys.readFile(fileName); + + if (!text) { + errors.push(createCompilerDiagnostic(Diagnostics.File_0_not_found, fileName)); + return; + } + + var args: string[] = []; + var pos = 0; + while (true) { + while (pos < text.length && text.charCodeAt(pos) <= CharacterCodes.space) pos++; + if (pos >= text.length) break; + var start = pos; + if (text.charCodeAt(start) === CharacterCodes.doubleQuote) { + pos++; + while (pos < text.length && text.charCodeAt(pos) !== CharacterCodes.doubleQuote) pos++; + if (pos < text.length) { + args.push(text.substring(start + 1, pos)); + pos++; + } + else { + errors.push(createCompilerDiagnostic(Diagnostics.Unterminated_quoted_string_in_response_file_0, fileName)); + } + } + else { + while (text.charCodeAt(pos) > CharacterCodes.space) pos++; + args.push(text.substring(start, pos)); + } + } + parseStrings(args); + } + } + + /** + * Read tsconfig.json file + * @param fileName The path to the config file + */ + export function readConfigFile(fileName: string): { config?: any; error?: Diagnostic } { + try { + var text = sys.readFile(fileName); + } + catch (e) { + return { error: createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message) }; + } + return parseConfigFileText(fileName, text); + } + + /** + * Parse the text of the tsconfig.json file + * @param fileName The path to the config file + * @param jsonText The text of the config file + */ + export function parseConfigFileText(fileName: string, jsonText: string): { config?: any; error?: Diagnostic } { + try { + return { config: /\S/.test(jsonText) ? JSON.parse(jsonText) : {} }; + } + catch (e) { + return { error: createCompilerDiagnostic(Diagnostics.Failed_to_parse_file_0_Colon_1, fileName, e.message) }; + } + } + + /** + * Parse the contents of a config file (tsconfig.json). + * @param json The contents of the config file to parse + * @param basePath A root directory to resolve relative path entries in the config + * file to. e.g. outDir + */ + export function parseConfigFile(json: any, host: ParseConfigHost, basePath: string): ParsedCommandLine { + var errors: Diagnostic[] = []; + + return { + options: getCompilerOptions(), + fileNames: getFiles(), + errors + }; + + function getCompilerOptions(): CompilerOptions { + var options: CompilerOptions = {}; + var optionNameMap: Map = {}; + forEach(optionDeclarations, option => { + optionNameMap[option.name] = option; + }); + var jsonOptions = json["compilerOptions"]; + if (jsonOptions) { + for (var id in jsonOptions) { + if (hasProperty(optionNameMap, id)) { + var opt = optionNameMap[id]; + var optType = opt.type; + var value = jsonOptions[id]; + var expectedType = typeof optType === "string" ? optType : "string"; + if (typeof value === expectedType) { + if (typeof optType !== "string") { + var key = value.toLowerCase(); + if (hasProperty(optType, key)) { + value = optType[key]; + } + else { + errors.push(createCompilerDiagnostic(opt.error)); + value = 0; + } + } + if (opt.isFilePath) { + value = normalizePath(combinePaths(basePath, value)); + } + options[opt.name] = value; + } + else { + errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, id, expectedType)); + } + } + else { + errors.push(createCompilerDiagnostic(Diagnostics.Unknown_compiler_option_0, id)); + } + } + } + return options; + } + + function getFiles(): string[] { + var files: string[] = []; + if (hasProperty(json, "files")) { + if (json["files"] instanceof Array) { + var files = map(json["files"], s => combinePaths(basePath, s)); + } + } + else { + var sysFiles = host.readDirectory(basePath, ".ts"); + for (var i = 0; i < sysFiles.length; i++) { + var name = sysFiles[i]; + if (!fileExtensionIs(name, ".d.ts") || !contains(sysFiles, name.substr(0, name.length - 5) + ".ts")) { + files.push(name); + } + } + } + return files; + } + } +} diff --git a/lib/typescript/compiler/core.ts b/lib/typescript/compiler/core.ts new file mode 100644 index 000000000..5f4cf64f1 --- /dev/null +++ b/lib/typescript/compiler/core.ts @@ -0,0 +1,740 @@ +/// + +/* @internal */ +module ts { + // Ternary values are defined such that + // x & y is False if either x or y is False. + // x & y is Maybe if either x or y is Maybe, but neither x or y is False. + // x & y is True if both x and y are True. + // x | y is False if both x and y are False. + // x | y is Maybe if either x or y is Maybe, but neither x or y is True. + // x | y is True if either x or y is True. + export const enum Ternary { + False = 0, + Maybe = 1, + True = -1 + } + + export const enum Comparison { + LessThan = -1, + EqualTo = 0, + GreaterThan = 1 + } + + export interface StringSet extends Map { } + + export function forEach(array: T[], callback: (element: T, index: number) => U): U { + if (array) { + for (let i = 0, len = array.length; i < len; i++) { + let result = callback(array[i], i); + if (result) { + return result; + } + } + } + return undefined; + } + + export function contains(array: T[], value: T): boolean { + if (array) { + for (let v of array) { + if (v === value) { + return true; + } + } + } + return false; + } + + export function indexOf(array: T[], value: T): number { + if (array) { + for (let i = 0, len = array.length; i < len; i++) { + if (array[i] === value) { + return i; + } + } + } + return -1; + } + + export function countWhere(array: T[], predicate: (x: T) => boolean): number { + let count = 0; + if (array) { + for (let v of array) { + if (predicate(v)) { + count++; + } + } + } + return count; + } + + export function filter(array: T[], f: (x: T) => boolean): T[]{ + let result: T[]; + if (array) { + result = []; + for (let item of array) { + if (f(item)) { + result.push(item); + } + } + } + return result; + } + + export function map(array: T[], f: (x: T) => U): U[]{ + let result: U[]; + if (array) { + result = []; + for (let v of array) { + result.push(f(v)); + } + } + return result; + } + + export function concatenate(array1: T[], array2: T[]): T[] { + if (!array2 || !array2.length) return array1; + if (!array1 || !array1.length) return array2; + + return array1.concat(array2); + } + + export function deduplicate(array: T[]): T[]{ + let result: T[]; + if (array) { + result = []; + for (let item of array) { + if (!contains(result, item)) { + result.push(item); + } + } + } + return result; + } + + export function sum(array: any[], prop: string): number { + let result = 0; + for (let v of array) { + result += v[prop]; + } + return result; + } + + export function addRange(to: T[], from: T[]): void { + if (to && from) { + for (let v of from) { + to.push(v); + } + } + } + + /** + * Returns the last element of an array if non-empty, undefined otherwise. + */ + export function lastOrUndefined(array: T[]): T { + if (array.length === 0) { + return undefined; + } + + return array[array.length - 1]; + } + + export function binarySearch(array: number[], value: number): number { + let low = 0; + let high = array.length - 1; + + while (low <= high) { + let middle = low + ((high - low) >> 1); + let midValue = array[middle]; + + if (midValue === value) { + return middle; + } + else if (midValue > value) { + high = middle - 1; + } + else { + low = middle + 1; + } + } + + return ~low; + } + + export function reduceLeft(array: T[], f: (a: T, x: T) => T): T; + export function reduceLeft(array: T[], f: (a: U, x: T) => U, initial: U): U; + export function reduceLeft(array: T[], f: (a: U, x: T) => U, initial?: U): U { + if (array) { + var count = array.length; + if (count > 0) { + var pos = 0; + var result = arguments.length <= 2 ? array[pos++] : initial; + while (pos < count) { + result = f(result, array[pos++]); + } + return result; + } + } + return initial; + } + + export function reduceRight(array: T[], f: (a: T, x: T) => T): T; + export function reduceRight(array: T[], f: (a: U, x: T) => U, initial: U): U; + export function reduceRight(array: T[], f: (a: U, x: T) => U, initial?: U): U { + if (array) { + var pos = array.length - 1; + if (pos >= 0) { + var result = arguments.length <= 2 ? array[pos--] : initial; + while (pos >= 0) { + result = f(result, array[pos--]); + } + return result; + } + } + return initial; + } + + let hasOwnProperty = Object.prototype.hasOwnProperty; + + export function hasProperty(map: Map, key: string): boolean { + return hasOwnProperty.call(map, key); + } + + export function getProperty(map: Map, key: string): T { + return hasOwnProperty.call(map, key) ? map[key] : undefined; + } + + export function isEmpty(map: Map) { + for (let id in map) { + if (hasProperty(map, id)) { + return false; + } + } + return true; + } + + export function clone(object: T): T { + let result: any = {}; + for (let id in object) { + result[id] = (object)[id]; + } + return result; + } + + export function extend(first: Map, second: Map): Map { + let result: Map = {}; + for (let id in first) { + result[id] = first[id]; + } + for (let id in second) { + if (!hasProperty(result, id)) { + result[id] = second[id]; + } + } + return result; + } + + export function forEachValue(map: Map, callback: (value: T) => U): U { + let result: U; + for (let id in map) { + if (result = callback(map[id])) break; + } + return result; + } + + export function forEachKey(map: Map, callback: (key: string) => U): U { + let result: U; + for (let id in map) { + if (result = callback(id)) break; + } + return result; + } + + export function lookUp(map: Map, key: string): T { + return hasProperty(map, key) ? map[key] : undefined; + } + + export function copyMap(source: Map, target: Map): void { + for (let p in source) { + target[p] = source[p]; + } + } + + /** + * Creates a map from the elements of an array. + * + * @param array the array of input elements. + * @param makeKey a function that produces a key for a given element. + * + * This function makes no effort to avoid collisions; if any two elements produce + * the same key with the given 'makeKey' function, then the element with the higher + * index in the array will be the one associated with the produced key. + */ + export function arrayToMap(array: T[], makeKey: (value: T) => string): Map { + let result: Map = {}; + + forEach(array, value => { + result[makeKey(value)] = value; + }); + + return result; + } + + export function memoize(callback: () => T): () => T { + let value: T; + return () => { + if (callback) { + value = callback(); + callback = undefined; + } + return value; + }; + } + + function formatStringFromArgs(text: string, args: { [index: number]: any; }, baseIndex?: number): string { + baseIndex = baseIndex || 0; + + return text.replace(/{(\d+)}/g, (match, index?) => args[+index + baseIndex]); + } + + export let localizedDiagnosticMessages: Map = undefined; + + export function getLocaleSpecificMessage(message: string) { + return localizedDiagnosticMessages && localizedDiagnosticMessages[message] + ? localizedDiagnosticMessages[message] + : message; + } + + export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: any[]): Diagnostic; + export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): Diagnostic { + let end = start + length; + + Debug.assert(start >= 0, "start must be non-negative, is " + start); + Debug.assert(length >= 0, "length must be non-negative, is " + length); + Debug.assert(start <= file.text.length, `start must be within the bounds of the file. ${ start } > ${ file.text.length }`); + Debug.assert(end <= file.text.length, `end must be the bounds of the file. ${ end } > ${ file.text.length }`); + + let text = getLocaleSpecificMessage(message.key); + + if (arguments.length > 4) { + text = formatStringFromArgs(text, arguments, 4); + } + + return { + file, + start, + length, + + messageText: text, + category: message.category, + code: message.code, + }; + } + + export function createCompilerDiagnostic(message: DiagnosticMessage, ...args: any[]): Diagnostic; + export function createCompilerDiagnostic(message: DiagnosticMessage): Diagnostic { + let text = getLocaleSpecificMessage(message.key); + + if (arguments.length > 1) { + text = formatStringFromArgs(text, arguments, 1); + } + + return { + file: undefined, + start: undefined, + length: undefined, + + messageText: text, + category: message.category, + code: message.code + }; + } + + export function chainDiagnosticMessages(details: DiagnosticMessageChain, message: DiagnosticMessage, ...args: any[]): DiagnosticMessageChain; + export function chainDiagnosticMessages(details: DiagnosticMessageChain, message: DiagnosticMessage): DiagnosticMessageChain { + let text = getLocaleSpecificMessage(message.key); + + if (arguments.length > 2) { + text = formatStringFromArgs(text, arguments, 2); + } + + return { + messageText: text, + category: message.category, + code: message.code, + + next: details + }; + } + + export function concatenateDiagnosticMessageChains(headChain: DiagnosticMessageChain, tailChain: DiagnosticMessageChain): DiagnosticMessageChain { + Debug.assert(!headChain.next); + headChain.next = tailChain; + return headChain; + } + + export function compareValues(a: T, b: T): Comparison { + if (a === b) return Comparison.EqualTo; + if (a === undefined) return Comparison.LessThan; + if (b === undefined) return Comparison.GreaterThan; + return a < b ? Comparison.LessThan : Comparison.GreaterThan; + } + + function getDiagnosticFileName(diagnostic: Diagnostic): string { + return diagnostic.file ? diagnostic.file.fileName : undefined; + } + + export function compareDiagnostics(d1: Diagnostic, d2: Diagnostic): Comparison { + return compareValues(getDiagnosticFileName(d1), getDiagnosticFileName(d2)) || + compareValues(d1.start, d2.start) || + compareValues(d1.length, d2.length) || + compareValues(d1.code, d2.code) || + compareMessageText(d1.messageText, d2.messageText) || + Comparison.EqualTo; + } + + function compareMessageText(text1: string | DiagnosticMessageChain, text2: string | DiagnosticMessageChain): Comparison { + while (text1 && text2) { + // We still have both chains. + let string1 = typeof text1 === "string" ? text1 : text1.messageText; + let string2 = typeof text2 === "string" ? text2 : text2.messageText; + + let res = compareValues(string1, string2); + if (res) { + return res; + } + + text1 = typeof text1 === "string" ? undefined : text1.next; + text2 = typeof text2 === "string" ? undefined : text2.next; + } + + if (!text1 && !text2) { + // if the chains are done, then these messages are the same. + return Comparison.EqualTo; + } + + // We still have one chain remaining. The shorter chain should come first. + return text1 ? Comparison.GreaterThan : Comparison.LessThan; + } + + export function sortAndDeduplicateDiagnostics(diagnostics: Diagnostic[]): Diagnostic[]{ + return deduplicateSortedDiagnostics(diagnostics.sort(compareDiagnostics)); + } + + export function deduplicateSortedDiagnostics(diagnostics: Diagnostic[]): Diagnostic[] { + if (diagnostics.length < 2) { + return diagnostics; + } + + let newDiagnostics = [diagnostics[0]]; + let previousDiagnostic = diagnostics[0]; + for (let i = 1; i < diagnostics.length; i++) { + let currentDiagnostic = diagnostics[i]; + let isDupe = compareDiagnostics(currentDiagnostic, previousDiagnostic) === Comparison.EqualTo; + if (!isDupe) { + newDiagnostics.push(currentDiagnostic); + previousDiagnostic = currentDiagnostic; + } + } + + return newDiagnostics; + } + + export function normalizeSlashes(path: string): string { + return path.replace(/\\/g, "/"); + } + + // Returns length of path root (i.e. length of "/", "x:/", "//server/share/, file:///user/files") + export function getRootLength(path: string): number { + if (path.charCodeAt(0) === CharacterCodes.slash) { + if (path.charCodeAt(1) !== CharacterCodes.slash) return 1; + let p1 = path.indexOf("/", 2); + if (p1 < 0) return 2; + let p2 = path.indexOf("/", p1 + 1); + if (p2 < 0) return p1 + 1; + return p2 + 1; + } + if (path.charCodeAt(1) === CharacterCodes.colon) { + if (path.charCodeAt(2) === CharacterCodes.slash) return 3; + return 2; + } + let idx = path.indexOf('://'); + if (idx !== -1) return idx + 3 + return 0; + } + + export let directorySeparator = "/"; + function getNormalizedParts(normalizedSlashedPath: string, rootLength: number) { + let parts = normalizedSlashedPath.substr(rootLength).split(directorySeparator); + let normalized: string[] = []; + for (let part of parts) { + if (part !== ".") { + if (part === ".." && normalized.length > 0 && normalized[normalized.length - 1] !== "..") { + normalized.pop(); + } + else { + // A part may be an empty string (which is 'falsy') if the path had consecutive slashes, + // e.g. "path//file.ts". Drop these before re-joining the parts. + if(part) { + normalized.push(part); + } + } + } + } + + return normalized; + } + + export function normalizePath(path: string): string { + path = normalizeSlashes(path); + let rootLength = getRootLength(path); + let normalized = getNormalizedParts(path, rootLength); + return path.substr(0, rootLength) + normalized.join(directorySeparator); + } + + export function getDirectoryPath(path: string) { + return path.substr(0, Math.max(getRootLength(path), path.lastIndexOf(directorySeparator))); + } + + export function isUrl(path: string) { + return path && !isRootedDiskPath(path) && path.indexOf("://") !== -1; + } + + export function isRootedDiskPath(path: string) { + return getRootLength(path) !== 0; + } + + function normalizedPathComponents(path: string, rootLength: number) { + let normalizedParts = getNormalizedParts(path, rootLength); + return [path.substr(0, rootLength)].concat(normalizedParts); + } + + export function getNormalizedPathComponents(path: string, currentDirectory: string) { + path = normalizeSlashes(path); + let rootLength = getRootLength(path); + if (rootLength == 0) { + // If the path is not rooted it is relative to current directory + path = combinePaths(normalizeSlashes(currentDirectory), path); + rootLength = getRootLength(path); + } + + return normalizedPathComponents(path, rootLength); + } + + export function getNormalizedAbsolutePath(fileName: string, currentDirectory: string) { + return getNormalizedPathFromPathComponents(getNormalizedPathComponents(fileName, currentDirectory)); + } + + export function getNormalizedPathFromPathComponents(pathComponents: string[]) { + if (pathComponents && pathComponents.length) { + return pathComponents[0] + pathComponents.slice(1).join(directorySeparator); + } + } + + function getNormalizedPathComponentsOfUrl(url: string) { + // Get root length of http://www.website.com/folder1/foler2/ + // In this example the root is: http://www.website.com/ + // normalized path components should be ["http://www.website.com/", "folder1", "folder2"] + + let urlLength = url.length; + // Initial root length is http:// part + let rootLength = url.indexOf("://") + "://".length; + while (rootLength < urlLength) { + // Consume all immediate slashes in the protocol + // eg.initial rootlength is just file:// but it needs to consume another "/" in file:/// + if (url.charCodeAt(rootLength) === CharacterCodes.slash) { + rootLength++; + } + else { + // non slash character means we continue proceeding to next component of root search + break; + } + } + + // there are no parts after http:// just return current string as the pathComponent + if (rootLength === urlLength) { + return [url]; + } + + // Find the index of "/" after website.com so the root can be http://www.website.com/ (from existing http://) + let indexOfNextSlash = url.indexOf(directorySeparator, rootLength); + if (indexOfNextSlash !== -1) { + // Found the "/" after the website.com so the root is length of http://www.website.com/ + // and get components afetr the root normally like any other folder components + rootLength = indexOfNextSlash + 1; + return normalizedPathComponents(url, rootLength); + } + else { + // Can't find the host assume the rest of the string as component + // but make sure we append "/" to it as root is not joined using "/" + // eg. if url passed in was http://website.com we want to use root as [http://website.com/] + // so that other path manipulations will be correct and it can be merged with relative paths correctly + return [url + directorySeparator]; + } + } + + function getNormalizedPathOrUrlComponents(pathOrUrl: string, currentDirectory: string) { + if (isUrl(pathOrUrl)) { + return getNormalizedPathComponentsOfUrl(pathOrUrl); + } + else { + return getNormalizedPathComponents(pathOrUrl, currentDirectory); + } + } + + export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, relativeOrAbsolutePath: string, currentDirectory: string, getCanonicalFileName: (fileName: string) => string, isAbsolutePathAnUrl: boolean) { + let pathComponents = getNormalizedPathOrUrlComponents(relativeOrAbsolutePath, currentDirectory); + let directoryComponents = getNormalizedPathOrUrlComponents(directoryPathOrUrl, currentDirectory); + if (directoryComponents.length > 1 && directoryComponents[directoryComponents.length - 1] === "") { + // If the directory path given was of type test/cases/ then we really need components of directory to be only till its name + // that is ["test", "cases", ""] needs to be actually ["test", "cases"] + directoryComponents.length--; + } + + // Find the component that differs + for (var joinStartIndex = 0; joinStartIndex < pathComponents.length && joinStartIndex < directoryComponents.length; joinStartIndex++) { + if (getCanonicalFileName(directoryComponents[joinStartIndex]) !== getCanonicalFileName(pathComponents[joinStartIndex])) { + break; + } + } + + // Get the relative path + if (joinStartIndex) { + let relativePath = ""; + let relativePathComponents = pathComponents.slice(joinStartIndex, pathComponents.length); + for (; joinStartIndex < directoryComponents.length; joinStartIndex++) { + if (directoryComponents[joinStartIndex] !== "") { + relativePath = relativePath + ".." + directorySeparator; + } + } + + return relativePath + relativePathComponents.join(directorySeparator); + } + + // Cant find the relative path, get the absolute path + let absolutePath = getNormalizedPathFromPathComponents(pathComponents); + if (isAbsolutePathAnUrl && isRootedDiskPath(absolutePath)) { + absolutePath = "file:///" + absolutePath; + } + + return absolutePath; + } + + export function getBaseFileName(path: string) { + let i = path.lastIndexOf(directorySeparator); + return i < 0 ? path : path.substring(i + 1); + } + + export function combinePaths(path1: string, path2: string) { + if (!(path1 && path1.length)) return path2; + if (!(path2 && path2.length)) return path1; + if (getRootLength(path2) !== 0) return path2; + if (path1.charAt(path1.length - 1) === directorySeparator) return path1 + path2; + return path1 + directorySeparator + path2; + } + + export function fileExtensionIs(path: string, extension: string): boolean { + let pathLen = path.length; + let extLen = extension.length; + return pathLen > extLen && path.substr(pathLen - extLen, extLen) === extension; + } + + let supportedExtensions = [".d.ts", ".ts", ".js"]; + + export function removeFileExtension(path: string): string { + for (let ext of supportedExtensions) { + + if (fileExtensionIs(path, ext)) { + return path.substr(0, path.length - ext.length); + } + } + + return path; + } + + let backslashOrDoubleQuote = /[\"\\]/g; + let escapedCharsRegExp = /[\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g; + let escapedCharsMap: Map = { + "\0": "\\0", + "\t": "\\t", + "\v": "\\v", + "\f": "\\f", + "\b": "\\b", + "\r": "\\r", + "\n": "\\n", + "\\": "\\\\", + "\"": "\\\"", + "\u2028": "\\u2028", // lineSeparator + "\u2029": "\\u2029", // paragraphSeparator + "\u0085": "\\u0085" // nextLine + }; + + export interface ObjectAllocator { + getNodeConstructor(kind: SyntaxKind): new () => Node; + getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol; + getTypeConstructor(): new (checker: TypeChecker, flags: TypeFlags) => Type; + getSignatureConstructor(): new (checker: TypeChecker) => Signature; + } + + function Symbol(flags: SymbolFlags, name: string) { + this.flags = flags; + this.name = name; + this.declarations = undefined; + } + + function Type(checker: TypeChecker, flags: TypeFlags) { + this.flags = flags; + } + + function Signature(checker: TypeChecker) { + } + + export let objectAllocator: ObjectAllocator = { + getNodeConstructor: kind => { + function Node() { + } + Node.prototype = { + kind: kind, + pos: 0, + end: 0, + flags: 0, + parent: undefined, + }; + return Node; + }, + getSymbolConstructor: () => Symbol, + getTypeConstructor: () => Type, + getSignatureConstructor: () => Signature + } + + export const enum AssertionLevel { + None = 0, + Normal = 1, + Aggressive = 2, + VeryAggressive = 3, + } + + export module Debug { + let currentAssertionLevel = AssertionLevel.None; + + export function shouldAssert(level: AssertionLevel): boolean { + return currentAssertionLevel >= level; + } + + export function assert(expression: boolean, message?: string, verboseDebugInfo?: () => string): void { + if (!expression) { + let verboseDebugString = ""; + if (verboseDebugInfo) { + verboseDebugString = "\r\nVerbose Debug Information: " + verboseDebugInfo(); + } + + throw new Error("Debug Failure. False expression: " + (message || "") + verboseDebugString); + } + } + + export function fail(message?: string): void { + Debug.assert(false, message); + } + } +} diff --git a/lib/typescript/compiler/declarationEmitter.ts b/lib/typescript/compiler/declarationEmitter.ts new file mode 100644 index 000000000..d2399e5d0 --- /dev/null +++ b/lib/typescript/compiler/declarationEmitter.ts @@ -0,0 +1,1590 @@ +/// + +/* @internal */ +module ts { + interface ModuleElementDeclarationEmitInfo { + node: Node; + outputPos: number; + indent: number; + asynchronousOutput?: string; // If the output for alias was written asynchronously, the corresponding output + subModuleElementDeclarationEmitInfo?: ModuleElementDeclarationEmitInfo[]; + isVisible?: boolean; + } + + interface DeclarationEmit { + reportedDeclarationError: boolean; + moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[]; + synchronousDeclarationOutput: string; + referencePathsOutput: string; + } + + type GetSymbolAccessibilityDiagnostic = (symbolAccesibilityResult: SymbolAccessiblityResult) => SymbolAccessibilityDiagnostic; + + interface EmitTextWriterWithSymbolWriter extends EmitTextWriter, SymbolWriter { + getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic; + } + + interface SymbolAccessibilityDiagnostic { + errorNode: Node; + diagnosticMessage: DiagnosticMessage; + typeName?: DeclarationName; + } + + export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, targetSourceFile: SourceFile): Diagnostic[] { + let diagnostics: Diagnostic[] = []; + let jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, host, ".js"); + emitDeclarations(host, resolver, diagnostics, jsFilePath, targetSourceFile); + return diagnostics; + } + + function emitDeclarations(host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[], jsFilePath: string, root?: SourceFile): DeclarationEmit { + let newLine = host.getNewLine(); + let compilerOptions = host.getCompilerOptions(); + let languageVersion = compilerOptions.target || ScriptTarget.ES3; + + let write: (s: string) => void; + let writeLine: () => void; + let increaseIndent: () => void; + let decreaseIndent: () => void; + let writeTextOfNode: (sourceFile: SourceFile, node: Node) => void; + + let writer = createAndSetNewTextWriterWithSymbolWriter(); + + let enclosingDeclaration: Node; + let currentSourceFile: SourceFile; + let reportedDeclarationError = false; + let emitJsDocComments = compilerOptions.removeComments ? function (declaration: Node) { } : writeJsDocComments; + let emit = compilerOptions.stripInternal ? stripInternal : emitNode; + + let moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = []; + let asynchronousSubModuleDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[]; + + // Contains the reference paths that needs to go in the declaration file. + // Collecting this separately because reference paths need to be first thing in the declaration file + // and we could be collecting these paths from multiple files into single one with --out option + let referencePathsOutput = ""; + + if (root) { + // Emitting just a single file, so emit references in this file only + if (!compilerOptions.noResolve) { + let addedGlobalFileReference = false; + forEach(root.referencedFiles, fileReference => { + let referencedFile = tryResolveScriptReference(host, root, fileReference); + + // All the references that are not going to be part of same file + if (referencedFile && ((referencedFile.flags & NodeFlags.DeclarationFile) || // This is a declare file reference + shouldEmitToOwnFile(referencedFile, compilerOptions) || // This is referenced file is emitting its own js file + !addedGlobalFileReference)) { // Or the global out file corresponding to this reference was not added + + writeReferencePath(referencedFile); + if (!isExternalModuleOrDeclarationFile(referencedFile)) { + addedGlobalFileReference = true; + } + } + }); + } + + emitSourceFile(root); + + // create asynchronous output for the importDeclarations + if (moduleElementDeclarationEmitInfo.length) { + let oldWriter = writer; + forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => { + if (aliasEmitInfo.isVisible) { + Debug.assert(aliasEmitInfo.node.kind === SyntaxKind.ImportDeclaration); + createAndSetNewTextWriterWithSymbolWriter(); + Debug.assert(aliasEmitInfo.indent === 0); + writeImportDeclaration(aliasEmitInfo.node); + aliasEmitInfo.asynchronousOutput = writer.getText(); + } + }); + setWriter(oldWriter); + } + } + else { + // Emit references corresponding to this file + let emittedReferencedFiles: SourceFile[] = []; + forEach(host.getSourceFiles(), sourceFile => { + if (!isExternalModuleOrDeclarationFile(sourceFile)) { + // Check what references need to be added + if (!compilerOptions.noResolve) { + forEach(sourceFile.referencedFiles, fileReference => { + let referencedFile = tryResolveScriptReference(host, sourceFile, fileReference); + + // If the reference file is a declaration file or an external module, emit that reference + if (referencedFile && (isExternalModuleOrDeclarationFile(referencedFile) && + !contains(emittedReferencedFiles, referencedFile))) { // If the file reference was not already emitted + + writeReferencePath(referencedFile); + emittedReferencedFiles.push(referencedFile); + } + }); + } + + emitSourceFile(sourceFile); + } + }); + } + + return { + reportedDeclarationError, + moduleElementDeclarationEmitInfo, + synchronousDeclarationOutput: writer.getText(), + referencePathsOutput, + } + + function hasInternalAnnotation(range: CommentRange) { + let text = currentSourceFile.text; + let comment = text.substring(range.pos, range.end); + return comment.indexOf("@internal") >= 0; + } + + function stripInternal(node: Node) { + if (node) { + let leadingCommentRanges = getLeadingCommentRanges(currentSourceFile.text, node.pos); + if (forEach(leadingCommentRanges, hasInternalAnnotation)) { + return; + } + + emitNode(node); + } + } + + function createAndSetNewTextWriterWithSymbolWriter(): EmitTextWriterWithSymbolWriter { + let writer = createTextWriter(newLine); + writer.trackSymbol = trackSymbol; + writer.writeKeyword = writer.write; + writer.writeOperator = writer.write; + writer.writePunctuation = writer.write; + writer.writeSpace = writer.write; + writer.writeStringLiteral = writer.writeLiteral; + writer.writeParameter = writer.write; + writer.writeSymbol = writer.write; + setWriter(writer); + return writer; + } + + function setWriter(newWriter: EmitTextWriterWithSymbolWriter) { + writer = newWriter; + write = newWriter.write; + writeTextOfNode = newWriter.writeTextOfNode; + writeLine = newWriter.writeLine; + increaseIndent = newWriter.increaseIndent; + decreaseIndent = newWriter.decreaseIndent; + } + + function writeAsynchronousModuleElements(nodes: Node[]) { + let oldWriter = writer; + forEach(nodes, declaration => { + let nodeToCheck: Node; + if (declaration.kind === SyntaxKind.VariableDeclaration) { + nodeToCheck = declaration.parent.parent; + } else if (declaration.kind === SyntaxKind.NamedImports || declaration.kind === SyntaxKind.ImportSpecifier || declaration.kind === SyntaxKind.ImportClause) { + Debug.fail("We should be getting ImportDeclaration instead to write"); + } else { + nodeToCheck = declaration; + } + + let moduleElementEmitInfo = forEach(moduleElementDeclarationEmitInfo, declEmitInfo => declEmitInfo.node === nodeToCheck ? declEmitInfo : undefined); + if (!moduleElementEmitInfo && asynchronousSubModuleDeclarationEmitInfo) { + moduleElementEmitInfo = forEach(asynchronousSubModuleDeclarationEmitInfo, declEmitInfo => declEmitInfo.node === nodeToCheck ? declEmitInfo : undefined); + } + + // If the alias was marked as not visible when we saw its declaration, we would have saved the aliasEmitInfo, but if we haven't yet visited the alias declaration + // then we don't need to write it at this point. We will write it when we actually see its declaration + // Eg. + // export function bar(a: foo.Foo) { } + // import foo = require("foo"); + // Writing of function bar would mark alias declaration foo as visible but we haven't yet visited that declaration so do nothing, + // we would write alias foo declaration when we visit it since it would now be marked as visible + if (moduleElementEmitInfo) { + if (moduleElementEmitInfo.node.kind === SyntaxKind.ImportDeclaration) { + // we have to create asynchronous output only after we have collected complete information + // because it is possible to enable multiple bindings as asynchronously visible + moduleElementEmitInfo.isVisible = true; + } + else { + createAndSetNewTextWriterWithSymbolWriter(); + for (let declarationIndent = moduleElementEmitInfo.indent; declarationIndent; declarationIndent--) { + increaseIndent(); + } + + if (nodeToCheck.kind === SyntaxKind.ModuleDeclaration) { + Debug.assert(asynchronousSubModuleDeclarationEmitInfo === undefined); + asynchronousSubModuleDeclarationEmitInfo = []; + } + writeModuleElement(nodeToCheck); + if (nodeToCheck.kind === SyntaxKind.ModuleDeclaration) { + moduleElementEmitInfo.subModuleElementDeclarationEmitInfo = asynchronousSubModuleDeclarationEmitInfo; + asynchronousSubModuleDeclarationEmitInfo = undefined; + } + moduleElementEmitInfo.asynchronousOutput = writer.getText(); + } + } + }); + setWriter(oldWriter); + } + + function handleSymbolAccessibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) { + if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) { + // write the aliases + if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) { + writeAsynchronousModuleElements(symbolAccesibilityResult.aliasesToMakeVisible); + } + } + else { + // Report error + reportedDeclarationError = true; + let errorInfo = writer.getSymbolAccessibilityDiagnostic(symbolAccesibilityResult); + if (errorInfo) { + if (errorInfo.typeName) { + diagnostics.push(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode, + errorInfo.diagnosticMessage, + getSourceTextOfNodeFromSourceFile(currentSourceFile, errorInfo.typeName), + symbolAccesibilityResult.errorSymbolName, + symbolAccesibilityResult.errorModuleName)); + } + else { + diagnostics.push(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode, + errorInfo.diagnosticMessage, + symbolAccesibilityResult.errorSymbolName, + symbolAccesibilityResult.errorModuleName)); + } + } + } + } + + function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { + handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning)); + } + + function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, type: TypeNode, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) { + writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic; + write(": "); + if (type) { + // Write the type + emitType(type); + } + else { + resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); + } + } + + function writeReturnTypeAtSignature(signature: SignatureDeclaration, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) { + writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic; + write(": "); + if (signature.type) { + // Write the type + emitType(signature.type); + } + else { + resolver.writeReturnTypeOfSignatureDeclaration(signature, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); + } + } + + function emitLines(nodes: Node[]) { + for (let node of nodes) { + emit(node); + } + } + + function emitSeparatedList(nodes: Node[], separator: string, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) { + let currentWriterPos = writer.getTextPos(); + for (let node of nodes) { + if (!canEmitFn || canEmitFn(node)) { + if (currentWriterPos !== writer.getTextPos()) { + write(separator); + } + currentWriterPos = writer.getTextPos(); + eachNodeEmitFn(node); + } + } + } + + function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) { + emitSeparatedList(nodes, ", ", eachNodeEmitFn, canEmitFn); + } + + function writeJsDocComments(declaration: Node) { + if (declaration) { + let jsDocComments = getJsDocComments(declaration, currentSourceFile); + emitNewLineBeforeLeadingComments(currentSourceFile, writer, declaration, jsDocComments); + // jsDoc comments are emitted at /*leading comment1 */space/*leading comment*/space + emitComments(currentSourceFile, writer, jsDocComments, /*trailingSeparator*/ true, newLine, writeCommentRange); + } + } + + function emitTypeWithNewGetSymbolAccessibilityDiagnostic(type: TypeNode | EntityName, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) { + writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic; + emitType(type); + } + + function emitType(type: TypeNode | Identifier | QualifiedName) { + switch (type.kind) { + case SyntaxKind.AnyKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.SymbolKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.StringLiteral: + return writeTextOfNode(currentSourceFile, type); + case SyntaxKind.HeritageClauseElement: + return emitHeritageClauseElement(type); + case SyntaxKind.TypeReference: + return emitTypeReference(type); + case SyntaxKind.TypeQuery: + return emitTypeQuery(type); + case SyntaxKind.ArrayType: + return emitArrayType(type); + case SyntaxKind.TupleType: + return emitTupleType(type); + case SyntaxKind.UnionType: + return emitUnionType(type); + case SyntaxKind.ParenthesizedType: + return emitParenType(type); + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + return emitSignatureDeclarationWithJsDocComments(type); + case SyntaxKind.TypeLiteral: + return emitTypeLiteral(type); + case SyntaxKind.Identifier: + return emitEntityName(type); + case SyntaxKind.QualifiedName: + return emitEntityName(type); + } + + function emitEntityName(entityName: EntityName | PropertyAccessExpression) { + let visibilityResult = resolver.isEntityNameVisible(entityName, + // Aliases can be written asynchronously so use correct enclosing declaration + entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration ? entityName.parent : enclosingDeclaration); + + handleSymbolAccessibilityError(visibilityResult); + writeEntityName(entityName); + + function writeEntityName(entityName: EntityName | Expression) { + if (entityName.kind === SyntaxKind.Identifier) { + writeTextOfNode(currentSourceFile, entityName); + } + else { + let left = entityName.kind === SyntaxKind.QualifiedName ? (entityName).left : (entityName).expression; + let right = entityName.kind === SyntaxKind.QualifiedName ? (entityName).right : (entityName).name; + writeEntityName(left); + write("."); + writeTextOfNode(currentSourceFile, right); + } + } + } + + function emitHeritageClauseElement(node: HeritageClauseElement) { + if (isSupportedHeritageClauseElement(node)) { + Debug.assert(node.expression.kind === SyntaxKind.Identifier || node.expression.kind === SyntaxKind.PropertyAccessExpression); + emitEntityName(node.expression); + if (node.typeArguments) { + write("<"); + emitCommaList(node.typeArguments, emitType); + write(">"); + } + } + } + + function emitTypeReference(type: TypeReferenceNode) { + emitEntityName(type.typeName); + if (type.typeArguments) { + write("<"); + emitCommaList(type.typeArguments, emitType); + write(">"); + } + } + + function emitTypeQuery(type: TypeQueryNode) { + write("typeof "); + emitEntityName(type.exprName); + } + + function emitArrayType(type: ArrayTypeNode) { + emitType(type.elementType); + write("[]"); + } + + function emitTupleType(type: TupleTypeNode) { + write("["); + emitCommaList(type.elementTypes, emitType); + write("]"); + } + + function emitUnionType(type: UnionTypeNode) { + emitSeparatedList(type.types, " | ", emitType); + } + + function emitParenType(type: ParenthesizedTypeNode) { + write("("); + emitType(type.type); + write(")"); + } + + function emitTypeLiteral(type: TypeLiteralNode) { + write("{"); + if (type.members.length) { + writeLine(); + increaseIndent(); + // write members + emitLines(type.members); + decreaseIndent(); + } + write("}"); + } + } + + function emitSourceFile(node: SourceFile) { + currentSourceFile = node; + enclosingDeclaration = node; + emitLines(node.statements); + } + + // Return a temp variable name to be used in `export default` statements. + // The temp name will be of the form _default_counter. + // Note that export default is only allowed at most once in a module, so we + // do not need to keep track of created temp names. + function getExportDefaultTempVariableName(): string { + let baseName = "_default"; + if (!hasProperty(currentSourceFile.identifiers, baseName)) { + return baseName; + } + let count = 0; + while (true) { + let name = baseName + "_" + (++count); + if (!hasProperty(currentSourceFile.identifiers, name)) { + return name; + } + } + } + + function emitExportAssignment(node: ExportAssignment) { + if (node.expression.kind === SyntaxKind.Identifier) { + write(node.isExportEquals ? "export = " : "export default "); + writeTextOfNode(currentSourceFile, node.expression); + } + else { + // Expression + let tempVarName = getExportDefaultTempVariableName(); + write("declare var "); + write(tempVarName); + write(": "); + writer.getSymbolAccessibilityDiagnostic = getDefaultExportAccessibilityDiagnostic; + resolver.writeTypeOfExpression(node.expression, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); + write(";"); + writeLine(); + write(node.isExportEquals ? "export = " : "export default "); + write(tempVarName); + } + write(";"); + writeLine(); + + // Make all the declarations visible for the export name + if (node.expression.kind === SyntaxKind.Identifier) { + let nodes = resolver.collectLinkedAliases(node.expression); + + // write each of these declarations asynchronously + writeAsynchronousModuleElements(nodes); + } + + function getDefaultExportAccessibilityDiagnostic(diagnostic: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { + return { + diagnosticMessage: Diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0, + errorNode: node + }; + } + } + + function isModuleElementVisible(node: Declaration) { + return resolver.isDeclarationVisible(node); + } + + function emitModuleElement(node: Node, isModuleElementVisible: boolean) { + if (isModuleElementVisible) { + writeModuleElement(node); + } + // Import equals declaration in internal module can become visible as part of any emit so lets make sure we add these irrespective + else if (node.kind === SyntaxKind.ImportEqualsDeclaration || + (node.parent.kind === SyntaxKind.SourceFile && isExternalModule(currentSourceFile))) { + let isVisible: boolean; + if (asynchronousSubModuleDeclarationEmitInfo && node.parent.kind !== SyntaxKind.SourceFile) { + // Import declaration of another module that is visited async so lets put it in right spot + asynchronousSubModuleDeclarationEmitInfo.push({ + node, + outputPos: writer.getTextPos(), + indent: writer.getIndent(), + isVisible + }); + } + else { + if (node.kind === SyntaxKind.ImportDeclaration) { + let importDeclaration = node; + if (importDeclaration.importClause) { + isVisible = (importDeclaration.importClause.name && resolver.isDeclarationVisible(importDeclaration.importClause)) || + isVisibleNamedBinding(importDeclaration.importClause.namedBindings); + } + } + moduleElementDeclarationEmitInfo.push({ + node, + outputPos: writer.getTextPos(), + indent: writer.getIndent(), + isVisible + }); + } + } + } + + function writeModuleElement(node: Node) { + switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + return writeFunctionDeclaration(node); + case SyntaxKind.VariableStatement: + return writeVariableStatement(node); + case SyntaxKind.InterfaceDeclaration: + return writeInterfaceDeclaration(node); + case SyntaxKind.ClassDeclaration: + return writeClassDeclaration(node); + case SyntaxKind.TypeAliasDeclaration: + return writeTypeAliasDeclaration(node); + case SyntaxKind.EnumDeclaration: + return writeEnumDeclaration(node); + case SyntaxKind.ModuleDeclaration: + return writeModuleDeclaration(node); + case SyntaxKind.ImportEqualsDeclaration: + return writeImportEqualsDeclaration(node); + case SyntaxKind.ImportDeclaration: + return writeImportDeclaration(node); + default: + Debug.fail("Unknown symbol kind"); + } + } + + function emitModuleElementDeclarationFlags(node: Node) { + // If the node is parented in the current source file we need to emit export declare or just export + if (node.parent === currentSourceFile) { + // If the node is exported + if (node.flags & NodeFlags.Export) { + write("export "); + } + + if (node.flags & NodeFlags.Default) { + write("default "); + } + else if (node.kind !== SyntaxKind.InterfaceDeclaration) { + write("declare "); + } + } + } + + function emitClassMemberDeclarationFlags(node: Declaration) { + if (node.flags & NodeFlags.Private) { + write("private "); + } + else if (node.flags & NodeFlags.Protected) { + write("protected "); + } + + if (node.flags & NodeFlags.Static) { + write("static "); + } + } + + function writeImportEqualsDeclaration(node: ImportEqualsDeclaration) { + // note usage of writer. methods instead of aliases created, just to make sure we are using + // correct writer especially to handle asynchronous alias writing + emitJsDocComments(node); + if (node.flags & NodeFlags.Export) { + write("export "); + } + write("import "); + writeTextOfNode(currentSourceFile, node.name); + write(" = "); + if (isInternalModuleImportEqualsDeclaration(node)) { + emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.moduleReference, getImportEntityNameVisibilityError); + write(";"); + } + else { + write("require("); + writeTextOfNode(currentSourceFile, getExternalModuleImportEqualsDeclarationExpression(node)); + write(");"); + } + writer.writeLine(); + + function getImportEntityNameVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { + return { + diagnosticMessage: Diagnostics.Import_declaration_0_is_using_private_name_1, + errorNode: node, + typeName: node.name + }; + } + } + + function isVisibleNamedBinding(namedBindings: NamespaceImport | NamedImports): boolean { + if (namedBindings) { + if (namedBindings.kind === SyntaxKind.NamespaceImport) { + return resolver.isDeclarationVisible(namedBindings); + } + else { + return forEach((namedBindings).elements, namedImport => resolver.isDeclarationVisible(namedImport)); + } + } + } + + function writeImportDeclaration(node: ImportDeclaration) { + if (!node.importClause && !(node.flags & NodeFlags.Export)) { + // do not write non-exported import declarations that don't have import clauses + return; + } + emitJsDocComments(node); + if (node.flags & NodeFlags.Export) { + write("export "); + } + write("import "); + if (node.importClause) { + let currentWriterPos = writer.getTextPos(); + if (node.importClause.name && resolver.isDeclarationVisible(node.importClause)) { + writeTextOfNode(currentSourceFile, node.importClause.name); + } + if (node.importClause.namedBindings && isVisibleNamedBinding(node.importClause.namedBindings)) { + if (currentWriterPos !== writer.getTextPos()) { + // If the default binding was emitted, write the separated + write(", "); + } + if (node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + write("* as "); + writeTextOfNode(currentSourceFile, (node.importClause.namedBindings).name); + } + else { + write("{ "); + emitCommaList((node.importClause.namedBindings).elements, emitImportOrExportSpecifier, resolver.isDeclarationVisible); + write(" }"); + } + } + write(" from "); + } + writeTextOfNode(currentSourceFile, node.moduleSpecifier); + write(";"); + writer.writeLine(); + } + + function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) { + if (node.propertyName) { + writeTextOfNode(currentSourceFile, node.propertyName); + write(" as "); + } + writeTextOfNode(currentSourceFile, node.name); + } + + function emitExportSpecifier(node: ExportSpecifier) { + emitImportOrExportSpecifier(node); + + // Make all the declarations visible for the export name + let nodes = resolver.collectLinkedAliases(node.propertyName || node.name); + + // write each of these declarations asynchronously + writeAsynchronousModuleElements(nodes); + } + + function emitExportDeclaration(node: ExportDeclaration) { + emitJsDocComments(node); + write("export "); + if (node.exportClause) { + write("{ "); + emitCommaList(node.exportClause.elements, emitExportSpecifier); + write(" }"); + } + else { + write("*"); + } + if (node.moduleSpecifier) { + write(" from "); + writeTextOfNode(currentSourceFile, node.moduleSpecifier); + } + write(";"); + writer.writeLine(); + } + + function writeModuleDeclaration(node: ModuleDeclaration) { + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + write("module "); + writeTextOfNode(currentSourceFile, node.name); + while (node.body.kind !== SyntaxKind.ModuleBlock) { + node = node.body; + write("."); + writeTextOfNode(currentSourceFile, node.name); + } + let prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = node; + write(" {"); + writeLine(); + increaseIndent(); + emitLines((node.body).statements); + decreaseIndent(); + write("}"); + writeLine(); + enclosingDeclaration = prevEnclosingDeclaration; + } + + function writeTypeAliasDeclaration(node: TypeAliasDeclaration) { + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + write("type "); + writeTextOfNode(currentSourceFile, node.name); + write(" = "); + emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.type, getTypeAliasDeclarationVisibilityError); + write(";"); + writeLine(); + + function getTypeAliasDeclarationVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { + return { + diagnosticMessage: Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1, + errorNode: node.type, + typeName: node.name + }; + } + } + + function writeEnumDeclaration(node: EnumDeclaration) { + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + if (isConst(node)) { + write("const ") + } + write("enum "); + writeTextOfNode(currentSourceFile, node.name); + write(" {"); + writeLine(); + increaseIndent(); + emitLines(node.members); + decreaseIndent(); + write("}"); + writeLine(); + } + + function emitEnumMemberDeclaration(node: EnumMember) { + emitJsDocComments(node); + writeTextOfNode(currentSourceFile, node.name); + let enumMemberValue = resolver.getConstantValue(node); + if (enumMemberValue !== undefined) { + write(" = "); + write(enumMemberValue.toString()); + } + write(","); + writeLine(); + } + + function isPrivateMethodTypeParameter(node: TypeParameterDeclaration) { + return node.parent.kind === SyntaxKind.MethodDeclaration && (node.parent.flags & NodeFlags.Private); + } + + function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) { + function emitTypeParameter(node: TypeParameterDeclaration) { + increaseIndent(); + emitJsDocComments(node); + decreaseIndent(); + writeTextOfNode(currentSourceFile, node.name); + // If there is constraint present and this is not a type parameter of the private method emit the constraint + if (node.constraint && !isPrivateMethodTypeParameter(node)) { + write(" extends "); + if (node.parent.kind === SyntaxKind.FunctionType || + node.parent.kind === SyntaxKind.ConstructorType || + (node.parent.parent && node.parent.parent.kind === SyntaxKind.TypeLiteral)) { + Debug.assert(node.parent.kind === SyntaxKind.MethodDeclaration || + node.parent.kind === SyntaxKind.MethodSignature || + node.parent.kind === SyntaxKind.FunctionType || + node.parent.kind === SyntaxKind.ConstructorType || + node.parent.kind === SyntaxKind.CallSignature || + node.parent.kind === SyntaxKind.ConstructSignature); + emitType(node.constraint); + } + else { + emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.constraint, getTypeParameterConstraintVisibilityError); + } + } + + function getTypeParameterConstraintVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { + // Type parameter constraints are named by user so we should always be able to name it + let diagnosticMessage: DiagnosticMessage; + switch (node.parent.kind) { + case SyntaxKind.ClassDeclaration: + diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_class_has_or_is_using_private_name_1; + break; + + case SyntaxKind.InterfaceDeclaration: + diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1; + break; + + case SyntaxKind.ConstructSignature: + diagnosticMessage = Diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; + break; + + case SyntaxKind.CallSignature: + diagnosticMessage = Diagnostics.Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; + break; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + if (node.parent.flags & NodeFlags.Static) { + diagnosticMessage = Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; + } + else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) { + diagnosticMessage = Diagnostics.Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; + } + else { + diagnosticMessage = Diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; + } + break; + + case SyntaxKind.FunctionDeclaration: + diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_function_has_or_is_using_private_name_1; + break; + + default: + Debug.fail("This is unknown parent for type parameter: " + node.parent.kind); + } + + return { + diagnosticMessage, + errorNode: node, + typeName: node.name + }; + } + } + + if (typeParameters) { + write("<"); + emitCommaList(typeParameters, emitTypeParameter); + write(">"); + } + } + + function emitHeritageClause(typeReferences: HeritageClauseElement[], isImplementsList: boolean) { + if (typeReferences) { + write(isImplementsList ? " implements " : " extends "); + emitCommaList(typeReferences, emitTypeOfTypeReference); + } + + function emitTypeOfTypeReference(node: HeritageClauseElement) { + if (isSupportedHeritageClauseElement(node)) { + emitTypeWithNewGetSymbolAccessibilityDiagnostic(node, getHeritageClauseVisibilityError); + } + + function getHeritageClauseVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { + let diagnosticMessage: DiagnosticMessage; + // Heritage clause is written by user so it can always be named + if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) { + // Class or Interface implemented/extended is inaccessible + diagnosticMessage = isImplementsList ? + Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 : + Diagnostics.Extends_clause_of_exported_class_0_has_or_is_using_private_name_1; + } + else { + // interface is inaccessible + diagnosticMessage = Diagnostics.Extends_clause_of_exported_interface_0_has_or_is_using_private_name_1; + } + + return { + diagnosticMessage, + errorNode: node, + typeName: (node.parent.parent).name + }; + } + } + } + + function writeClassDeclaration(node: ClassDeclaration) { + function emitParameterProperties(constructorDeclaration: ConstructorDeclaration) { + if (constructorDeclaration) { + forEach(constructorDeclaration.parameters, param => { + if (param.flags & NodeFlags.AccessibilityModifier) { + emitPropertyDeclaration(param); + } + }); + } + } + + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + write("class "); + writeTextOfNode(currentSourceFile, node.name); + let prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = node; + emitTypeParameters(node.typeParameters); + let baseTypeNode = getClassExtendsHeritageClauseElement(node); + if (baseTypeNode) { + emitHeritageClause([baseTypeNode], /*isImplementsList*/ false); + } + emitHeritageClause(getClassImplementsHeritageClauseElements(node), /*isImplementsList*/ true); + write(" {"); + writeLine(); + increaseIndent(); + emitParameterProperties(getFirstConstructorWithBody(node)); + emitLines(node.members); + decreaseIndent(); + write("}"); + writeLine(); + enclosingDeclaration = prevEnclosingDeclaration; + } + + function writeInterfaceDeclaration(node: InterfaceDeclaration) { + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + write("interface "); + writeTextOfNode(currentSourceFile, node.name); + let prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = node; + emitTypeParameters(node.typeParameters); + emitHeritageClause(getInterfaceBaseTypeNodes(node), /*isImplementsList*/ false); + write(" {"); + writeLine(); + increaseIndent(); + emitLines(node.members); + decreaseIndent(); + write("}"); + writeLine(); + enclosingDeclaration = prevEnclosingDeclaration; + } + + function emitPropertyDeclaration(node: Declaration) { + if (hasDynamicName(node)) { + return; + } + + emitJsDocComments(node); + emitClassMemberDeclarationFlags(node); + emitVariableDeclaration(node); + write(";"); + writeLine(); + } + + function emitVariableDeclaration(node: VariableDeclaration) { + // If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted + // so there is no check needed to see if declaration is visible + if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) { + if (isBindingPattern(node.name)) { + emitBindingPattern(node.name); + } + else { + // If this node is a computed name, it can only be a symbol, because we've already skipped + // it if it's not a well known symbol. In that case, the text of the name will be exactly + // what we want, namely the name expression enclosed in brackets. + writeTextOfNode(currentSourceFile, node.name); + // If optional property emit ? + if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && hasQuestionToken(node)) { + write("?"); + } + if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) { + emitTypeOfVariableDeclarationFromTypeLiteral(node); + } + else if (!(node.flags & NodeFlags.Private)) { + writeTypeOfDeclaration(node, node.type, getVariableDeclarationTypeVisibilityError); + } + } + } + + function getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult: SymbolAccessiblityResult) { + if (node.kind === SyntaxKind.VariableDeclaration) { + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Exported_variable_0_has_or_is_using_private_name_1; + } + // This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit + else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) { + // TODO(jfreeman): Deal with computed properties in error reporting. + if (node.flags & NodeFlags.Static) { + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1; + } + else if (node.parent.kind === SyntaxKind.ClassDeclaration) { + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1; + } + else { + // Interfaces cannot have types that cannot be named + return symbolAccesibilityResult.errorModuleName ? + Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1; + } + } + } + + function getVariableDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { + let diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult); + return diagnosticMessage !== undefined ? { + diagnosticMessage, + errorNode: node, + typeName: node.name + } : undefined; + } + + function emitBindingPattern(bindingPattern: BindingPattern) { + // Only select non-omitted expression from the bindingPattern's elements. + // We have to do this to avoid emitting trailing commas. + // For example: + // original: var [, c,,] = [ 2,3,4] + // emitted: declare var c: number; // instead of declare var c:number, ; + let elements: Node[] = []; + for (let element of bindingPattern.elements) { + if (element.kind !== SyntaxKind.OmittedExpression){ + elements.push(element); + } + } + emitCommaList(elements, emitBindingElement); + } + + function emitBindingElement(bindingElement: BindingElement) { + function getBindingElementTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { + let diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult); + return diagnosticMessage !== undefined ? { + diagnosticMessage, + errorNode: bindingElement, + typeName: bindingElement.name + } : undefined; + } + + if (bindingElement.name) { + if (isBindingPattern(bindingElement.name)) { + emitBindingPattern(bindingElement.name); + } + else { + writeTextOfNode(currentSourceFile, bindingElement.name); + writeTypeOfDeclaration(bindingElement, /*type*/ undefined, getBindingElementTypeVisibilityError); + } + } + } + } + + function emitTypeOfVariableDeclarationFromTypeLiteral(node: VariableLikeDeclaration) { + // if this is property of type literal, + // or is parameter of method/call/construct/index signature of type literal + // emit only if type is specified + if (node.type) { + write(": "); + emitType(node.type); + } + } + + function isVariableStatementVisible(node: VariableStatement) { + return forEach(node.declarationList.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration)); + } + + function writeVariableStatement(node: VariableStatement) { + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + if (isLet(node.declarationList)) { + write("let "); + } + else if (isConst(node.declarationList)) { + write("const "); + } + else { + write("var "); + } + emitCommaList(node.declarationList.declarations, emitVariableDeclaration, resolver.isDeclarationVisible); + write(";"); + writeLine(); + } + + function emitAccessorDeclaration(node: AccessorDeclaration) { + if (hasDynamicName(node)) { + return; + } + + let accessors = getAllAccessorDeclarations((node.parent).members, node); + let accessorWithTypeAnnotation: AccessorDeclaration; + + if (node === accessors.firstAccessor) { + emitJsDocComments(accessors.getAccessor); + emitJsDocComments(accessors.setAccessor); + emitClassMemberDeclarationFlags(node); + writeTextOfNode(currentSourceFile, node.name); + if (!(node.flags & NodeFlags.Private)) { + accessorWithTypeAnnotation = node; + let type = getTypeAnnotationFromAccessor(node); + if (!type) { + // couldn't get type for the first accessor, try the another one + let anotherAccessor = node.kind === SyntaxKind.GetAccessor ? accessors.setAccessor : accessors.getAccessor; + type = getTypeAnnotationFromAccessor(anotherAccessor); + if (type) { + accessorWithTypeAnnotation = anotherAccessor; + } + } + writeTypeOfDeclaration(node, type, getAccessorDeclarationTypeVisibilityError); + } + write(";"); + writeLine(); + } + + function getTypeAnnotationFromAccessor(accessor: AccessorDeclaration): TypeNode { + if (accessor) { + return accessor.kind === SyntaxKind.GetAccessor + ? accessor.type // Getter - return type + : accessor.parameters.length > 0 + ? accessor.parameters[0].type // Setter parameter type + : undefined; + } + } + + function getAccessorDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { + let diagnosticMessage: DiagnosticMessage; + if (accessorWithTypeAnnotation.kind === SyntaxKind.SetAccessor) { + // Setters have to have type named and cannot infer it so, the type should always be named + if (accessorWithTypeAnnotation.parent.flags & NodeFlags.Static) { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1; + } + else { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_name_1; + } + return { + diagnosticMessage, + errorNode: accessorWithTypeAnnotation.parameters[0], + // TODO(jfreeman): Investigate why we are passing node.name instead of node.parameters[0].name + typeName: accessorWithTypeAnnotation.name + }; + } + else { + if (accessorWithTypeAnnotation.flags & NodeFlags.Static) { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : + Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 : + Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_name_0; + } + else { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : + Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 : + Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_name_0; + } + return { + diagnosticMessage, + errorNode: accessorWithTypeAnnotation.name, + typeName: undefined + }; + } + } + } + + function writeFunctionDeclaration(node: FunctionLikeDeclaration) { + if (hasDynamicName(node)) { + return; + } + + // If we are emitting Method/Constructor it isn't moduleElement and hence already determined to be emitting + // so no need to verify if the declaration is visible + if (!resolver.isImplementationOfOverload(node)) { + emitJsDocComments(node); + if (node.kind === SyntaxKind.FunctionDeclaration) { + emitModuleElementDeclarationFlags(node); + } + else if (node.kind === SyntaxKind.MethodDeclaration) { + emitClassMemberDeclarationFlags(node); + } + if (node.kind === SyntaxKind.FunctionDeclaration) { + write("function "); + writeTextOfNode(currentSourceFile, node.name); + } + else if (node.kind === SyntaxKind.Constructor) { + write("constructor"); + } + else { + writeTextOfNode(currentSourceFile, node.name); + if (hasQuestionToken(node)) { + write("?"); + } + } + emitSignatureDeclaration(node); + } + } + + function emitSignatureDeclarationWithJsDocComments(node: SignatureDeclaration) { + emitJsDocComments(node); + emitSignatureDeclaration(node); + } + + function emitSignatureDeclaration(node: SignatureDeclaration) { + // Construct signature or constructor type write new Signature + if (node.kind === SyntaxKind.ConstructSignature || node.kind === SyntaxKind.ConstructorType) { + write("new "); + } + emitTypeParameters(node.typeParameters); + if (node.kind === SyntaxKind.IndexSignature) { + write("["); + } + else { + write("("); + } + + let prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = node; + + // Parameters + emitCommaList(node.parameters, emitParameterDeclaration); + + if (node.kind === SyntaxKind.IndexSignature) { + write("]"); + } + else { + write(")"); + } + + // If this is not a constructor and is not private, emit the return type + let isFunctionTypeOrConstructorType = node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.ConstructorType; + if (isFunctionTypeOrConstructorType || node.parent.kind === SyntaxKind.TypeLiteral) { + // Emit type literal signature return type only if specified + if (node.type) { + write(isFunctionTypeOrConstructorType ? " => " : ": "); + emitType(node.type); + } + } + else if (node.kind !== SyntaxKind.Constructor && !(node.flags & NodeFlags.Private)) { + writeReturnTypeAtSignature(node, getReturnTypeVisibilityError); + } + + enclosingDeclaration = prevEnclosingDeclaration; + + if (!isFunctionTypeOrConstructorType) { + write(";"); + writeLine(); + } + + function getReturnTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { + let diagnosticMessage: DiagnosticMessage; + switch (node.kind) { + case SyntaxKind.ConstructSignature: + // Interfaces cannot have return types that cannot be named + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : + Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0; + break; + + case SyntaxKind.CallSignature: + // Interfaces cannot have return types that cannot be named + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : + Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0; + break; + + case SyntaxKind.IndexSignature: + // Interfaces cannot have return types that cannot be named + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : + Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0; + break; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + if (node.flags & NodeFlags.Static) { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : + Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 : + Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0; + } + else if (node.parent.kind === SyntaxKind.ClassDeclaration) { + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : + Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 : + Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0; + } + else { + // Interfaces cannot have return types that cannot be named + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : + Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0; + } + break; + + case SyntaxKind.FunctionDeclaration: + diagnosticMessage = symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : + Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1 : + Diagnostics.Return_type_of_exported_function_has_or_is_using_private_name_0; + break; + + default: + Debug.fail("This is unknown kind for signature: " + node.kind); + } + + return { + diagnosticMessage, + errorNode: node.name || node, + }; + } + } + + function emitParameterDeclaration(node: ParameterDeclaration) { + increaseIndent(); + emitJsDocComments(node); + if (node.dotDotDotToken) { + write("..."); + } + if (isBindingPattern(node.name)) { + // For bindingPattern, we can't simply writeTextOfNode from the source file + // because we want to omit the initializer and using writeTextOfNode will result in initializer get emitted. + // Therefore, we will have to recursively emit each element in the bindingPattern. + emitBindingPattern(node.name); + } + else { + writeTextOfNode(currentSourceFile, node.name); + } + if (node.initializer || hasQuestionToken(node)) { + write("?"); + } + decreaseIndent(); + + if (node.parent.kind === SyntaxKind.FunctionType || + node.parent.kind === SyntaxKind.ConstructorType || + node.parent.parent.kind === SyntaxKind.TypeLiteral) { + emitTypeOfVariableDeclarationFromTypeLiteral(node); + } + else if (!(node.parent.flags & NodeFlags.Private)) { + writeTypeOfDeclaration(node, node.type, getParameterDeclarationTypeVisibilityError); + } + + function getParameterDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { + let diagnosticMessage: DiagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult); + return diagnosticMessage !== undefined ? { + diagnosticMessage, + errorNode: node, + typeName: node.name + } : undefined; + } + + function getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult: SymbolAccessiblityResult): DiagnosticMessage { + switch (node.parent.kind) { + case SyntaxKind.Constructor: + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1; + + case SyntaxKind.ConstructSignature: + // Interfaces cannot have parameter types that cannot be named + return symbolAccesibilityResult.errorModuleName ? + Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; + + case SyntaxKind.CallSignature: + // Interfaces cannot have parameter types that cannot be named + return symbolAccesibilityResult.errorModuleName ? + Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + if (node.parent.flags & NodeFlags.Static) { + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; + } + else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) { + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; + } + else { + // Interfaces cannot have parameter types that cannot be named + return symbolAccesibilityResult.errorModuleName ? + Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; + } + + case SyntaxKind.FunctionDeclaration: + return symbolAccesibilityResult.errorModuleName ? + symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? + Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : + Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1; + + default: + Debug.fail("This is unknown parent for parameter: " + node.parent.kind); + } + } + + function emitBindingPattern(bindingPattern: BindingPattern) { + // We have to explicitly emit square bracket and bracket because these tokens are not store inside the node. + if (bindingPattern.kind === SyntaxKind.ObjectBindingPattern) { + write("{"); + emitCommaList(bindingPattern.elements, emitBindingElement); + write("}"); + } + else if (bindingPattern.kind === SyntaxKind.ArrayBindingPattern) { + write("["); + let elements = bindingPattern.elements; + emitCommaList(elements, emitBindingElement); + if (elements && elements.hasTrailingComma) { + write(", "); + } + write("]"); + } + } + + function emitBindingElement(bindingElement: BindingElement) { + function getBindingElementTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { + let diagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult); + return diagnosticMessage !== undefined ? { + diagnosticMessage, + errorNode: bindingElement, + typeName: bindingElement.name + } : undefined; + } + + if (bindingElement.kind === SyntaxKind.OmittedExpression) { + // If bindingElement is an omittedExpression (i.e. containing elision), + // we will emit blank space (although this may differ from users' original code, + // it allows emitSeparatedList to write separator appropriately) + // Example: + // original: function foo([, x, ,]) {} + // emit : function foo([ , x, , ]) {} + write(" "); + } + else if (bindingElement.kind === SyntaxKind.BindingElement) { + if (bindingElement.propertyName) { + // bindingElement has propertyName property in the following case: + // { y: [a,b,c] ...} -> bindingPattern will have a property called propertyName for "y" + // We have to explicitly emit the propertyName before descending into its binding elements. + // Example: + // original: function foo({y: [a,b,c]}) {} + // emit : declare function foo({y: [a, b, c]}: { y: [any, any, any] }) void; + writeTextOfNode(currentSourceFile, bindingElement.propertyName); + write(": "); + + // If bindingElement has propertyName property, then its name must be another bindingPattern of SyntaxKind.ObjectBindingPattern + emitBindingPattern(bindingElement.name); + } + else if (bindingElement.name) { + if (isBindingPattern(bindingElement.name)) { + // If it is a nested binding pattern, we will recursively descend into each element and emit each one separately. + // In the case of rest element, we will omit rest element. + // Example: + // original: function foo([a, [[b]], c] = [1,[["string"]], 3]) {} + // emit : declare function foo([a, [[b]], c]: [number, [[string]], number]): void; + // original with rest: function foo([a, ...c]) {} + // emit : declare function foo([a, ...c]): void; + emitBindingPattern(bindingElement.name); + } + else { + Debug.assert(bindingElement.name.kind === SyntaxKind.Identifier); + // If the node is just an identifier, we will simply emit the text associated with the node's name + // Example: + // original: function foo({y = 10, x}) {} + // emit : declare function foo({y, x}: {number, any}): void; + if (bindingElement.dotDotDotToken) { + write("..."); + } + writeTextOfNode(currentSourceFile, bindingElement.name); + } + } + } + } + } + + function emitNode(node: Node) { + switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.EnumDeclaration: + return emitModuleElement(node, isModuleElementVisible(node)); + case SyntaxKind.VariableStatement: + return emitModuleElement(node, isVariableStatementVisible(node)); + case SyntaxKind.ImportDeclaration: + // Import declaration without import clause is visible, otherwise it is not visible + return emitModuleElement(node, /*isModuleElementVisible*/!(node).importClause); + case SyntaxKind.ExportDeclaration: + return emitExportDeclaration(node); + case SyntaxKind.Constructor: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + return writeFunctionDeclaration(node); + case SyntaxKind.ConstructSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.IndexSignature: + return emitSignatureDeclarationWithJsDocComments(node); + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return emitAccessorDeclaration(node); + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + return emitPropertyDeclaration(node); + case SyntaxKind.EnumMember: + return emitEnumMemberDeclaration(node); + case SyntaxKind.ExportAssignment: + return emitExportAssignment(node); + case SyntaxKind.SourceFile: + return emitSourceFile(node); + } + } + + function writeReferencePath(referencedFile: SourceFile) { + let declFileName = referencedFile.flags & NodeFlags.DeclarationFile + ? referencedFile.fileName // Declaration file, use declaration file name + : shouldEmitToOwnFile(referencedFile, compilerOptions) + ? getOwnEmitOutputFilePath(referencedFile, host, ".d.ts") // Own output file so get the .d.ts file + : removeFileExtension(compilerOptions.out) + ".d.ts";// Global out file + + declFileName = getRelativePathToDirectoryOrUrl( + getDirectoryPath(normalizeSlashes(jsFilePath)), + declFileName, + host.getCurrentDirectory(), + host.getCanonicalFileName, + /*isAbsolutePathAnUrl*/ false); + + referencePathsOutput += "/// " + newLine; + } + } + + /* @internal */ + export function writeDeclarationFile(jsFilePath: string, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[]) { + let emitDeclarationResult = emitDeclarations(host, resolver, diagnostics, jsFilePath, sourceFile); + // TODO(shkamat): Should we not write any declaration file if any of them can produce error, + // or should we just not write this file like we are doing now + if (!emitDeclarationResult.reportedDeclarationError) { + let declarationOutput = emitDeclarationResult.referencePathsOutput + + getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo); + writeFile(host, diagnostics, removeFileExtension(jsFilePath) + ".d.ts", declarationOutput, host.getCompilerOptions().emitBOM); + } + + function getDeclarationOutput(synchronousDeclarationOutput: string, moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[]) { + let appliedSyncOutputPos = 0; + let declarationOutput = ""; + // apply asynchronous additions to the synchronous output + forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => { + if (aliasEmitInfo.asynchronousOutput) { + declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos, aliasEmitInfo.outputPos); + declarationOutput += getDeclarationOutput(aliasEmitInfo.asynchronousOutput, aliasEmitInfo.subModuleElementDeclarationEmitInfo); + appliedSyncOutputPos = aliasEmitInfo.outputPos; + } + }); + declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos); + return declarationOutput; + } + } +} diff --git a/lib/typescript/compiler/diagnosticInformationMap.generated.ts b/lib/typescript/compiler/diagnosticInformationMap.generated.ts new file mode 100644 index 000000000..20ffe2628 --- /dev/null +++ b/lib/typescript/compiler/diagnosticInformationMap.generated.ts @@ -0,0 +1,542 @@ +// +/// +/* @internal */ +module ts { + export var Diagnostics = { + Unterminated_string_literal: { code: 1002, category: DiagnosticCategory.Error, key: "Unterminated string literal." }, + Identifier_expected: { code: 1003, category: DiagnosticCategory.Error, key: "Identifier expected." }, + _0_expected: { code: 1005, category: DiagnosticCategory.Error, key: "'{0}' expected." }, + A_file_cannot_have_a_reference_to_itself: { code: 1006, category: DiagnosticCategory.Error, key: "A file cannot have a reference to itself." }, + Trailing_comma_not_allowed: { code: 1009, category: DiagnosticCategory.Error, key: "Trailing comma not allowed." }, + Asterisk_Slash_expected: { code: 1010, category: DiagnosticCategory.Error, key: "'*/' expected." }, + Unexpected_token: { code: 1012, category: DiagnosticCategory.Error, key: "Unexpected token." }, + A_rest_parameter_must_be_last_in_a_parameter_list: { code: 1014, category: DiagnosticCategory.Error, key: "A rest parameter must be last in a parameter list." }, + Parameter_cannot_have_question_mark_and_initializer: { code: 1015, category: DiagnosticCategory.Error, key: "Parameter cannot have question mark and initializer." }, + A_required_parameter_cannot_follow_an_optional_parameter: { code: 1016, category: DiagnosticCategory.Error, key: "A required parameter cannot follow an optional parameter." }, + An_index_signature_cannot_have_a_rest_parameter: { code: 1017, category: DiagnosticCategory.Error, key: "An index signature cannot have a rest parameter." }, + An_index_signature_parameter_cannot_have_an_accessibility_modifier: { code: 1018, category: DiagnosticCategory.Error, key: "An index signature parameter cannot have an accessibility modifier." }, + An_index_signature_parameter_cannot_have_a_question_mark: { code: 1019, category: DiagnosticCategory.Error, key: "An index signature parameter cannot have a question mark." }, + An_index_signature_parameter_cannot_have_an_initializer: { code: 1020, category: DiagnosticCategory.Error, key: "An index signature parameter cannot have an initializer." }, + An_index_signature_must_have_a_type_annotation: { code: 1021, category: DiagnosticCategory.Error, key: "An index signature must have a type annotation." }, + An_index_signature_parameter_must_have_a_type_annotation: { code: 1022, category: DiagnosticCategory.Error, key: "An index signature parameter must have a type annotation." }, + An_index_signature_parameter_type_must_be_string_or_number: { code: 1023, category: DiagnosticCategory.Error, key: "An index signature parameter type must be 'string' or 'number'." }, + A_class_or_interface_declaration_can_only_have_one_extends_clause: { code: 1024, category: DiagnosticCategory.Error, key: "A class or interface declaration can only have one 'extends' clause." }, + An_extends_clause_must_precede_an_implements_clause: { code: 1025, category: DiagnosticCategory.Error, key: "An 'extends' clause must precede an 'implements' clause." }, + A_class_can_only_extend_a_single_class: { code: 1026, category: DiagnosticCategory.Error, key: "A class can only extend a single class." }, + A_class_declaration_can_only_have_one_implements_clause: { code: 1027, category: DiagnosticCategory.Error, key: "A class declaration can only have one 'implements' clause." }, + Accessibility_modifier_already_seen: { code: 1028, category: DiagnosticCategory.Error, key: "Accessibility modifier already seen." }, + _0_modifier_must_precede_1_modifier: { code: 1029, category: DiagnosticCategory.Error, key: "'{0}' modifier must precede '{1}' modifier." }, + _0_modifier_already_seen: { code: 1030, category: DiagnosticCategory.Error, key: "'{0}' modifier already seen." }, + _0_modifier_cannot_appear_on_a_class_element: { code: 1031, category: DiagnosticCategory.Error, key: "'{0}' modifier cannot appear on a class element." }, + An_interface_declaration_cannot_have_an_implements_clause: { code: 1032, category: DiagnosticCategory.Error, key: "An interface declaration cannot have an 'implements' clause." }, + super_must_be_followed_by_an_argument_list_or_member_access: { code: 1034, category: DiagnosticCategory.Error, key: "'super' must be followed by an argument list or member access." }, + Only_ambient_modules_can_use_quoted_names: { code: 1035, category: DiagnosticCategory.Error, key: "Only ambient modules can use quoted names." }, + Statements_are_not_allowed_in_ambient_contexts: { code: 1036, category: DiagnosticCategory.Error, key: "Statements are not allowed in ambient contexts." }, + A_declare_modifier_cannot_be_used_in_an_already_ambient_context: { code: 1038, category: DiagnosticCategory.Error, key: "A 'declare' modifier cannot be used in an already ambient context." }, + Initializers_are_not_allowed_in_ambient_contexts: { code: 1039, category: DiagnosticCategory.Error, key: "Initializers are not allowed in ambient contexts." }, + _0_modifier_cannot_appear_on_a_module_element: { code: 1044, category: DiagnosticCategory.Error, key: "'{0}' modifier cannot appear on a module element." }, + A_declare_modifier_cannot_be_used_with_an_interface_declaration: { code: 1045, category: DiagnosticCategory.Error, key: "A 'declare' modifier cannot be used with an interface declaration." }, + A_declare_modifier_is_required_for_a_top_level_declaration_in_a_d_ts_file: { code: 1046, category: DiagnosticCategory.Error, key: "A 'declare' modifier is required for a top level declaration in a .d.ts file." }, + A_rest_parameter_cannot_be_optional: { code: 1047, category: DiagnosticCategory.Error, key: "A rest parameter cannot be optional." }, + A_rest_parameter_cannot_have_an_initializer: { code: 1048, category: DiagnosticCategory.Error, key: "A rest parameter cannot have an initializer." }, + A_set_accessor_must_have_exactly_one_parameter: { code: 1049, category: DiagnosticCategory.Error, key: "A 'set' accessor must have exactly one parameter." }, + A_set_accessor_cannot_have_an_optional_parameter: { code: 1051, category: DiagnosticCategory.Error, key: "A 'set' accessor cannot have an optional parameter." }, + A_set_accessor_parameter_cannot_have_an_initializer: { code: 1052, category: DiagnosticCategory.Error, key: "A 'set' accessor parameter cannot have an initializer." }, + A_set_accessor_cannot_have_rest_parameter: { code: 1053, category: DiagnosticCategory.Error, key: "A 'set' accessor cannot have rest parameter." }, + A_get_accessor_cannot_have_parameters: { code: 1054, category: DiagnosticCategory.Error, key: "A 'get' accessor cannot have parameters." }, + Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher: { code: 1056, category: DiagnosticCategory.Error, key: "Accessors are only available when targeting ECMAScript 5 and higher." }, + Enum_member_must_have_initializer: { code: 1061, category: DiagnosticCategory.Error, key: "Enum member must have initializer." }, + An_export_assignment_cannot_be_used_in_an_internal_module: { code: 1063, category: DiagnosticCategory.Error, key: "An export assignment cannot be used in an internal module." }, + Ambient_enum_elements_can_only_have_integer_literal_initializers: { code: 1066, category: DiagnosticCategory.Error, key: "Ambient enum elements can only have integer literal initializers." }, + Unexpected_token_A_constructor_method_accessor_or_property_was_expected: { code: 1068, category: DiagnosticCategory.Error, key: "Unexpected token. A constructor, method, accessor, or property was expected." }, + A_declare_modifier_cannot_be_used_with_an_import_declaration: { code: 1079, category: DiagnosticCategory.Error, key: "A 'declare' modifier cannot be used with an import declaration." }, + Invalid_reference_directive_syntax: { code: 1084, category: DiagnosticCategory.Error, key: "Invalid 'reference' directive syntax." }, + Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher: { code: 1085, category: DiagnosticCategory.Error, key: "Octal literals are not available when targeting ECMAScript 5 and higher." }, + An_accessor_cannot_be_declared_in_an_ambient_context: { code: 1086, category: DiagnosticCategory.Error, key: "An accessor cannot be declared in an ambient context." }, + _0_modifier_cannot_appear_on_a_constructor_declaration: { code: 1089, category: DiagnosticCategory.Error, key: "'{0}' modifier cannot appear on a constructor declaration." }, + _0_modifier_cannot_appear_on_a_parameter: { code: 1090, category: DiagnosticCategory.Error, key: "'{0}' modifier cannot appear on a parameter." }, + Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement: { code: 1091, category: DiagnosticCategory.Error, key: "Only a single variable declaration is allowed in a 'for...in' statement." }, + Type_parameters_cannot_appear_on_a_constructor_declaration: { code: 1092, category: DiagnosticCategory.Error, key: "Type parameters cannot appear on a constructor declaration." }, + Type_annotation_cannot_appear_on_a_constructor_declaration: { code: 1093, category: DiagnosticCategory.Error, key: "Type annotation cannot appear on a constructor declaration." }, + An_accessor_cannot_have_type_parameters: { code: 1094, category: DiagnosticCategory.Error, key: "An accessor cannot have type parameters." }, + A_set_accessor_cannot_have_a_return_type_annotation: { code: 1095, category: DiagnosticCategory.Error, key: "A 'set' accessor cannot have a return type annotation." }, + An_index_signature_must_have_exactly_one_parameter: { code: 1096, category: DiagnosticCategory.Error, key: "An index signature must have exactly one parameter." }, + _0_list_cannot_be_empty: { code: 1097, category: DiagnosticCategory.Error, key: "'{0}' list cannot be empty." }, + Type_parameter_list_cannot_be_empty: { code: 1098, category: DiagnosticCategory.Error, key: "Type parameter list cannot be empty." }, + Type_argument_list_cannot_be_empty: { code: 1099, category: DiagnosticCategory.Error, key: "Type argument list cannot be empty." }, + Invalid_use_of_0_in_strict_mode: { code: 1100, category: DiagnosticCategory.Error, key: "Invalid use of '{0}' in strict mode." }, + with_statements_are_not_allowed_in_strict_mode: { code: 1101, category: DiagnosticCategory.Error, key: "'with' statements are not allowed in strict mode." }, + delete_cannot_be_called_on_an_identifier_in_strict_mode: { code: 1102, category: DiagnosticCategory.Error, key: "'delete' cannot be called on an identifier in strict mode." }, + A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement: { code: 1104, category: DiagnosticCategory.Error, key: "A 'continue' statement can only be used within an enclosing iteration statement." }, + A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement: { code: 1105, category: DiagnosticCategory.Error, key: "A 'break' statement can only be used within an enclosing iteration or switch statement." }, + Jump_target_cannot_cross_function_boundary: { code: 1107, category: DiagnosticCategory.Error, key: "Jump target cannot cross function boundary." }, + A_return_statement_can_only_be_used_within_a_function_body: { code: 1108, category: DiagnosticCategory.Error, key: "A 'return' statement can only be used within a function body." }, + Expression_expected: { code: 1109, category: DiagnosticCategory.Error, key: "Expression expected." }, + Type_expected: { code: 1110, category: DiagnosticCategory.Error, key: "Type expected." }, + A_class_member_cannot_be_declared_optional: { code: 1112, category: DiagnosticCategory.Error, key: "A class member cannot be declared optional." }, + A_default_clause_cannot_appear_more_than_once_in_a_switch_statement: { code: 1113, category: DiagnosticCategory.Error, key: "A 'default' clause cannot appear more than once in a 'switch' statement." }, + Duplicate_label_0: { code: 1114, category: DiagnosticCategory.Error, key: "Duplicate label '{0}'" }, + A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement: { code: 1115, category: DiagnosticCategory.Error, key: "A 'continue' statement can only jump to a label of an enclosing iteration statement." }, + A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement: { code: 1116, category: DiagnosticCategory.Error, key: "A 'break' statement can only jump to a label of an enclosing statement." }, + An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode: { code: 1117, category: DiagnosticCategory.Error, key: "An object literal cannot have multiple properties with the same name in strict mode." }, + An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name: { code: 1118, category: DiagnosticCategory.Error, key: "An object literal cannot have multiple get/set accessors with the same name." }, + An_object_literal_cannot_have_property_and_accessor_with_the_same_name: { code: 1119, category: DiagnosticCategory.Error, key: "An object literal cannot have property and accessor with the same name." }, + An_export_assignment_cannot_have_modifiers: { code: 1120, category: DiagnosticCategory.Error, key: "An export assignment cannot have modifiers." }, + Octal_literals_are_not_allowed_in_strict_mode: { code: 1121, category: DiagnosticCategory.Error, key: "Octal literals are not allowed in strict mode." }, + A_tuple_type_element_list_cannot_be_empty: { code: 1122, category: DiagnosticCategory.Error, key: "A tuple type element list cannot be empty." }, + Variable_declaration_list_cannot_be_empty: { code: 1123, category: DiagnosticCategory.Error, key: "Variable declaration list cannot be empty." }, + Digit_expected: { code: 1124, category: DiagnosticCategory.Error, key: "Digit expected." }, + Hexadecimal_digit_expected: { code: 1125, category: DiagnosticCategory.Error, key: "Hexadecimal digit expected." }, + Unexpected_end_of_text: { code: 1126, category: DiagnosticCategory.Error, key: "Unexpected end of text." }, + Invalid_character: { code: 1127, category: DiagnosticCategory.Error, key: "Invalid character." }, + Declaration_or_statement_expected: { code: 1128, category: DiagnosticCategory.Error, key: "Declaration or statement expected." }, + Statement_expected: { code: 1129, category: DiagnosticCategory.Error, key: "Statement expected." }, + case_or_default_expected: { code: 1130, category: DiagnosticCategory.Error, key: "'case' or 'default' expected." }, + Property_or_signature_expected: { code: 1131, category: DiagnosticCategory.Error, key: "Property or signature expected." }, + Enum_member_expected: { code: 1132, category: DiagnosticCategory.Error, key: "Enum member expected." }, + Type_reference_expected: { code: 1133, category: DiagnosticCategory.Error, key: "Type reference expected." }, + Variable_declaration_expected: { code: 1134, category: DiagnosticCategory.Error, key: "Variable declaration expected." }, + Argument_expression_expected: { code: 1135, category: DiagnosticCategory.Error, key: "Argument expression expected." }, + Property_assignment_expected: { code: 1136, category: DiagnosticCategory.Error, key: "Property assignment expected." }, + Expression_or_comma_expected: { code: 1137, category: DiagnosticCategory.Error, key: "Expression or comma expected." }, + Parameter_declaration_expected: { code: 1138, category: DiagnosticCategory.Error, key: "Parameter declaration expected." }, + Type_parameter_declaration_expected: { code: 1139, category: DiagnosticCategory.Error, key: "Type parameter declaration expected." }, + Type_argument_expected: { code: 1140, category: DiagnosticCategory.Error, key: "Type argument expected." }, + String_literal_expected: { code: 1141, category: DiagnosticCategory.Error, key: "String literal expected." }, + Line_break_not_permitted_here: { code: 1142, category: DiagnosticCategory.Error, key: "Line break not permitted here." }, + or_expected: { code: 1144, category: DiagnosticCategory.Error, key: "'{' or ';' expected." }, + Modifiers_not_permitted_on_index_signature_members: { code: 1145, category: DiagnosticCategory.Error, key: "Modifiers not permitted on index signature members." }, + Declaration_expected: { code: 1146, category: DiagnosticCategory.Error, key: "Declaration expected." }, + Import_declarations_in_an_internal_module_cannot_reference_an_external_module: { code: 1147, category: DiagnosticCategory.Error, key: "Import declarations in an internal module cannot reference an external module." }, + Cannot_compile_external_modules_unless_the_module_flag_is_provided: { code: 1148, category: DiagnosticCategory.Error, key: "Cannot compile external modules unless the '--module' flag is provided." }, + File_name_0_differs_from_already_included_file_name_1_only_in_casing: { code: 1149, category: DiagnosticCategory.Error, key: "File name '{0}' differs from already included file name '{1}' only in casing" }, + new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 1150, category: DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array()' instead." }, + var_let_or_const_expected: { code: 1152, category: DiagnosticCategory.Error, key: "'var', 'let' or 'const' expected." }, + let_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1153, category: DiagnosticCategory.Error, key: "'let' declarations are only available when targeting ECMAScript 6 and higher." }, + const_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1154, category: DiagnosticCategory.Error, key: "'const' declarations are only available when targeting ECMAScript 6 and higher." }, + const_declarations_must_be_initialized: { code: 1155, category: DiagnosticCategory.Error, key: "'const' declarations must be initialized" }, + const_declarations_can_only_be_declared_inside_a_block: { code: 1156, category: DiagnosticCategory.Error, key: "'const' declarations can only be declared inside a block." }, + let_declarations_can_only_be_declared_inside_a_block: { code: 1157, category: DiagnosticCategory.Error, key: "'let' declarations can only be declared inside a block." }, + Unterminated_template_literal: { code: 1160, category: DiagnosticCategory.Error, key: "Unterminated template literal." }, + Unterminated_regular_expression_literal: { code: 1161, category: DiagnosticCategory.Error, key: "Unterminated regular expression literal." }, + An_object_member_cannot_be_declared_optional: { code: 1162, category: DiagnosticCategory.Error, key: "An object member cannot be declared optional." }, + yield_expression_must_be_contained_within_a_generator_declaration: { code: 1163, category: DiagnosticCategory.Error, key: "'yield' expression must be contained_within a generator declaration." }, + Computed_property_names_are_not_allowed_in_enums: { code: 1164, category: DiagnosticCategory.Error, key: "Computed property names are not allowed in enums." }, + A_computed_property_name_in_an_ambient_context_must_directly_refer_to_a_built_in_symbol: { code: 1165, category: DiagnosticCategory.Error, key: "A computed property name in an ambient context must directly refer to a built-in symbol." }, + A_computed_property_name_in_a_class_property_declaration_must_directly_refer_to_a_built_in_symbol: { code: 1166, category: DiagnosticCategory.Error, key: "A computed property name in a class property declaration must directly refer to a built-in symbol." }, + Computed_property_names_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1167, category: DiagnosticCategory.Error, key: "Computed property names are only available when targeting ECMAScript 6 and higher." }, + A_computed_property_name_in_a_method_overload_must_directly_refer_to_a_built_in_symbol: { code: 1168, category: DiagnosticCategory.Error, key: "A computed property name in a method overload must directly refer to a built-in symbol." }, + A_computed_property_name_in_an_interface_must_directly_refer_to_a_built_in_symbol: { code: 1169, category: DiagnosticCategory.Error, key: "A computed property name in an interface must directly refer to a built-in symbol." }, + A_computed_property_name_in_a_type_literal_must_directly_refer_to_a_built_in_symbol: { code: 1170, category: DiagnosticCategory.Error, key: "A computed property name in a type literal must directly refer to a built-in symbol." }, + A_comma_expression_is_not_allowed_in_a_computed_property_name: { code: 1171, category: DiagnosticCategory.Error, key: "A comma expression is not allowed in a computed property name." }, + extends_clause_already_seen: { code: 1172, category: DiagnosticCategory.Error, key: "'extends' clause already seen." }, + extends_clause_must_precede_implements_clause: { code: 1173, category: DiagnosticCategory.Error, key: "'extends' clause must precede 'implements' clause." }, + Classes_can_only_extend_a_single_class: { code: 1174, category: DiagnosticCategory.Error, key: "Classes can only extend a single class." }, + implements_clause_already_seen: { code: 1175, category: DiagnosticCategory.Error, key: "'implements' clause already seen." }, + Interface_declaration_cannot_have_implements_clause: { code: 1176, category: DiagnosticCategory.Error, key: "Interface declaration cannot have 'implements' clause." }, + Binary_digit_expected: { code: 1177, category: DiagnosticCategory.Error, key: "Binary digit expected." }, + Octal_digit_expected: { code: 1178, category: DiagnosticCategory.Error, key: "Octal digit expected." }, + Unexpected_token_expected: { code: 1179, category: DiagnosticCategory.Error, key: "Unexpected token. '{' expected." }, + Property_destructuring_pattern_expected: { code: 1180, category: DiagnosticCategory.Error, key: "Property destructuring pattern expected." }, + Array_element_destructuring_pattern_expected: { code: 1181, category: DiagnosticCategory.Error, key: "Array element destructuring pattern expected." }, + A_destructuring_declaration_must_have_an_initializer: { code: 1182, category: DiagnosticCategory.Error, key: "A destructuring declaration must have an initializer." }, + Destructuring_declarations_are_not_allowed_in_ambient_contexts: { code: 1183, category: DiagnosticCategory.Error, key: "Destructuring declarations are not allowed in ambient contexts." }, + An_implementation_cannot_be_declared_in_ambient_contexts: { code: 1184, category: DiagnosticCategory.Error, key: "An implementation cannot be declared in ambient contexts." }, + Modifiers_cannot_appear_here: { code: 1184, category: DiagnosticCategory.Error, key: "Modifiers cannot appear here." }, + Merge_conflict_marker_encountered: { code: 1185, category: DiagnosticCategory.Error, key: "Merge conflict marker encountered." }, + A_rest_element_cannot_have_an_initializer: { code: 1186, category: DiagnosticCategory.Error, key: "A rest element cannot have an initializer." }, + A_parameter_property_may_not_be_a_binding_pattern: { code: 1187, category: DiagnosticCategory.Error, key: "A parameter property may not be a binding pattern." }, + Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement: { code: 1188, category: DiagnosticCategory.Error, key: "Only a single variable declaration is allowed in a 'for...of' statement." }, + The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer: { code: 1189, category: DiagnosticCategory.Error, key: "The variable declaration of a 'for...in' statement cannot have an initializer." }, + The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer: { code: 1190, category: DiagnosticCategory.Error, key: "The variable declaration of a 'for...of' statement cannot have an initializer." }, + An_import_declaration_cannot_have_modifiers: { code: 1191, category: DiagnosticCategory.Error, key: "An import declaration cannot have modifiers." }, + External_module_0_has_no_default_export: { code: 1192, category: DiagnosticCategory.Error, key: "External module '{0}' has no default export." }, + An_export_declaration_cannot_have_modifiers: { code: 1193, category: DiagnosticCategory.Error, key: "An export declaration cannot have modifiers." }, + Export_declarations_are_not_permitted_in_an_internal_module: { code: 1194, category: DiagnosticCategory.Error, key: "Export declarations are not permitted in an internal module." }, + Catch_clause_variable_name_must_be_an_identifier: { code: 1195, category: DiagnosticCategory.Error, key: "Catch clause variable name must be an identifier." }, + Catch_clause_variable_cannot_have_a_type_annotation: { code: 1196, category: DiagnosticCategory.Error, key: "Catch clause variable cannot have a type annotation." }, + Catch_clause_variable_cannot_have_an_initializer: { code: 1197, category: DiagnosticCategory.Error, key: "Catch clause variable cannot have an initializer." }, + An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive: { code: 1198, category: DiagnosticCategory.Error, key: "An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive." }, + Unterminated_Unicode_escape_sequence: { code: 1199, category: DiagnosticCategory.Error, key: "Unterminated Unicode escape sequence." }, + Line_terminator_not_permitted_before_arrow: { code: 1200, category: DiagnosticCategory.Error, key: "Line terminator not permitted before arrow." }, + Import_assignment_cannot_be_used_when_targeting_ECMAScript_6_or_higher_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_or_import_d_from_mod_instead: { code: 1202, category: DiagnosticCategory.Error, key: "Import assignment cannot be used when targeting ECMAScript 6 or higher. Consider using 'import * as ns from \"mod\"', 'import {a} from \"mod\"' or 'import d from \"mod\"' instead." }, + Export_assignment_cannot_be_used_when_targeting_ECMAScript_6_or_higher_Consider_using_export_default_instead: { code: 1203, category: DiagnosticCategory.Error, key: "Export assignment cannot be used when targeting ECMAScript 6 or higher. Consider using 'export default' instead." }, + Cannot_compile_external_modules_into_amd_commonjs_or_umd_when_targeting_ES6_or_higher: { code: 1204, category: DiagnosticCategory.Error, key: "Cannot compile external modules into 'amd', 'commonjs' or 'umd' when targeting 'ES6' or higher." }, + Decorators_are_only_available_when_targeting_ECMAScript_5_and_higher: { code: 1205, category: DiagnosticCategory.Error, key: "Decorators are only available when targeting ECMAScript 5 and higher." }, + Decorators_are_not_valid_here: { code: 1206, category: DiagnosticCategory.Error, key: "Decorators are not valid here." }, + Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name: { code: 1207, category: DiagnosticCategory.Error, key: "Decorators cannot be applied to multiple get/set accessors of the same name." }, + Cannot_compile_non_external_modules_when_the_separateCompilation_flag_is_provided: { code: 1208, category: DiagnosticCategory.Error, key: "Cannot compile non-external modules when the '--separateCompilation' flag is provided." }, + Ambient_const_enums_are_not_allowed_when_the_separateCompilation_flag_is_provided: { code: 1209, category: DiagnosticCategory.Error, key: "Ambient const enums are not allowed when the '--separateCompilation' flag is provided." }, + Invalid_use_of_0_Class_definitions_are_automatically_in_strict_mode: { code: 1210, category: DiagnosticCategory.Error, key: "Invalid use of '{0}'. Class definitions are automatically in strict mode." }, + A_class_declaration_without_the_default_modifier_must_have_a_name: { code: 1211, category: DiagnosticCategory.Error, key: "A class declaration without the 'default' modifier must have a name" }, + Identifier_expected_0_is_a_reserved_word_in_strict_mode: { code: 1212, category: DiagnosticCategory.Error, key: "Identifier expected. '{0}' is a reserved word in strict mode" }, + Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode: { code: 1213, category: DiagnosticCategory.Error, key: "Identifier expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode." }, + Identifier_expected_0_is_a_reserved_word_in_strict_mode_External_Module_is_automatically_in_strict_mode: { code: 1214, category: DiagnosticCategory.Error, key: "Identifier expected. '{0}' is a reserved word in strict mode. External Module is automatically in strict mode." }, + Type_expected_0_is_a_reserved_word_in_strict_mode: { code: 1215, category: DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode" }, + Type_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode: { code: 1216, category: DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode." }, + Type_expected_0_is_a_reserved_word_in_strict_mode_Module_is_automatically_in_strict_mode: { code: 1217, category: DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode. Module is automatically in strict mode." }, + Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, + Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, + Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, + Circular_definition_of_import_alias_0: { code: 2303, category: DiagnosticCategory.Error, key: "Circular definition of import alias '{0}'." }, + Cannot_find_name_0: { code: 2304, category: DiagnosticCategory.Error, key: "Cannot find name '{0}'." }, + Module_0_has_no_exported_member_1: { code: 2305, category: DiagnosticCategory.Error, key: "Module '{0}' has no exported member '{1}'." }, + File_0_is_not_an_external_module: { code: 2306, category: DiagnosticCategory.Error, key: "File '{0}' is not an external module." }, + Cannot_find_external_module_0: { code: 2307, category: DiagnosticCategory.Error, key: "Cannot find external module '{0}'." }, + A_module_cannot_have_more_than_one_export_assignment: { code: 2308, category: DiagnosticCategory.Error, key: "A module cannot have more than one export assignment." }, + An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements: { code: 2309, category: DiagnosticCategory.Error, key: "An export assignment cannot be used in a module with other exported elements." }, + Type_0_recursively_references_itself_as_a_base_type: { code: 2310, category: DiagnosticCategory.Error, key: "Type '{0}' recursively references itself as a base type." }, + A_class_may_only_extend_another_class: { code: 2311, category: DiagnosticCategory.Error, key: "A class may only extend another class." }, + An_interface_may_only_extend_a_class_or_another_interface: { code: 2312, category: DiagnosticCategory.Error, key: "An interface may only extend a class or another interface." }, + Constraint_of_a_type_parameter_cannot_reference_any_type_parameter_from_the_same_type_parameter_list: { code: 2313, category: DiagnosticCategory.Error, key: "Constraint of a type parameter cannot reference any type parameter from the same type parameter list." }, + Generic_type_0_requires_1_type_argument_s: { code: 2314, category: DiagnosticCategory.Error, key: "Generic type '{0}' requires {1} type argument(s)." }, + Type_0_is_not_generic: { code: 2315, category: DiagnosticCategory.Error, key: "Type '{0}' is not generic." }, + Global_type_0_must_be_a_class_or_interface_type: { code: 2316, category: DiagnosticCategory.Error, key: "Global type '{0}' must be a class or interface type." }, + Global_type_0_must_have_1_type_parameter_s: { code: 2317, category: DiagnosticCategory.Error, key: "Global type '{0}' must have {1} type parameter(s)." }, + Cannot_find_global_type_0: { code: 2318, category: DiagnosticCategory.Error, key: "Cannot find global type '{0}'." }, + Named_property_0_of_types_1_and_2_are_not_identical: { code: 2319, category: DiagnosticCategory.Error, key: "Named property '{0}' of types '{1}' and '{2}' are not identical." }, + Interface_0_cannot_simultaneously_extend_types_1_and_2: { code: 2320, category: DiagnosticCategory.Error, key: "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}'." }, + Excessive_stack_depth_comparing_types_0_and_1: { code: 2321, category: DiagnosticCategory.Error, key: "Excessive stack depth comparing types '{0}' and '{1}'." }, + Type_0_is_not_assignable_to_type_1: { code: 2322, category: DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}'." }, + Property_0_is_missing_in_type_1: { code: 2324, category: DiagnosticCategory.Error, key: "Property '{0}' is missing in type '{1}'." }, + Property_0_is_private_in_type_1_but_not_in_type_2: { code: 2325, category: DiagnosticCategory.Error, key: "Property '{0}' is private in type '{1}' but not in type '{2}'." }, + Types_of_property_0_are_incompatible: { code: 2326, category: DiagnosticCategory.Error, key: "Types of property '{0}' are incompatible." }, + Property_0_is_optional_in_type_1_but_required_in_type_2: { code: 2327, category: DiagnosticCategory.Error, key: "Property '{0}' is optional in type '{1}' but required in type '{2}'." }, + Types_of_parameters_0_and_1_are_incompatible: { code: 2328, category: DiagnosticCategory.Error, key: "Types of parameters '{0}' and '{1}' are incompatible." }, + Index_signature_is_missing_in_type_0: { code: 2329, category: DiagnosticCategory.Error, key: "Index signature is missing in type '{0}'." }, + Index_signatures_are_incompatible: { code: 2330, category: DiagnosticCategory.Error, key: "Index signatures are incompatible." }, + this_cannot_be_referenced_in_a_module_body: { code: 2331, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in a module body." }, + this_cannot_be_referenced_in_current_location: { code: 2332, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in current location." }, + this_cannot_be_referenced_in_constructor_arguments: { code: 2333, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in constructor arguments." }, + this_cannot_be_referenced_in_a_static_property_initializer: { code: 2334, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in a static property initializer." }, + super_can_only_be_referenced_in_a_derived_class: { code: 2335, category: DiagnosticCategory.Error, key: "'super' can only be referenced in a derived class." }, + super_cannot_be_referenced_in_constructor_arguments: { code: 2336, category: DiagnosticCategory.Error, key: "'super' cannot be referenced in constructor arguments." }, + Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors: { code: 2337, category: DiagnosticCategory.Error, key: "Super calls are not permitted outside constructors or in nested functions inside constructors" }, + super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class: { code: 2338, category: DiagnosticCategory.Error, key: "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class" }, + Property_0_does_not_exist_on_type_1: { code: 2339, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist on type '{1}'." }, + Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword: { code: 2340, category: DiagnosticCategory.Error, key: "Only public and protected methods of the base class are accessible via the 'super' keyword" }, + Property_0_is_private_and_only_accessible_within_class_1: { code: 2341, category: DiagnosticCategory.Error, key: "Property '{0}' is private and only accessible within class '{1}'." }, + An_index_expression_argument_must_be_of_type_string_number_symbol_or_any: { code: 2342, category: DiagnosticCategory.Error, key: "An index expression argument must be of type 'string', 'number', 'symbol, or 'any'." }, + Type_0_does_not_satisfy_the_constraint_1: { code: 2344, category: DiagnosticCategory.Error, key: "Type '{0}' does not satisfy the constraint '{1}'." }, + Argument_of_type_0_is_not_assignable_to_parameter_of_type_1: { code: 2345, category: DiagnosticCategory.Error, key: "Argument of type '{0}' is not assignable to parameter of type '{1}'." }, + Supplied_parameters_do_not_match_any_signature_of_call_target: { code: 2346, category: DiagnosticCategory.Error, key: "Supplied parameters do not match any signature of call target." }, + Untyped_function_calls_may_not_accept_type_arguments: { code: 2347, category: DiagnosticCategory.Error, key: "Untyped function calls may not accept type arguments." }, + Value_of_type_0_is_not_callable_Did_you_mean_to_include_new: { code: 2348, category: DiagnosticCategory.Error, key: "Value of type '{0}' is not callable. Did you mean to include 'new'?" }, + Cannot_invoke_an_expression_whose_type_lacks_a_call_signature: { code: 2349, category: DiagnosticCategory.Error, key: "Cannot invoke an expression whose type lacks a call signature." }, + Only_a_void_function_can_be_called_with_the_new_keyword: { code: 2350, category: DiagnosticCategory.Error, key: "Only a void function can be called with the 'new' keyword." }, + Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature: { code: 2351, category: DiagnosticCategory.Error, key: "Cannot use 'new' with an expression whose type lacks a call or construct signature." }, + Neither_type_0_nor_type_1_is_assignable_to_the_other: { code: 2352, category: DiagnosticCategory.Error, key: "Neither type '{0}' nor type '{1}' is assignable to the other." }, + No_best_common_type_exists_among_return_expressions: { code: 2354, category: DiagnosticCategory.Error, key: "No best common type exists among return expressions." }, + A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value_or_consist_of_a_single_throw_statement: { code: 2355, category: DiagnosticCategory.Error, key: "A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement." }, + An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type: { code: 2356, category: DiagnosticCategory.Error, key: "An arithmetic operand must be of type 'any', 'number' or an enum type." }, + The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_property_or_indexer: { code: 2357, category: DiagnosticCategory.Error, key: "The operand of an increment or decrement operator must be a variable, property or indexer." }, + The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: { code: 2358, category: DiagnosticCategory.Error, key: "The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter." }, + The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type: { code: 2359, category: DiagnosticCategory.Error, key: "The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type." }, + The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol: { code: 2360, category: DiagnosticCategory.Error, key: "The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'." }, + The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: { code: 2361, category: DiagnosticCategory.Error, key: "The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter" }, + The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type: { code: 2362, category: DiagnosticCategory.Error, key: "The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type." }, + The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type: { code: 2363, category: DiagnosticCategory.Error, key: "The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type." }, + Invalid_left_hand_side_of_assignment_expression: { code: 2364, category: DiagnosticCategory.Error, key: "Invalid left-hand side of assignment expression." }, + Operator_0_cannot_be_applied_to_types_1_and_2: { code: 2365, category: DiagnosticCategory.Error, key: "Operator '{0}' cannot be applied to types '{1}' and '{2}'." }, + Type_parameter_name_cannot_be_0: { code: 2368, category: DiagnosticCategory.Error, key: "Type parameter name cannot be '{0}'" }, + A_parameter_property_is_only_allowed_in_a_constructor_implementation: { code: 2369, category: DiagnosticCategory.Error, key: "A parameter property is only allowed in a constructor implementation." }, + A_rest_parameter_must_be_of_an_array_type: { code: 2370, category: DiagnosticCategory.Error, key: "A rest parameter must be of an array type." }, + A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation: { code: 2371, category: DiagnosticCategory.Error, key: "A parameter initializer is only allowed in a function or constructor implementation." }, + Parameter_0_cannot_be_referenced_in_its_initializer: { code: 2372, category: DiagnosticCategory.Error, key: "Parameter '{0}' cannot be referenced in its initializer." }, + Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it: { code: 2373, category: DiagnosticCategory.Error, key: "Initializer of parameter '{0}' cannot reference identifier '{1}' declared after it." }, + Duplicate_string_index_signature: { code: 2374, category: DiagnosticCategory.Error, key: "Duplicate string index signature." }, + Duplicate_number_index_signature: { code: 2375, category: DiagnosticCategory.Error, key: "Duplicate number index signature." }, + A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties: { code: 2376, category: DiagnosticCategory.Error, key: "A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties." }, + Constructors_for_derived_classes_must_contain_a_super_call: { code: 2377, category: DiagnosticCategory.Error, key: "Constructors for derived classes must contain a 'super' call." }, + A_get_accessor_must_return_a_value_or_consist_of_a_single_throw_statement: { code: 2378, category: DiagnosticCategory.Error, key: "A 'get' accessor must return a value or consist of a single 'throw' statement." }, + Getter_and_setter_accessors_do_not_agree_in_visibility: { code: 2379, category: DiagnosticCategory.Error, key: "Getter and setter accessors do not agree in visibility." }, + get_and_set_accessor_must_have_the_same_type: { code: 2380, category: DiagnosticCategory.Error, key: "'get' and 'set' accessor must have the same type." }, + A_signature_with_an_implementation_cannot_use_a_string_literal_type: { code: 2381, category: DiagnosticCategory.Error, key: "A signature with an implementation cannot use a string literal type." }, + Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature: { code: 2382, category: DiagnosticCategory.Error, key: "Specialized overload signature is not assignable to any non-specialized signature." }, + Overload_signatures_must_all_be_exported_or_not_exported: { code: 2383, category: DiagnosticCategory.Error, key: "Overload signatures must all be exported or not exported." }, + Overload_signatures_must_all_be_ambient_or_non_ambient: { code: 2384, category: DiagnosticCategory.Error, key: "Overload signatures must all be ambient or non-ambient." }, + Overload_signatures_must_all_be_public_private_or_protected: { code: 2385, category: DiagnosticCategory.Error, key: "Overload signatures must all be public, private or protected." }, + Overload_signatures_must_all_be_optional_or_required: { code: 2386, category: DiagnosticCategory.Error, key: "Overload signatures must all be optional or required." }, + Function_overload_must_be_static: { code: 2387, category: DiagnosticCategory.Error, key: "Function overload must be static." }, + Function_overload_must_not_be_static: { code: 2388, category: DiagnosticCategory.Error, key: "Function overload must not be static." }, + Function_implementation_name_must_be_0: { code: 2389, category: DiagnosticCategory.Error, key: "Function implementation name must be '{0}'." }, + Constructor_implementation_is_missing: { code: 2390, category: DiagnosticCategory.Error, key: "Constructor implementation is missing." }, + Function_implementation_is_missing_or_not_immediately_following_the_declaration: { code: 2391, category: DiagnosticCategory.Error, key: "Function implementation is missing or not immediately following the declaration." }, + Multiple_constructor_implementations_are_not_allowed: { code: 2392, category: DiagnosticCategory.Error, key: "Multiple constructor implementations are not allowed." }, + Duplicate_function_implementation: { code: 2393, category: DiagnosticCategory.Error, key: "Duplicate function implementation." }, + Overload_signature_is_not_compatible_with_function_implementation: { code: 2394, category: DiagnosticCategory.Error, key: "Overload signature is not compatible with function implementation." }, + Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local: { code: 2395, category: DiagnosticCategory.Error, key: "Individual declarations in merged declaration {0} must be all exported or all local." }, + Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters: { code: 2396, category: DiagnosticCategory.Error, key: "Duplicate identifier 'arguments'. Compiler uses 'arguments' to initialize rest parameters." }, + Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference: { code: 2399, category: DiagnosticCategory.Error, key: "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference." }, + Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference: { code: 2400, category: DiagnosticCategory.Error, key: "Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference." }, + Duplicate_identifier_super_Compiler_uses_super_to_capture_base_class_reference: { code: 2401, category: DiagnosticCategory.Error, key: "Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference." }, + Expression_resolves_to_super_that_compiler_uses_to_capture_base_class_reference: { code: 2402, category: DiagnosticCategory.Error, key: "Expression resolves to '_super' that compiler uses to capture base class reference." }, + Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2: { code: 2403, category: DiagnosticCategory.Error, key: "Subsequent variable declarations must have the same type. Variable '{0}' must be of type '{1}', but here has type '{2}'." }, + The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation: { code: 2404, category: DiagnosticCategory.Error, key: "The left-hand side of a 'for...in' statement cannot use a type annotation." }, + The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any: { code: 2405, category: DiagnosticCategory.Error, key: "The left-hand side of a 'for...in' statement must be of type 'string' or 'any'." }, + Invalid_left_hand_side_in_for_in_statement: { code: 2406, category: DiagnosticCategory.Error, key: "Invalid left-hand side in 'for...in' statement." }, + The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter: { code: 2407, category: DiagnosticCategory.Error, key: "The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter." }, + Setters_cannot_return_a_value: { code: 2408, category: DiagnosticCategory.Error, key: "Setters cannot return a value." }, + Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class: { code: 2409, category: DiagnosticCategory.Error, key: "Return type of constructor signature must be assignable to the instance type of the class" }, + All_symbols_within_a_with_block_will_be_resolved_to_any: { code: 2410, category: DiagnosticCategory.Error, key: "All symbols within a 'with' block will be resolved to 'any'." }, + Property_0_of_type_1_is_not_assignable_to_string_index_type_2: { code: 2411, category: DiagnosticCategory.Error, key: "Property '{0}' of type '{1}' is not assignable to string index type '{2}'." }, + Property_0_of_type_1_is_not_assignable_to_numeric_index_type_2: { code: 2412, category: DiagnosticCategory.Error, key: "Property '{0}' of type '{1}' is not assignable to numeric index type '{2}'." }, + Numeric_index_type_0_is_not_assignable_to_string_index_type_1: { code: 2413, category: DiagnosticCategory.Error, key: "Numeric index type '{0}' is not assignable to string index type '{1}'." }, + Class_name_cannot_be_0: { code: 2414, category: DiagnosticCategory.Error, key: "Class name cannot be '{0}'" }, + Class_0_incorrectly_extends_base_class_1: { code: 2415, category: DiagnosticCategory.Error, key: "Class '{0}' incorrectly extends base class '{1}'." }, + Class_static_side_0_incorrectly_extends_base_class_static_side_1: { code: 2417, category: DiagnosticCategory.Error, key: "Class static side '{0}' incorrectly extends base class static side '{1}'." }, + Type_name_0_in_extends_clause_does_not_reference_constructor_function_for_0: { code: 2419, category: DiagnosticCategory.Error, key: "Type name '{0}' in extends clause does not reference constructor function for '{0}'." }, + Class_0_incorrectly_implements_interface_1: { code: 2420, category: DiagnosticCategory.Error, key: "Class '{0}' incorrectly implements interface '{1}'." }, + A_class_may_only_implement_another_class_or_interface: { code: 2422, category: DiagnosticCategory.Error, key: "A class may only implement another class or interface." }, + Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor: { code: 2423, category: DiagnosticCategory.Error, key: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member accessor." }, + Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property: { code: 2424, category: DiagnosticCategory.Error, key: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member property." }, + Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function: { code: 2425, category: DiagnosticCategory.Error, key: "Class '{0}' defines instance member property '{1}', but extended class '{2}' defines it as instance member function." }, + Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function: { code: 2426, category: DiagnosticCategory.Error, key: "Class '{0}' defines instance member accessor '{1}', but extended class '{2}' defines it as instance member function." }, + Interface_name_cannot_be_0: { code: 2427, category: DiagnosticCategory.Error, key: "Interface name cannot be '{0}'" }, + All_declarations_of_an_interface_must_have_identical_type_parameters: { code: 2428, category: DiagnosticCategory.Error, key: "All declarations of an interface must have identical type parameters." }, + Interface_0_incorrectly_extends_interface_1: { code: 2430, category: DiagnosticCategory.Error, key: "Interface '{0}' incorrectly extends interface '{1}'." }, + Enum_name_cannot_be_0: { code: 2431, category: DiagnosticCategory.Error, key: "Enum name cannot be '{0}'" }, + In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element: { code: 2432, category: DiagnosticCategory.Error, key: "In an enum with multiple declarations, only one declaration can omit an initializer for its first enum element." }, + A_module_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged: { code: 2433, category: DiagnosticCategory.Error, key: "A module declaration cannot be in a different file from a class or function with which it is merged" }, + A_module_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged: { code: 2434, category: DiagnosticCategory.Error, key: "A module declaration cannot be located prior to a class or function with which it is merged" }, + Ambient_external_modules_cannot_be_nested_in_other_modules: { code: 2435, category: DiagnosticCategory.Error, key: "Ambient external modules cannot be nested in other modules." }, + Ambient_external_module_declaration_cannot_specify_relative_module_name: { code: 2436, category: DiagnosticCategory.Error, key: "Ambient external module declaration cannot specify relative module name." }, + Module_0_is_hidden_by_a_local_declaration_with_the_same_name: { code: 2437, category: DiagnosticCategory.Error, key: "Module '{0}' is hidden by a local declaration with the same name" }, + Import_name_cannot_be_0: { code: 2438, category: DiagnosticCategory.Error, key: "Import name cannot be '{0}'" }, + Import_or_export_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name: { code: 2439, category: DiagnosticCategory.Error, key: "Import or export declaration in an ambient external module declaration cannot reference external module through relative external module name." }, + Import_declaration_conflicts_with_local_declaration_of_0: { code: 2440, category: DiagnosticCategory.Error, key: "Import declaration conflicts with local declaration of '{0}'" }, + Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_an_external_module: { code: 2441, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of an external module." }, + Types_have_separate_declarations_of_a_private_property_0: { code: 2442, category: DiagnosticCategory.Error, key: "Types have separate declarations of a private property '{0}'." }, + Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2: { code: 2443, category: DiagnosticCategory.Error, key: "Property '{0}' is protected but type '{1}' is not a class derived from '{2}'." }, + Property_0_is_protected_in_type_1_but_public_in_type_2: { code: 2444, category: DiagnosticCategory.Error, key: "Property '{0}' is protected in type '{1}' but public in type '{2}'." }, + Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses: { code: 2445, category: DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible within class '{1}' and its subclasses." }, + Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1: { code: 2446, category: DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible through an instance of class '{1}'." }, + The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead: { code: 2447, category: DiagnosticCategory.Error, key: "The '{0}' operator is not allowed for boolean types. Consider using '{1}' instead." }, + Block_scoped_variable_0_used_before_its_declaration: { code: 2448, category: DiagnosticCategory.Error, key: "Block-scoped variable '{0}' used before its declaration." }, + The_operand_of_an_increment_or_decrement_operator_cannot_be_a_constant: { code: 2449, category: DiagnosticCategory.Error, key: "The operand of an increment or decrement operator cannot be a constant." }, + Left_hand_side_of_assignment_expression_cannot_be_a_constant: { code: 2450, category: DiagnosticCategory.Error, key: "Left-hand side of assignment expression cannot be a constant." }, + Cannot_redeclare_block_scoped_variable_0: { code: 2451, category: DiagnosticCategory.Error, key: "Cannot redeclare block-scoped variable '{0}'." }, + An_enum_member_cannot_have_a_numeric_name: { code: 2452, category: DiagnosticCategory.Error, key: "An enum member cannot have a numeric name." }, + The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly: { code: 2453, category: DiagnosticCategory.Error, key: "The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly." }, + Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0: { code: 2455, category: DiagnosticCategory.Error, key: "Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'." }, + Type_alias_0_circularly_references_itself: { code: 2456, category: DiagnosticCategory.Error, key: "Type alias '{0}' circularly references itself." }, + Type_alias_name_cannot_be_0: { code: 2457, category: DiagnosticCategory.Error, key: "Type alias name cannot be '{0}'" }, + An_AMD_module_cannot_have_multiple_name_assignments: { code: 2458, category: DiagnosticCategory.Error, key: "An AMD module cannot have multiple name assignments." }, + Type_0_has_no_property_1_and_no_string_index_signature: { code: 2459, category: DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}' and no string index signature." }, + Type_0_has_no_property_1: { code: 2460, category: DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}'." }, + Type_0_is_not_an_array_type: { code: 2461, category: DiagnosticCategory.Error, key: "Type '{0}' is not an array type." }, + A_rest_element_must_be_last_in_an_array_destructuring_pattern: { code: 2462, category: DiagnosticCategory.Error, key: "A rest element must be last in an array destructuring pattern" }, + A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature: { code: 2463, category: DiagnosticCategory.Error, key: "A binding pattern parameter cannot be optional in an implementation signature." }, + A_computed_property_name_must_be_of_type_string_number_symbol_or_any: { code: 2464, category: DiagnosticCategory.Error, key: "A computed property name must be of type 'string', 'number', 'symbol', or 'any'." }, + this_cannot_be_referenced_in_a_computed_property_name: { code: 2465, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in a computed property name." }, + super_cannot_be_referenced_in_a_computed_property_name: { code: 2466, category: DiagnosticCategory.Error, key: "'super' cannot be referenced in a computed property name." }, + A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type: { code: 2467, category: DiagnosticCategory.Error, key: "A computed property name cannot reference a type parameter from its containing type." }, + Cannot_find_global_value_0: { code: 2468, category: DiagnosticCategory.Error, key: "Cannot find global value '{0}'." }, + The_0_operator_cannot_be_applied_to_type_symbol: { code: 2469, category: DiagnosticCategory.Error, key: "The '{0}' operator cannot be applied to type 'symbol'." }, + Symbol_reference_does_not_refer_to_the_global_Symbol_constructor_object: { code: 2470, category: DiagnosticCategory.Error, key: "'Symbol' reference does not refer to the global Symbol constructor object." }, + A_computed_property_name_of_the_form_0_must_be_of_type_symbol: { code: 2471, category: DiagnosticCategory.Error, key: "A computed property name of the form '{0}' must be of type 'symbol'." }, + Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_6_and_higher: { code: 2472, category: DiagnosticCategory.Error, key: "Spread operator in 'new' expressions is only available when targeting ECMAScript 6 and higher." }, + Enum_declarations_must_all_be_const_or_non_const: { code: 2473, category: DiagnosticCategory.Error, key: "Enum declarations must all be const or non-const." }, + In_const_enum_declarations_member_initializer_must_be_constant_expression: { code: 2474, category: DiagnosticCategory.Error, key: "In 'const' enum declarations member initializer must be constant expression." }, + const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment: { code: 2475, category: DiagnosticCategory.Error, key: "'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment." }, + A_const_enum_member_can_only_be_accessed_using_a_string_literal: { code: 2476, category: DiagnosticCategory.Error, key: "A const enum member can only be accessed using a string literal." }, + const_enum_member_initializer_was_evaluated_to_a_non_finite_value: { code: 2477, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to a non-finite value." }, + const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN: { code: 2478, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to disallowed value 'NaN'." }, + Property_0_does_not_exist_on_const_enum_1: { code: 2479, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist on 'const' enum '{1}'." }, + let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations: { code: 2480, category: DiagnosticCategory.Error, key: "'let' is not allowed to be used as a name in 'let' or 'const' declarations." }, + Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1: { code: 2481, category: DiagnosticCategory.Error, key: "Cannot initialize outer scoped variable '{0}' in the same scope as block scoped declaration '{1}'." }, + The_left_hand_side_of_a_for_of_statement_cannot_use_a_type_annotation: { code: 2483, category: DiagnosticCategory.Error, key: "The left-hand side of a 'for...of' statement cannot use a type annotation." }, + Export_declaration_conflicts_with_exported_declaration_of_0: { code: 2484, category: DiagnosticCategory.Error, key: "Export declaration conflicts with exported declaration of '{0}'" }, + The_left_hand_side_of_a_for_of_statement_cannot_be_a_previously_defined_constant: { code: 2485, category: DiagnosticCategory.Error, key: "The left-hand side of a 'for...of' statement cannot be a previously defined constant." }, + The_left_hand_side_of_a_for_in_statement_cannot_be_a_previously_defined_constant: { code: 2486, category: DiagnosticCategory.Error, key: "The left-hand side of a 'for...in' statement cannot be a previously defined constant." }, + Invalid_left_hand_side_in_for_of_statement: { code: 2487, category: DiagnosticCategory.Error, key: "Invalid left-hand side in 'for...of' statement." }, + Type_must_have_a_Symbol_iterator_method_that_returns_an_iterator: { code: 2488, category: DiagnosticCategory.Error, key: "Type must have a '[Symbol.iterator]()' method that returns an iterator." }, + An_iterator_must_have_a_next_method: { code: 2489, category: DiagnosticCategory.Error, key: "An iterator must have a 'next()' method." }, + The_type_returned_by_the_next_method_of_an_iterator_must_have_a_value_property: { code: 2490, category: DiagnosticCategory.Error, key: "The type returned by the 'next()' method of an iterator must have a 'value' property." }, + The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern: { code: 2491, category: DiagnosticCategory.Error, key: "The left-hand side of a 'for...in' statement cannot be a destructuring pattern." }, + Cannot_redeclare_identifier_0_in_catch_clause: { code: 2492, category: DiagnosticCategory.Error, key: "Cannot redeclare identifier '{0}' in catch clause" }, + Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2: { code: 2493, category: DiagnosticCategory.Error, key: "Tuple type '{0}' with length '{1}' cannot be assigned to tuple with length '{2}'." }, + Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher: { code: 2494, category: DiagnosticCategory.Error, key: "Using a string in a 'for...of' statement is only supported in ECMAScript 5 and higher." }, + Type_0_is_not_an_array_type_or_a_string_type: { code: 2495, category: DiagnosticCategory.Error, key: "Type '{0}' is not an array type or a string type." }, + The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression: { code: 2496, category: DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an arrow function in ES3 and ES5. Consider using a standard function expression." }, + External_module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct: { code: 2497, category: DiagnosticCategory.Error, key: "External module '{0}' resolves to a non-module entity and cannot be imported using this construct." }, + External_module_0_uses_export_and_cannot_be_used_with_export_Asterisk: { code: 2498, category: DiagnosticCategory.Error, key: "External module '{0}' uses 'export =' and cannot be used with 'export *'." }, + An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments: { code: 2499, category: DiagnosticCategory.Error, key: "An interface can only extend an identifier/qualified-name with optional type arguments." }, + A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments: { code: 2500, category: DiagnosticCategory.Error, key: "A class can only implement an identifier/qualified-name with optional type arguments." }, + A_rest_element_cannot_contain_a_binding_pattern: { code: 2501, category: DiagnosticCategory.Error, key: "A rest element cannot contain a binding pattern." }, + Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." }, + Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." }, + Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." }, + Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 4006, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of constructor signature from exported interface has or is using private name '{1}'." }, + Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 4008, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of call signature from exported interface has or is using private name '{1}'." }, + Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1: { code: 4010, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of public static method from exported class has or is using private name '{1}'." }, + Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1: { code: 4012, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of public method from exported class has or is using private name '{1}'." }, + Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1: { code: 4014, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of method from exported interface has or is using private name '{1}'." }, + Type_parameter_0_of_exported_function_has_or_is_using_private_name_1: { code: 4016, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported function has or is using private name '{1}'." }, + Implements_clause_of_exported_class_0_has_or_is_using_private_name_1: { code: 4019, category: DiagnosticCategory.Error, key: "Implements clause of exported class '{0}' has or is using private name '{1}'." }, + Extends_clause_of_exported_class_0_has_or_is_using_private_name_1: { code: 4020, category: DiagnosticCategory.Error, key: "Extends clause of exported class '{0}' has or is using private name '{1}'." }, + Extends_clause_of_exported_interface_0_has_or_is_using_private_name_1: { code: 4022, category: DiagnosticCategory.Error, key: "Extends clause of exported interface '{0}' has or is using private name '{1}'." }, + Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4023, category: DiagnosticCategory.Error, key: "Exported variable '{0}' has or is using name '{1}' from external module {2} but cannot be named." }, + Exported_variable_0_has_or_is_using_name_1_from_private_module_2: { code: 4024, category: DiagnosticCategory.Error, key: "Exported variable '{0}' has or is using name '{1}' from private module '{2}'." }, + Exported_variable_0_has_or_is_using_private_name_1: { code: 4025, category: DiagnosticCategory.Error, key: "Exported variable '{0}' has or is using private name '{1}'." }, + Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4026, category: DiagnosticCategory.Error, key: "Public static property '{0}' of exported class has or is using name '{1}' from external module {2} but cannot be named." }, + Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4027, category: DiagnosticCategory.Error, key: "Public static property '{0}' of exported class has or is using name '{1}' from private module '{2}'." }, + Public_static_property_0_of_exported_class_has_or_is_using_private_name_1: { code: 4028, category: DiagnosticCategory.Error, key: "Public static property '{0}' of exported class has or is using private name '{1}'." }, + Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4029, category: DiagnosticCategory.Error, key: "Public property '{0}' of exported class has or is using name '{1}' from external module {2} but cannot be named." }, + Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4030, category: DiagnosticCategory.Error, key: "Public property '{0}' of exported class has or is using name '{1}' from private module '{2}'." }, + Public_property_0_of_exported_class_has_or_is_using_private_name_1: { code: 4031, category: DiagnosticCategory.Error, key: "Public property '{0}' of exported class has or is using private name '{1}'." }, + Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4032, category: DiagnosticCategory.Error, key: "Property '{0}' of exported interface has or is using name '{1}' from private module '{2}'." }, + Property_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4033, category: DiagnosticCategory.Error, key: "Property '{0}' of exported interface has or is using private name '{1}'." }, + Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4034, category: DiagnosticCategory.Error, key: "Parameter '{0}' of public static property setter from exported class has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1: { code: 4035, category: DiagnosticCategory.Error, key: "Parameter '{0}' of public static property setter from exported class has or is using private name '{1}'." }, + Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4036, category: DiagnosticCategory.Error, key: "Parameter '{0}' of public property setter from exported class has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_name_1: { code: 4037, category: DiagnosticCategory.Error, key: "Parameter '{0}' of public property setter from exported class has or is using private name '{1}'." }, + Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named: { code: 4038, category: DiagnosticCategory.Error, key: "Return type of public static property getter from exported class has or is using name '{0}' from external module {1} but cannot be named." }, + Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1: { code: 4039, category: DiagnosticCategory.Error, key: "Return type of public static property getter from exported class has or is using name '{0}' from private module '{1}'." }, + Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_name_0: { code: 4040, category: DiagnosticCategory.Error, key: "Return type of public static property getter from exported class has or is using private name '{0}'." }, + Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named: { code: 4041, category: DiagnosticCategory.Error, key: "Return type of public property getter from exported class has or is using name '{0}' from external module {1} but cannot be named." }, + Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1: { code: 4042, category: DiagnosticCategory.Error, key: "Return type of public property getter from exported class has or is using name '{0}' from private module '{1}'." }, + Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_name_0: { code: 4043, category: DiagnosticCategory.Error, key: "Return type of public property getter from exported class has or is using private name '{0}'." }, + Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1: { code: 4044, category: DiagnosticCategory.Error, key: "Return type of constructor signature from exported interface has or is using name '{0}' from private module '{1}'." }, + Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0: { code: 4045, category: DiagnosticCategory.Error, key: "Return type of constructor signature from exported interface has or is using private name '{0}'." }, + Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1: { code: 4046, category: DiagnosticCategory.Error, key: "Return type of call signature from exported interface has or is using name '{0}' from private module '{1}'." }, + Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0: { code: 4047, category: DiagnosticCategory.Error, key: "Return type of call signature from exported interface has or is using private name '{0}'." }, + Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1: { code: 4048, category: DiagnosticCategory.Error, key: "Return type of index signature from exported interface has or is using name '{0}' from private module '{1}'." }, + Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0: { code: 4049, category: DiagnosticCategory.Error, key: "Return type of index signature from exported interface has or is using private name '{0}'." }, + Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named: { code: 4050, category: DiagnosticCategory.Error, key: "Return type of public static method from exported class has or is using name '{0}' from external module {1} but cannot be named." }, + Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1: { code: 4051, category: DiagnosticCategory.Error, key: "Return type of public static method from exported class has or is using name '{0}' from private module '{1}'." }, + Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0: { code: 4052, category: DiagnosticCategory.Error, key: "Return type of public static method from exported class has or is using private name '{0}'." }, + Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named: { code: 4053, category: DiagnosticCategory.Error, key: "Return type of public method from exported class has or is using name '{0}' from external module {1} but cannot be named." }, + Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1: { code: 4054, category: DiagnosticCategory.Error, key: "Return type of public method from exported class has or is using name '{0}' from private module '{1}'." }, + Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0: { code: 4055, category: DiagnosticCategory.Error, key: "Return type of public method from exported class has or is using private name '{0}'." }, + Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1: { code: 4056, category: DiagnosticCategory.Error, key: "Return type of method from exported interface has or is using name '{0}' from private module '{1}'." }, + Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0: { code: 4057, category: DiagnosticCategory.Error, key: "Return type of method from exported interface has or is using private name '{0}'." }, + Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named: { code: 4058, category: DiagnosticCategory.Error, key: "Return type of exported function has or is using name '{0}' from external module {1} but cannot be named." }, + Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1: { code: 4059, category: DiagnosticCategory.Error, key: "Return type of exported function has or is using name '{0}' from private module '{1}'." }, + Return_type_of_exported_function_has_or_is_using_private_name_0: { code: 4060, category: DiagnosticCategory.Error, key: "Return type of exported function has or is using private name '{0}'." }, + Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4061, category: DiagnosticCategory.Error, key: "Parameter '{0}' of constructor from exported class has or is using name '{1}' from external module {2} but cannot be named." }, + Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4062, category: DiagnosticCategory.Error, key: "Parameter '{0}' of constructor from exported class has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1: { code: 4063, category: DiagnosticCategory.Error, key: "Parameter '{0}' of constructor from exported class has or is using private name '{1}'." }, + Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4064, category: DiagnosticCategory.Error, key: "Parameter '{0}' of constructor signature from exported interface has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 4065, category: DiagnosticCategory.Error, key: "Parameter '{0}' of constructor signature from exported interface has or is using private name '{1}'." }, + Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4066, category: DiagnosticCategory.Error, key: "Parameter '{0}' of call signature from exported interface has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 4067, category: DiagnosticCategory.Error, key: "Parameter '{0}' of call signature from exported interface has or is using private name '{1}'." }, + Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4068, category: DiagnosticCategory.Error, key: "Parameter '{0}' of public static method from exported class has or is using name '{1}' from external module {2} but cannot be named." }, + Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4069, category: DiagnosticCategory.Error, key: "Parameter '{0}' of public static method from exported class has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1: { code: 4070, category: DiagnosticCategory.Error, key: "Parameter '{0}' of public static method from exported class has or is using private name '{1}'." }, + Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4071, category: DiagnosticCategory.Error, key: "Parameter '{0}' of public method from exported class has or is using name '{1}' from external module {2} but cannot be named." }, + Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4072, category: DiagnosticCategory.Error, key: "Parameter '{0}' of public method from exported class has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1: { code: 4073, category: DiagnosticCategory.Error, key: "Parameter '{0}' of public method from exported class has or is using private name '{1}'." }, + Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4074, category: DiagnosticCategory.Error, key: "Parameter '{0}' of method from exported interface has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1: { code: 4075, category: DiagnosticCategory.Error, key: "Parameter '{0}' of method from exported interface has or is using private name '{1}'." }, + Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4076, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from external module {2} but cannot be named." }, + Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2: { code: 4077, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from private module '{2}'." }, + Parameter_0_of_exported_function_has_or_is_using_private_name_1: { code: 4078, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using private name '{1}'." }, + Exported_type_alias_0_has_or_is_using_private_name_1: { code: 4081, category: DiagnosticCategory.Error, key: "Exported type alias '{0}' has or is using private name '{1}'." }, + Default_export_of_the_module_has_or_is_using_private_name_0: { code: 4082, category: DiagnosticCategory.Error, key: "Default export of the module has or is using private name '{0}'." }, + Loop_contains_block_scoped_variable_0_referenced_by_a_function_in_the_loop_This_is_only_supported_in_ECMAScript_6_or_higher: { code: 4091, category: DiagnosticCategory.Error, key: "Loop contains block-scoped variable '{0}' referenced by a function in the loop. This is only supported in ECMAScript 6 or higher." }, + The_current_host_does_not_support_the_0_option: { code: 5001, category: DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." }, + Cannot_find_the_common_subdirectory_path_for_the_input_files: { code: 5009, category: DiagnosticCategory.Error, key: "Cannot find the common subdirectory path for the input files." }, + Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" }, + Unsupported_file_encoding: { code: 5013, category: DiagnosticCategory.Error, key: "Unsupported file encoding." }, + Failed_to_parse_file_0_Colon_1: { code: 5014, category: DiagnosticCategory.Error, key: "Failed to parse file '{0}': {1}." }, + Unknown_compiler_option_0: { code: 5023, category: DiagnosticCategory.Error, key: "Unknown compiler option '{0}'." }, + Compiler_option_0_requires_a_value_of_type_1: { code: 5024, category: DiagnosticCategory.Error, key: "Compiler option '{0}' requires a value of type {1}." }, + Could_not_write_file_0_Colon_1: { code: 5033, category: DiagnosticCategory.Error, key: "Could not write file '{0}': {1}" }, + Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option: { code: 5038, category: DiagnosticCategory.Error, key: "Option 'mapRoot' cannot be specified without specifying 'sourcemap' option." }, + Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option: { code: 5039, category: DiagnosticCategory.Error, key: "Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option." }, + Option_noEmit_cannot_be_specified_with_option_out_or_outDir: { code: 5040, category: DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'out' or 'outDir'." }, + Option_noEmit_cannot_be_specified_with_option_declaration: { code: 5041, category: DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'declaration'." }, + Option_project_cannot_be_mixed_with_source_files_on_a_command_line: { code: 5042, category: DiagnosticCategory.Error, key: "Option 'project' cannot be mixed with source files on a command line." }, + Option_sourceMap_cannot_be_specified_with_option_separateCompilation: { code: 5043, category: DiagnosticCategory.Error, key: "Option 'sourceMap' cannot be specified with option 'separateCompilation'." }, + Option_declaration_cannot_be_specified_with_option_separateCompilation: { code: 5044, category: DiagnosticCategory.Error, key: "Option 'declaration' cannot be specified with option 'separateCompilation'." }, + Option_noEmitOnError_cannot_be_specified_with_option_separateCompilation: { code: 5045, category: DiagnosticCategory.Error, key: "Option 'noEmitOnError' cannot be specified with option 'separateCompilation'." }, + Option_out_cannot_be_specified_with_option_separateCompilation: { code: 5046, category: DiagnosticCategory.Error, key: "Option 'out' cannot be specified with option 'separateCompilation'." }, + Option_separateCompilation_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES6_or_higher: { code: 5047, category: DiagnosticCategory.Error, key: "Option 'separateCompilation' can only be used when either option'--module' is provided or option 'target' is 'ES6' or higher." }, + Concatenate_and_emit_output_to_single_file: { code: 6001, category: DiagnosticCategory.Message, key: "Concatenate and emit output to single file." }, + Generates_corresponding_d_ts_file: { code: 6002, category: DiagnosticCategory.Message, key: "Generates corresponding '.d.ts' file." }, + Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations: { code: 6003, category: DiagnosticCategory.Message, key: "Specifies the location where debugger should locate map files instead of generated locations." }, + Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations: { code: 6004, category: DiagnosticCategory.Message, key: "Specifies the location where debugger should locate TypeScript files instead of source locations." }, + Watch_input_files: { code: 6005, category: DiagnosticCategory.Message, key: "Watch input files." }, + Redirect_output_structure_to_the_directory: { code: 6006, category: DiagnosticCategory.Message, key: "Redirect output structure to the directory." }, + Do_not_erase_const_enum_declarations_in_generated_code: { code: 6007, category: DiagnosticCategory.Message, key: "Do not erase const enum declarations in generated code." }, + Do_not_emit_outputs_if_any_type_checking_errors_were_reported: { code: 6008, category: DiagnosticCategory.Message, key: "Do not emit outputs if any type checking errors were reported." }, + Do_not_emit_comments_to_output: { code: 6009, category: DiagnosticCategory.Message, key: "Do not emit comments to output." }, + Do_not_emit_outputs: { code: 6010, category: DiagnosticCategory.Message, key: "Do not emit outputs." }, + Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES6_experimental: { code: 6015, category: DiagnosticCategory.Message, key: "Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES6' (experimental)" }, + Specify_module_code_generation_Colon_commonjs_amd_or_umd: { code: 6016, category: DiagnosticCategory.Message, key: "Specify module code generation: 'commonjs', 'amd', or 'umd'." }, + Print_this_message: { code: 6017, category: DiagnosticCategory.Message, key: "Print this message." }, + Print_the_compiler_s_version: { code: 6019, category: DiagnosticCategory.Message, key: "Print the compiler's version." }, + Compile_the_project_in_the_given_directory: { code: 6020, category: DiagnosticCategory.Message, key: "Compile the project in the given directory." }, + Syntax_Colon_0: { code: 6023, category: DiagnosticCategory.Message, key: "Syntax: {0}" }, + options: { code: 6024, category: DiagnosticCategory.Message, key: "options" }, + file: { code: 6025, category: DiagnosticCategory.Message, key: "file" }, + Examples_Colon_0: { code: 6026, category: DiagnosticCategory.Message, key: "Examples: {0}" }, + Options_Colon: { code: 6027, category: DiagnosticCategory.Message, key: "Options:" }, + Version_0: { code: 6029, category: DiagnosticCategory.Message, key: "Version {0}" }, + Insert_command_line_options_and_files_from_a_file: { code: 6030, category: DiagnosticCategory.Message, key: "Insert command line options and files from a file." }, + File_change_detected_Starting_incremental_compilation: { code: 6032, category: DiagnosticCategory.Message, key: "File change detected. Starting incremental compilation..." }, + KIND: { code: 6034, category: DiagnosticCategory.Message, key: "KIND" }, + FILE: { code: 6035, category: DiagnosticCategory.Message, key: "FILE" }, + VERSION: { code: 6036, category: DiagnosticCategory.Message, key: "VERSION" }, + LOCATION: { code: 6037, category: DiagnosticCategory.Message, key: "LOCATION" }, + DIRECTORY: { code: 6038, category: DiagnosticCategory.Message, key: "DIRECTORY" }, + Compilation_complete_Watching_for_file_changes: { code: 6042, category: DiagnosticCategory.Message, key: "Compilation complete. Watching for file changes." }, + Generates_corresponding_map_file: { code: 6043, category: DiagnosticCategory.Message, key: "Generates corresponding '.map' file." }, + Compiler_option_0_expects_an_argument: { code: 6044, category: DiagnosticCategory.Error, key: "Compiler option '{0}' expects an argument." }, + Unterminated_quoted_string_in_response_file_0: { code: 6045, category: DiagnosticCategory.Error, key: "Unterminated quoted string in response file '{0}'." }, + Argument_for_module_option_must_be_commonjs_amd_or_umd: { code: 6046, category: DiagnosticCategory.Error, key: "Argument for '--module' option must be 'commonjs', 'amd', or 'umd'." }, + Argument_for_target_option_must_be_ES3_ES5_or_ES6: { code: 6047, category: DiagnosticCategory.Error, key: "Argument for '--target' option must be 'ES3', 'ES5', or 'ES6'." }, + Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1: { code: 6048, category: DiagnosticCategory.Error, key: "Locale must be of the form or -. For example '{0}' or '{1}'." }, + Unsupported_locale_0: { code: 6049, category: DiagnosticCategory.Error, key: "Unsupported locale '{0}'." }, + Unable_to_open_file_0: { code: 6050, category: DiagnosticCategory.Error, key: "Unable to open file '{0}'." }, + Corrupted_locale_file_0: { code: 6051, category: DiagnosticCategory.Error, key: "Corrupted locale file {0}." }, + Raise_error_on_expressions_and_declarations_with_an_implied_any_type: { code: 6052, category: DiagnosticCategory.Message, key: "Raise error on expressions and declarations with an implied 'any' type." }, + File_0_not_found: { code: 6053, category: DiagnosticCategory.Error, key: "File '{0}' not found." }, + File_0_must_have_extension_ts_or_d_ts: { code: 6054, category: DiagnosticCategory.Error, key: "File '{0}' must have extension '.ts' or '.d.ts'." }, + Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures: { code: 6055, category: DiagnosticCategory.Message, key: "Suppress noImplicitAny errors for indexing objects lacking index signatures." }, + Do_not_emit_declarations_for_code_that_has_an_internal_annotation: { code: 6056, category: DiagnosticCategory.Message, key: "Do not emit declarations for code that has an '@internal' annotation." }, + Preserve_new_lines_when_emitting_code: { code: 6057, category: DiagnosticCategory.Message, key: "Preserve new-lines when emitting code." }, + Specifies_the_root_directory_of_input_files_Use_to_control_the_output_directory_structure_with_outDir: { code: 6058, category: DiagnosticCategory.Message, key: "Specifies the root directory of input files. Use to control the output directory structure with --outDir." }, + File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files: { code: 6059, category: DiagnosticCategory.Error, key: "File '{0}' is not under 'rootDir' '{1}'. 'rootDir' is expected to contain all source files." }, + Variable_0_implicitly_has_an_1_type: { code: 7005, category: DiagnosticCategory.Error, key: "Variable '{0}' implicitly has an '{1}' type." }, + Parameter_0_implicitly_has_an_1_type: { code: 7006, category: DiagnosticCategory.Error, key: "Parameter '{0}' implicitly has an '{1}' type." }, + Member_0_implicitly_has_an_1_type: { code: 7008, category: DiagnosticCategory.Error, key: "Member '{0}' implicitly has an '{1}' type." }, + new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type: { code: 7009, category: DiagnosticCategory.Error, key: "'new' expression, whose target lacks a construct signature, implicitly has an 'any' type." }, + _0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type: { code: 7010, category: DiagnosticCategory.Error, key: "'{0}', which lacks return-type annotation, implicitly has an '{1}' return type." }, + Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type: { code: 7011, category: DiagnosticCategory.Error, key: "Function expression, which lacks return-type annotation, implicitly has an '{0}' return type." }, + Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: { code: 7013, category: DiagnosticCategory.Error, key: "Construct signature, which lacks return-type annotation, implicitly has an 'any' return type." }, + Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation: { code: 7016, category: DiagnosticCategory.Error, key: "Property '{0}' implicitly has type 'any', because its 'set' accessor lacks a type annotation." }, + Index_signature_of_object_type_implicitly_has_an_any_type: { code: 7017, category: DiagnosticCategory.Error, key: "Index signature of object type implicitly has an 'any' type." }, + Object_literal_s_property_0_implicitly_has_an_1_type: { code: 7018, category: DiagnosticCategory.Error, key: "Object literal's property '{0}' implicitly has an '{1}' type." }, + Rest_parameter_0_implicitly_has_an_any_type: { code: 7019, category: DiagnosticCategory.Error, key: "Rest parameter '{0}' implicitly has an 'any[]' type." }, + Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: { code: 7020, category: DiagnosticCategory.Error, key: "Call signature, which lacks return-type annotation, implicitly has an 'any' return type." }, + _0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation: { code: 7021, category: DiagnosticCategory.Error, key: "'{0}' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation." }, + _0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer: { code: 7022, category: DiagnosticCategory.Error, key: "'{0}' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer." }, + _0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7023, category: DiagnosticCategory.Error, key: "'{0}' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." }, + Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7024, category: DiagnosticCategory.Error, key: "Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." }, + You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." }, + You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library: { code: 8001, category: DiagnosticCategory.Error, key: "You cannot rename elements that are defined in the standard TypeScript library." }, + import_can_only_be_used_in_a_ts_file: { code: 8002, category: DiagnosticCategory.Error, key: "'import ... =' can only be used in a .ts file." }, + export_can_only_be_used_in_a_ts_file: { code: 8003, category: DiagnosticCategory.Error, key: "'export=' can only be used in a .ts file." }, + type_parameter_declarations_can_only_be_used_in_a_ts_file: { code: 8004, category: DiagnosticCategory.Error, key: "'type parameter declarations' can only be used in a .ts file." }, + implements_clauses_can_only_be_used_in_a_ts_file: { code: 8005, category: DiagnosticCategory.Error, key: "'implements clauses' can only be used in a .ts file." }, + interface_declarations_can_only_be_used_in_a_ts_file: { code: 8006, category: DiagnosticCategory.Error, key: "'interface declarations' can only be used in a .ts file." }, + module_declarations_can_only_be_used_in_a_ts_file: { code: 8007, category: DiagnosticCategory.Error, key: "'module declarations' can only be used in a .ts file." }, + type_aliases_can_only_be_used_in_a_ts_file: { code: 8008, category: DiagnosticCategory.Error, key: "'type aliases' can only be used in a .ts file." }, + _0_can_only_be_used_in_a_ts_file: { code: 8009, category: DiagnosticCategory.Error, key: "'{0}' can only be used in a .ts file." }, + types_can_only_be_used_in_a_ts_file: { code: 8010, category: DiagnosticCategory.Error, key: "'types' can only be used in a .ts file." }, + type_arguments_can_only_be_used_in_a_ts_file: { code: 8011, category: DiagnosticCategory.Error, key: "'type arguments' can only be used in a .ts file." }, + parameter_modifiers_can_only_be_used_in_a_ts_file: { code: 8012, category: DiagnosticCategory.Error, key: "'parameter modifiers' can only be used in a .ts file." }, + can_only_be_used_in_a_ts_file: { code: 8013, category: DiagnosticCategory.Error, key: "'?' can only be used in a .ts file." }, + property_declarations_can_only_be_used_in_a_ts_file: { code: 8014, category: DiagnosticCategory.Error, key: "'property declarations' can only be used in a .ts file." }, + enum_declarations_can_only_be_used_in_a_ts_file: { code: 8015, category: DiagnosticCategory.Error, key: "'enum declarations' can only be used in a .ts file." }, + type_assertion_expressions_can_only_be_used_in_a_ts_file: { code: 8016, category: DiagnosticCategory.Error, key: "'type assertion expressions' can only be used in a .ts file." }, + decorators_can_only_be_used_in_a_ts_file: { code: 8017, category: DiagnosticCategory.Error, key: "'decorators' can only be used in a .ts file." }, + yield_expressions_are_not_currently_supported: { code: 9000, category: DiagnosticCategory.Error, key: "'yield' expressions are not currently supported." }, + Generators_are_not_currently_supported: { code: 9001, category: DiagnosticCategory.Error, key: "Generators are not currently supported." }, + Only_identifiers_Slashqualified_names_with_optional_type_arguments_are_currently_supported_in_a_class_extends_clauses: { code: 9002, category: DiagnosticCategory.Error, key: "Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clauses." }, + class_expressions_are_not_currently_supported: { code: 9003, category: DiagnosticCategory.Error, key: "'class' expressions are not currently supported." }, + class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration: { code: 9004, category: DiagnosticCategory.Error, key: "'class' declarations are only supported directly inside a module or as a top level declaration." }, + }; +} diff --git a/lib/typescript/compiler/diagnosticMessages.json b/lib/typescript/compiler/diagnosticMessages.json new file mode 100644 index 000000000..583b05fcc --- /dev/null +++ b/lib/typescript/compiler/diagnosticMessages.json @@ -0,0 +1,2146 @@ +{ + "Unterminated string literal.": { + "category": "Error", + "code": 1002 + }, + "Identifier expected.": { + "category": "Error", + "code": 1003 + }, + "'{0}' expected.": { + "category": "Error", + "code": 1005 + }, + "A file cannot have a reference to itself.": { + "category": "Error", + "code": 1006 + }, + "Trailing comma not allowed.": { + "category": "Error", + "code": 1009 + }, + "'*/' expected.": { + "category": "Error", + "code": 1010 + }, + "Unexpected token.": { + "category": "Error", + "code": 1012 + }, + "A rest parameter must be last in a parameter list.": { + "category": "Error", + "code": 1014 + }, + "Parameter cannot have question mark and initializer.": { + "category": "Error", + "code": 1015 + }, + "A required parameter cannot follow an optional parameter.": { + "category": "Error", + "code": 1016 + }, + "An index signature cannot have a rest parameter.": { + "category": "Error", + "code": 1017 + }, + "An index signature parameter cannot have an accessibility modifier.": { + "category": "Error", + "code": 1018 + }, + "An index signature parameter cannot have a question mark.": { + "category": "Error", + "code": 1019 + }, + "An index signature parameter cannot have an initializer.": { + "category": "Error", + "code": 1020 + }, + "An index signature must have a type annotation.": { + "category": "Error", + "code": 1021 + }, + "An index signature parameter must have a type annotation.": { + "category": "Error", + "code": 1022 + }, + "An index signature parameter type must be 'string' or 'number'.": { + "category": "Error", + "code": 1023 + }, + "A class or interface declaration can only have one 'extends' clause.": { + "category": "Error", + "code": 1024 + }, + "An 'extends' clause must precede an 'implements' clause.": { + "category": "Error", + "code": 1025 + }, + "A class can only extend a single class.": { + "category": "Error", + "code": 1026 + }, + "A class declaration can only have one 'implements' clause.": { + "category": "Error", + "code": 1027 + }, + "Accessibility modifier already seen.": { + "category": "Error", + "code": 1028 + }, + "'{0}' modifier must precede '{1}' modifier.": { + "category": "Error", + "code": 1029 + }, + "'{0}' modifier already seen.": { + "category": "Error", + "code": 1030 + }, + "'{0}' modifier cannot appear on a class element.": { + "category": "Error", + "code": 1031 + }, + "An interface declaration cannot have an 'implements' clause.": { + "category": "Error", + "code": 1032 + }, + "'super' must be followed by an argument list or member access.": { + "category": "Error", + "code": 1034 + }, + "Only ambient modules can use quoted names.": { + "category": "Error", + "code": 1035 + }, + "Statements are not allowed in ambient contexts.": { + "category": "Error", + "code": 1036 + }, + "A 'declare' modifier cannot be used in an already ambient context.": { + "category": "Error", + "code": 1038 + }, + "Initializers are not allowed in ambient contexts.": { + "category": "Error", + "code": 1039 + }, + "'{0}' modifier cannot appear on a module element.": { + "category": "Error", + "code": 1044 + }, + "A 'declare' modifier cannot be used with an interface declaration.": { + "category": "Error", + "code": 1045 + }, + "A 'declare' modifier is required for a top level declaration in a .d.ts file.": { + "category": "Error", + "code": 1046 + }, + "A rest parameter cannot be optional.": { + "category": "Error", + "code": 1047 + }, + "A rest parameter cannot have an initializer.": { + "category": "Error", + "code": 1048 + }, + "A 'set' accessor must have exactly one parameter.": { + "category": "Error", + "code": 1049 + }, + "A 'set' accessor cannot have an optional parameter.": { + "category": "Error", + "code": 1051 + }, + "A 'set' accessor parameter cannot have an initializer.": { + "category": "Error", + "code": 1052 + }, + "A 'set' accessor cannot have rest parameter.": { + "category": "Error", + "code": 1053 + }, + "A 'get' accessor cannot have parameters.": { + "category": "Error", + "code": 1054 + }, + "Accessors are only available when targeting ECMAScript 5 and higher.": { + "category": "Error", + "code": 1056 + }, + "Enum member must have initializer.": { + "category": "Error", + "code": 1061 + }, + "An export assignment cannot be used in an internal module.": { + "category": "Error", + "code": 1063 + }, + "Ambient enum elements can only have integer literal initializers.": { + "category": "Error", + "code": 1066 + }, + "Unexpected token. A constructor, method, accessor, or property was expected.": { + "category": "Error", + "code": 1068 + }, + "A 'declare' modifier cannot be used with an import declaration.": { + "category": "Error", + "code": 1079 + }, + "Invalid 'reference' directive syntax.": { + "category": "Error", + "code": 1084 + }, + "Octal literals are not available when targeting ECMAScript 5 and higher.": { + "category": "Error", + "code": 1085 + }, + "An accessor cannot be declared in an ambient context.": { + "category": "Error", + "code": 1086 + }, + "'{0}' modifier cannot appear on a constructor declaration.": { + "category": "Error", + "code": 1089 + }, + "'{0}' modifier cannot appear on a parameter.": { + "category": "Error", + "code": 1090 + }, + "Only a single variable declaration is allowed in a 'for...in' statement.": { + "category": "Error", + "code": 1091 + }, + "Type parameters cannot appear on a constructor declaration.": { + "category": "Error", + "code": 1092 + }, + "Type annotation cannot appear on a constructor declaration.": { + "category": "Error", + "code": 1093 + }, + "An accessor cannot have type parameters.": { + "category": "Error", + "code": 1094 + }, + "A 'set' accessor cannot have a return type annotation.": { + "category": "Error", + "code": 1095 + }, + "An index signature must have exactly one parameter.": { + "category": "Error", + "code": 1096 + }, + "'{0}' list cannot be empty.": { + "category": "Error", + "code": 1097 + }, + "Type parameter list cannot be empty.": { + "category": "Error", + "code": 1098 + }, + "Type argument list cannot be empty.": { + "category": "Error", + "code": 1099 + }, + "Invalid use of '{0}' in strict mode.": { + "category": "Error", + "code": 1100 + }, + "'with' statements are not allowed in strict mode.": { + "category": "Error", + "code": 1101 + }, + "'delete' cannot be called on an identifier in strict mode.": { + "category": "Error", + "code": 1102 + }, + "A 'continue' statement can only be used within an enclosing iteration statement.": { + "category": "Error", + "code": 1104 + }, + "A 'break' statement can only be used within an enclosing iteration or switch statement.": { + "category": "Error", + "code": 1105 + }, + "Jump target cannot cross function boundary.": { + "category": "Error", + "code": 1107 + }, + "A 'return' statement can only be used within a function body.": { + "category": "Error", + "code": 1108 + }, + "Expression expected.": { + "category": "Error", + "code": 1109 + }, + "Type expected.": { + "category": "Error", + "code": 1110 + }, + "A class member cannot be declared optional.": { + "category": "Error", + "code": 1112 + }, + "A 'default' clause cannot appear more than once in a 'switch' statement.": { + "category": "Error", + "code": 1113 + }, + "Duplicate label '{0}'": { + "category": "Error", + "code": 1114 + }, + "A 'continue' statement can only jump to a label of an enclosing iteration statement.": { + "category": "Error", + "code": 1115 + }, + "A 'break' statement can only jump to a label of an enclosing statement.": { + "category": "Error", + "code": 1116 + }, + "An object literal cannot have multiple properties with the same name in strict mode.": { + "category": "Error", + "code": 1117 + }, + "An object literal cannot have multiple get/set accessors with the same name.": { + "category": "Error", + "code": 1118 + }, + "An object literal cannot have property and accessor with the same name.": { + "category": "Error", + "code": 1119 + }, + "An export assignment cannot have modifiers.": { + "category": "Error", + "code": 1120 + }, + "Octal literals are not allowed in strict mode.": { + "category": "Error", + "code": 1121 + }, + "A tuple type element list cannot be empty.": { + "category": "Error", + "code": 1122 + }, + "Variable declaration list cannot be empty.": { + "category": "Error", + "code": 1123 + }, + "Digit expected.": { + "category": "Error", + "code": 1124 + }, + "Hexadecimal digit expected.": { + "category": "Error", + "code": 1125 + }, + "Unexpected end of text.": { + "category": "Error", + "code": 1126 + }, + "Invalid character.": { + "category": "Error", + "code": 1127 + }, + "Declaration or statement expected.": { + "category": "Error", + "code": 1128 + }, + "Statement expected.": { + "category": "Error", + "code": 1129 + }, + "'case' or 'default' expected.": { + "category": "Error", + "code": 1130 + }, + "Property or signature expected.": { + "category": "Error", + "code": 1131 + }, + "Enum member expected.": { + "category": "Error", + "code": 1132 + }, + "Type reference expected.": { + "category": "Error", + "code": 1133 + }, + "Variable declaration expected.": { + "category": "Error", + "code": 1134 + }, + "Argument expression expected.": { + "category": "Error", + "code": 1135 + }, + "Property assignment expected.": { + "category": "Error", + "code": 1136 + }, + "Expression or comma expected.": { + "category": "Error", + "code": 1137 + }, + "Parameter declaration expected.": { + "category": "Error", + "code": 1138 + }, + "Type parameter declaration expected.": { + "category": "Error", + "code": 1139 + }, + "Type argument expected.": { + "category": "Error", + "code": 1140 + }, + "String literal expected.": { + "category": "Error", + "code": 1141 + }, + "Line break not permitted here.": { + "category": "Error", + "code": 1142 + }, + "'{' or ';' expected.": { + "category": "Error", + "code": 1144 + }, + "Modifiers not permitted on index signature members.": { + "category": "Error", + "code": 1145 + }, + "Declaration expected.": { + "category": "Error", + "code": 1146 + }, + "Import declarations in an internal module cannot reference an external module.": { + "category": "Error", + "code": 1147 + }, + "Cannot compile external modules unless the '--module' flag is provided.": { + "category": "Error", + "code": 1148 + }, + "File name '{0}' differs from already included file name '{1}' only in casing": { + "category": "Error", + "code": 1149 + }, + "'new T[]' cannot be used to create an array. Use 'new Array()' instead.": { + "category": "Error", + "code": 1150 + }, + "'var', 'let' or 'const' expected.": { + "category": "Error", + "code": 1152 + }, + "'let' declarations are only available when targeting ECMAScript 6 and higher.": { + "category": "Error", + "code": 1153 + }, + "'const' declarations are only available when targeting ECMAScript 6 and higher.": { + "category": "Error", + "code": 1154 + }, + "'const' declarations must be initialized": { + "category": "Error", + "code": 1155 + }, + "'const' declarations can only be declared inside a block.": { + "category": "Error", + "code": 1156 + }, + "'let' declarations can only be declared inside a block.": { + "category": "Error", + "code": 1157 + }, + "Unterminated template literal.": { + "category": "Error", + "code": 1160 + }, + "Unterminated regular expression literal.": { + "category": "Error", + "code": 1161 + }, + "An object member cannot be declared optional.": { + "category": "Error", + "code": 1162 + }, + "'yield' expression must be contained_within a generator declaration.": { + "category": "Error", + "code": 1163 + }, + "Computed property names are not allowed in enums.": { + "category": "Error", + "code": 1164 + }, + "A computed property name in an ambient context must directly refer to a built-in symbol.": { + "category": "Error", + "code": 1165 + }, + "A computed property name in a class property declaration must directly refer to a built-in symbol.": { + "category": "Error", + "code": 1166 + }, + "Computed property names are only available when targeting ECMAScript 6 and higher.": { + "category": "Error", + "code": 1167 + }, + "A computed property name in a method overload must directly refer to a built-in symbol.": { + "category": "Error", + "code": 1168 + }, + "A computed property name in an interface must directly refer to a built-in symbol.": { + "category": "Error", + "code": 1169 + }, + "A computed property name in a type literal must directly refer to a built-in symbol.": { + "category": "Error", + "code": 1170 + }, + "A comma expression is not allowed in a computed property name.": { + "category": "Error", + "code": 1171 + }, + "'extends' clause already seen.": { + "category": "Error", + "code": 1172 + }, + "'extends' clause must precede 'implements' clause.": { + "category": "Error", + "code": 1173 + }, + "Classes can only extend a single class.": { + "category": "Error", + "code": 1174 + }, + "'implements' clause already seen.": { + "category": "Error", + "code": 1175 + }, + "Interface declaration cannot have 'implements' clause.": { + "category": "Error", + "code": 1176 + }, + "Binary digit expected.": { + "category": "Error", + "code": 1177 + }, + "Octal digit expected.": { + "category": "Error", + "code": 1178 + }, + "Unexpected token. '{' expected.": { + "category": "Error", + "code": 1179 + }, + "Property destructuring pattern expected.": { + "category": "Error", + "code": 1180 + }, + "Array element destructuring pattern expected.": { + "category": "Error", + "code": 1181 + }, + "A destructuring declaration must have an initializer.": { + "category": "Error", + "code": 1182 + }, + "Destructuring declarations are not allowed in ambient contexts.": { + "category": "Error", + "code": 1183 + }, + "An implementation cannot be declared in ambient contexts.": { + "category": "Error", + "code": 1184 + }, + "Modifiers cannot appear here.": { + "category": "Error", + "code": 1184 + }, + "Merge conflict marker encountered.": { + "category": "Error", + "code": 1185 + }, + "A rest element cannot have an initializer.": { + "category": "Error", + "code": 1186 + }, + "A parameter property may not be a binding pattern.": { + "category": "Error", + "code": 1187 + }, + "Only a single variable declaration is allowed in a 'for...of' statement.": { + "category": "Error", + "code": 1188 + }, + "The variable declaration of a 'for...in' statement cannot have an initializer.": { + "category": "Error", + "code": 1189 + }, + "The variable declaration of a 'for...of' statement cannot have an initializer.": { + "category": "Error", + "code": 1190 + }, + "An import declaration cannot have modifiers.": { + "category": "Error", + "code": 1191 + }, + "External module '{0}' has no default export.": { + "category": "Error", + "code": 1192 + }, + "An export declaration cannot have modifiers.": { + "category": "Error", + "code": 1193 + }, + "Export declarations are not permitted in an internal module.": { + "category": "Error", + "code": 1194 + }, + "Catch clause variable name must be an identifier.": { + "category": "Error", + "code": 1195 + }, + "Catch clause variable cannot have a type annotation.": { + "category": "Error", + "code": 1196 + }, + "Catch clause variable cannot have an initializer.": { + "category": "Error", + "code": 1197 + }, + "An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive.": { + "category": "Error", + "code": 1198 + }, + "Unterminated Unicode escape sequence.": { + "category": "Error", + "code": 1199 + }, + "Line terminator not permitted before arrow.": { + "category": "Error", + "code": 1200 + }, + "Import assignment cannot be used when targeting ECMAScript 6 or higher. Consider using 'import * as ns from \"mod\"', 'import {a} from \"mod\"' or 'import d from \"mod\"' instead.": { + "category": "Error", + "code": 1202 + }, + "Export assignment cannot be used when targeting ECMAScript 6 or higher. Consider using 'export default' instead.": { + "category": "Error", + "code": 1203 + }, + "Cannot compile external modules into 'amd', 'commonjs' or 'umd' when targeting 'ES6' or higher.": { + "category": "Error", + "code": 1204 + }, + "Decorators are only available when targeting ECMAScript 5 and higher.": { + "category": "Error", + "code": 1205 + }, + "Decorators are not valid here.": { + "category": "Error", + "code": 1206 + }, + "Decorators cannot be applied to multiple get/set accessors of the same name.": { + "category": "Error", + "code": 1207 + }, + "Cannot compile non-external modules when the '--separateCompilation' flag is provided.": { + "category": "Error", + "code": 1208 + }, + "Ambient const enums are not allowed when the '--separateCompilation' flag is provided.": { + "category": "Error", + "code": 1209 + }, + "Invalid use of '{0}'. Class definitions are automatically in strict mode.": { + "category": "Error", + "code": 1210 + }, + "A class declaration without the 'default' modifier must have a name": { + "category": "Error", + "code": 1211 + }, + "Identifier expected. '{0}' is a reserved word in strict mode": { + "category": "Error", + "code": 1212 + }, + "Identifier expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode.": { + "category": "Error", + "code": 1213 + }, + "Identifier expected. '{0}' is a reserved word in strict mode. External Module is automatically in strict mode.": { + "category": "Error", + "code": 1214 + }, + "Type expected. '{0}' is a reserved word in strict mode": { + "category": "Error", + "code": 1215 + }, + "Type expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode.": { + "category": "Error", + "code": 1216 + }, + "Type expected. '{0}' is a reserved word in strict mode. Module is automatically in strict mode.": { + "category": "Error", + "code": 1217 + }, + "Duplicate identifier '{0}'.": { + "category": "Error", + "code": 2300 + }, + "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor.": { + "category": "Error", + "code": 2301 + }, + "Static members cannot reference class type parameters.": { + "category": "Error", + "code": 2302 + }, + "Circular definition of import alias '{0}'.": { + "category": "Error", + "code": 2303 + }, + "Cannot find name '{0}'.": { + "category": "Error", + "code": 2304 + }, + "Module '{0}' has no exported member '{1}'.": { + "category": "Error", + "code": 2305 + }, + "File '{0}' is not an external module.": { + "category": "Error", + "code": 2306 + }, + "Cannot find external module '{0}'.": { + "category": "Error", + "code": 2307 + }, + "A module cannot have more than one export assignment.": { + "category": "Error", + "code": 2308 + }, + "An export assignment cannot be used in a module with other exported elements.": { + "category": "Error", + "code": 2309 + }, + "Type '{0}' recursively references itself as a base type.": { + "category": "Error", + "code": 2310 + }, + "A class may only extend another class.": { + "category": "Error", + "code": 2311 + }, + "An interface may only extend a class or another interface.": { + "category": "Error", + "code": 2312 + }, + "Constraint of a type parameter cannot reference any type parameter from the same type parameter list.": { + "category": "Error", + "code": 2313 + }, + "Generic type '{0}' requires {1} type argument(s).": { + "category": "Error", + "code": 2314 + }, + "Type '{0}' is not generic.": { + "category": "Error", + "code": 2315 + }, + "Global type '{0}' must be a class or interface type.": { + "category": "Error", + "code": 2316 + }, + "Global type '{0}' must have {1} type parameter(s).": { + "category": "Error", + "code": 2317 + }, + "Cannot find global type '{0}'.": { + "category": "Error", + "code": 2318 + }, + "Named property '{0}' of types '{1}' and '{2}' are not identical.": { + "category": "Error", + "code": 2319 + }, + "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}'.": { + "category": "Error", + "code": 2320 + }, + "Excessive stack depth comparing types '{0}' and '{1}'.": { + "category": "Error", + "code": 2321 + }, + "Type '{0}' is not assignable to type '{1}'.": { + "category": "Error", + "code": 2322 + }, + "Property '{0}' is missing in type '{1}'.": { + "category": "Error", + "code": 2324 + }, + "Property '{0}' is private in type '{1}' but not in type '{2}'.": { + "category": "Error", + "code": 2325 + }, + "Types of property '{0}' are incompatible.": { + "category": "Error", + "code": 2326 + }, + "Property '{0}' is optional in type '{1}' but required in type '{2}'.": { + "category": "Error", + "code": 2327 + }, + "Types of parameters '{0}' and '{1}' are incompatible.": { + "category": "Error", + "code": 2328 + }, + "Index signature is missing in type '{0}'.": { + "category": "Error", + "code": 2329 + }, + "Index signatures are incompatible.": { + "category": "Error", + "code": 2330 + }, + "'this' cannot be referenced in a module body.": { + "category": "Error", + "code": 2331 + }, + "'this' cannot be referenced in current location.": { + "category": "Error", + "code": 2332 + }, + "'this' cannot be referenced in constructor arguments.": { + "category": "Error", + "code": 2333 + }, + "'this' cannot be referenced in a static property initializer.": { + "category": "Error", + "code": 2334 + }, + "'super' can only be referenced in a derived class.": { + "category": "Error", + "code": 2335 + }, + "'super' cannot be referenced in constructor arguments.": { + "category": "Error", + "code": 2336 + }, + "Super calls are not permitted outside constructors or in nested functions inside constructors": { + "category": "Error", + "code": 2337 + }, + "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class": { + "category": "Error", + "code": 2338 + }, + "Property '{0}' does not exist on type '{1}'.": { + "category": "Error", + "code": 2339 + }, + "Only public and protected methods of the base class are accessible via the 'super' keyword": { + "category": "Error", + "code": 2340 + }, + "Property '{0}' is private and only accessible within class '{1}'.": { + "category": "Error", + "code": 2341 + }, + "An index expression argument must be of type 'string', 'number', 'symbol, or 'any'.": { + "category": "Error", + "code": 2342 + }, + "Type '{0}' does not satisfy the constraint '{1}'.": { + "category": "Error", + "code": 2344 + }, + "Argument of type '{0}' is not assignable to parameter of type '{1}'.": { + "category": "Error", + "code": 2345 + }, + "Supplied parameters do not match any signature of call target.": { + "category": "Error", + "code": 2346 + }, + "Untyped function calls may not accept type arguments.": { + "category": "Error", + "code": 2347 + }, + "Value of type '{0}' is not callable. Did you mean to include 'new'?": { + "category": "Error", + "code": 2348 + }, + "Cannot invoke an expression whose type lacks a call signature.": { + "category": "Error", + "code": 2349 + }, + "Only a void function can be called with the 'new' keyword.": { + "category": "Error", + "code": 2350 + }, + "Cannot use 'new' with an expression whose type lacks a call or construct signature.": { + "category": "Error", + "code": 2351 + }, + "Neither type '{0}' nor type '{1}' is assignable to the other.": { + "category": "Error", + "code": 2352 + }, + "No best common type exists among return expressions.": { + "category": "Error", + "code": 2354 + }, + "A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement.": { + "category": "Error", + "code": 2355 + }, + "An arithmetic operand must be of type 'any', 'number' or an enum type.": { + "category": "Error", + "code": 2356 + }, + "The operand of an increment or decrement operator must be a variable, property or indexer.": { + "category": "Error", + "code": 2357 + }, + "The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.": { + "category": "Error", + "code": 2358 + }, + "The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type.": { + "category": "Error", + "code": 2359 + }, + "The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.": { + "category": "Error", + "code": 2360 + }, + "The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter": { + "category": "Error", + "code": 2361 + }, + "The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": { + "category": "Error", + "code": 2362 + }, + "The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": { + "category": "Error", + "code": 2363 + }, + "Invalid left-hand side of assignment expression.": { + "category": "Error", + "code": 2364 + }, + "Operator '{0}' cannot be applied to types '{1}' and '{2}'.": { + "category": "Error", + "code": 2365 + }, + "Type parameter name cannot be '{0}'": { + "category": "Error", + "code": 2368 + }, + "A parameter property is only allowed in a constructor implementation.": { + "category": "Error", + "code": 2369 + }, + "A rest parameter must be of an array type.": { + "category": "Error", + "code": 2370 + }, + "A parameter initializer is only allowed in a function or constructor implementation.": { + "category": "Error", + "code": 2371 + }, + "Parameter '{0}' cannot be referenced in its initializer.": { + "category": "Error", + "code": 2372 + }, + "Initializer of parameter '{0}' cannot reference identifier '{1}' declared after it.": { + "category": "Error", + "code": 2373 + }, + "Duplicate string index signature.": { + "category": "Error", + "code": 2374 + }, + "Duplicate number index signature.": { + "category": "Error", + "code": 2375 + }, + "A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties.": { + "category": "Error", + "code": 2376 + }, + "Constructors for derived classes must contain a 'super' call.": { + "category": "Error", + "code": 2377 + }, + "A 'get' accessor must return a value or consist of a single 'throw' statement.": { + "category": "Error", + "code": 2378 + }, + "Getter and setter accessors do not agree in visibility.": { + "category": "Error", + "code": 2379 + }, + "'get' and 'set' accessor must have the same type.": { + "category": "Error", + "code": 2380 + }, + "A signature with an implementation cannot use a string literal type.": { + "category": "Error", + "code": 2381 + }, + "Specialized overload signature is not assignable to any non-specialized signature.": { + "category": "Error", + "code": 2382 + }, + "Overload signatures must all be exported or not exported.": { + "category": "Error", + "code": 2383 + }, + "Overload signatures must all be ambient or non-ambient.": { + "category": "Error", + "code": 2384 + }, + "Overload signatures must all be public, private or protected.": { + "category": "Error", + "code": 2385 + }, + "Overload signatures must all be optional or required.": { + "category": "Error", + "code": 2386 + }, + "Function overload must be static.": { + "category": "Error", + "code": 2387 + }, + "Function overload must not be static.": { + "category": "Error", + "code": 2388 + }, + "Function implementation name must be '{0}'.": { + "category": "Error", + "code": 2389 + }, + "Constructor implementation is missing.": { + "category": "Error", + "code": 2390 + }, + "Function implementation is missing or not immediately following the declaration.": { + "category": "Error", + "code": 2391 + }, + "Multiple constructor implementations are not allowed.": { + "category": "Error", + "code": 2392 + }, + "Duplicate function implementation.": { + "category": "Error", + "code": 2393 + }, + "Overload signature is not compatible with function implementation.": { + "category": "Error", + "code": 2394 + }, + "Individual declarations in merged declaration {0} must be all exported or all local.": { + "category": "Error", + "code": 2395 + }, + "Duplicate identifier 'arguments'. Compiler uses 'arguments' to initialize rest parameters.": { + "category": "Error", + "code": 2396 + }, + "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference.": { + "category": "Error", + "code": 2399 + }, + "Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference.": { + "category": "Error", + "code": 2400 + }, + "Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.": { + "category": "Error", + "code": 2401 + }, + "Expression resolves to '_super' that compiler uses to capture base class reference.": { + "category": "Error", + "code": 2402 + }, + "Subsequent variable declarations must have the same type. Variable '{0}' must be of type '{1}', but here has type '{2}'.": { + "category": "Error", + "code": 2403 + }, + "The left-hand side of a 'for...in' statement cannot use a type annotation.": { + "category": "Error", + "code": 2404 + }, + "The left-hand side of a 'for...in' statement must be of type 'string' or 'any'.": { + "category": "Error", + "code": 2405 + }, + "Invalid left-hand side in 'for...in' statement.": { + "category": "Error", + "code": 2406 + }, + "The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter.": { + "category": "Error", + "code": 2407 + }, + "Setters cannot return a value.": { + "category": "Error", + "code": 2408 + }, + "Return type of constructor signature must be assignable to the instance type of the class": { + "category": "Error", + "code": 2409 + }, + "All symbols within a 'with' block will be resolved to 'any'.": { + "category": "Error", + "code": 2410 + }, + "Property '{0}' of type '{1}' is not assignable to string index type '{2}'.": { + "category": "Error", + "code": 2411 + }, + "Property '{0}' of type '{1}' is not assignable to numeric index type '{2}'.": { + "category": "Error", + "code": 2412 + }, + "Numeric index type '{0}' is not assignable to string index type '{1}'.": { + "category": "Error", + "code": 2413 + }, + "Class name cannot be '{0}'": { + "category": "Error", + "code": 2414 + }, + "Class '{0}' incorrectly extends base class '{1}'.": { + "category": "Error", + "code": 2415 + }, + "Class static side '{0}' incorrectly extends base class static side '{1}'.": { + "category": "Error", + "code": 2417 + }, + "Type name '{0}' in extends clause does not reference constructor function for '{0}'.": { + "category": "Error", + "code": 2419 + }, + "Class '{0}' incorrectly implements interface '{1}'.": { + "category": "Error", + "code": 2420 + }, + "A class may only implement another class or interface.": { + "category": "Error", + "code": 2422 + }, + "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member accessor.": { + "category": "Error", + "code": 2423 + }, + "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member property.": { + "category": "Error", + "code": 2424 + }, + "Class '{0}' defines instance member property '{1}', but extended class '{2}' defines it as instance member function.": { + "category": "Error", + "code": 2425 + }, + "Class '{0}' defines instance member accessor '{1}', but extended class '{2}' defines it as instance member function.": { + "category": "Error", + "code": 2426 + }, + "Interface name cannot be '{0}'": { + "category": "Error", + "code": 2427 + }, + "All declarations of an interface must have identical type parameters.": { + "category": "Error", + "code": 2428 + }, + "Interface '{0}' incorrectly extends interface '{1}'.": { + "category": "Error", + "code": 2430 + }, + "Enum name cannot be '{0}'": { + "category": "Error", + "code": 2431 + }, + "In an enum with multiple declarations, only one declaration can omit an initializer for its first enum element.": { + "category": "Error", + "code": 2432 + }, + "A module declaration cannot be in a different file from a class or function with which it is merged": { + "category": "Error", + "code": 2433 + }, + "A module declaration cannot be located prior to a class or function with which it is merged": { + "category": "Error", + "code": 2434 + }, + "Ambient external modules cannot be nested in other modules.": { + "category": "Error", + "code": 2435 + }, + "Ambient external module declaration cannot specify relative module name.": { + "category": "Error", + "code": 2436 + }, + "Module '{0}' is hidden by a local declaration with the same name": { + "category": "Error", + "code": 2437 + }, + "Import name cannot be '{0}'": { + "category": "Error", + "code": 2438 + }, + "Import or export declaration in an ambient external module declaration cannot reference external module through relative external module name.": { + "category": "Error", + "code": 2439 + }, + "Import declaration conflicts with local declaration of '{0}'": { + "category": "Error", + "code": 2440 + }, + "Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of an external module.": { + "category": "Error", + "code": 2441 + }, + "Types have separate declarations of a private property '{0}'.": { + "category": "Error", + "code": 2442 + }, + "Property '{0}' is protected but type '{1}' is not a class derived from '{2}'.": { + "category": "Error", + "code": 2443 + }, + "Property '{0}' is protected in type '{1}' but public in type '{2}'.": { + "category": "Error", + "code": 2444 + }, + "Property '{0}' is protected and only accessible within class '{1}' and its subclasses.": { + "category": "Error", + "code": 2445 + }, + "Property '{0}' is protected and only accessible through an instance of class '{1}'.": { + "category": "Error", + "code": 2446 + }, + "The '{0}' operator is not allowed for boolean types. Consider using '{1}' instead.": { + "category": "Error", + "code": 2447 + }, + "Block-scoped variable '{0}' used before its declaration.": { + "category": "Error", + "code": 2448 + }, + "The operand of an increment or decrement operator cannot be a constant.": { + "category": "Error", + "code": 2449 + }, + "Left-hand side of assignment expression cannot be a constant.": { + "category": "Error", + "code": 2450 + }, + "Cannot redeclare block-scoped variable '{0}'.": { + "category": "Error", + "code": 2451 + }, + "An enum member cannot have a numeric name.": { + "category": "Error", + "code": 2452 + }, + "The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly.": { + "category": "Error", + "code": 2453 + }, + "Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'.": { + "category": "Error", + "code": 2455 + }, + "Type alias '{0}' circularly references itself.": { + "category": "Error", + "code": 2456 + }, + "Type alias name cannot be '{0}'": { + "category": "Error", + "code": 2457 + }, + "An AMD module cannot have multiple name assignments.": { + "category": "Error", + "code": 2458 + }, + "Type '{0}' has no property '{1}' and no string index signature.": { + "category": "Error", + "code": 2459 + }, + "Type '{0}' has no property '{1}'.": { + "category": "Error", + "code": 2460 + }, + "Type '{0}' is not an array type.": { + "category": "Error", + "code": 2461 + }, + "A rest element must be last in an array destructuring pattern": { + "category": "Error", + "code": 2462 + }, + "A binding pattern parameter cannot be optional in an implementation signature.": { + "category": "Error", + "code": 2463 + }, + "A computed property name must be of type 'string', 'number', 'symbol', or 'any'.": { + "category": "Error", + "code": 2464 + }, + "'this' cannot be referenced in a computed property name.": { + "category": "Error", + "code": 2465 + }, + "'super' cannot be referenced in a computed property name.": { + "category": "Error", + "code": 2466 + }, + "A computed property name cannot reference a type parameter from its containing type.": { + "category": "Error", + "code": 2467 + }, + "Cannot find global value '{0}'.": { + "category": "Error", + "code": 2468 + }, + "The '{0}' operator cannot be applied to type 'symbol'.": { + "category": "Error", + "code": 2469 + }, + "'Symbol' reference does not refer to the global Symbol constructor object.": { + "category": "Error", + "code": 2470 + }, + "A computed property name of the form '{0}' must be of type 'symbol'.": { + "category": "Error", + "code": 2471 + }, + "Spread operator in 'new' expressions is only available when targeting ECMAScript 6 and higher.": { + "category": "Error", + "code": 2472 + }, + "Enum declarations must all be const or non-const.": { + "category": "Error", + "code": 2473 + }, + "In 'const' enum declarations member initializer must be constant expression.": { + "category": "Error", + "code": 2474 + }, + "'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment.": { + "category": "Error", + "code": 2475 + }, + "A const enum member can only be accessed using a string literal.": { + "category": "Error", + "code": 2476 + }, + "'const' enum member initializer was evaluated to a non-finite value.": { + "category": "Error", + "code": 2477 + }, + "'const' enum member initializer was evaluated to disallowed value 'NaN'.": { + "category": "Error", + "code": 2478 + }, + "Property '{0}' does not exist on 'const' enum '{1}'.": { + "category": "Error", + "code": 2479 + }, + "'let' is not allowed to be used as a name in 'let' or 'const' declarations.": { + "category": "Error", + "code": 2480 + }, + "Cannot initialize outer scoped variable '{0}' in the same scope as block scoped declaration '{1}'.": { + "category": "Error", + "code": 2481 + }, + "The left-hand side of a 'for...of' statement cannot use a type annotation.": { + "category": "Error", + "code": 2483 + }, + "Export declaration conflicts with exported declaration of '{0}'": { + "category": "Error", + "code": 2484 + }, + "The left-hand side of a 'for...of' statement cannot be a previously defined constant.": { + "category": "Error", + "code": 2485 + }, + "The left-hand side of a 'for...in' statement cannot be a previously defined constant.": { + "category": "Error", + "code": 2486 + }, + "Invalid left-hand side in 'for...of' statement.": { + "category": "Error", + "code": 2487 + }, + "Type must have a '[Symbol.iterator]()' method that returns an iterator.": { + "category": "Error", + "code": 2488 + }, + "An iterator must have a 'next()' method.": { + "category": "Error", + "code": 2489 + }, + "The type returned by the 'next()' method of an iterator must have a 'value' property.": { + "category": "Error", + "code": 2490 + }, + "The left-hand side of a 'for...in' statement cannot be a destructuring pattern.": { + "category": "Error", + "code": 2491 + }, + "Cannot redeclare identifier '{0}' in catch clause": { + "category": "Error", + "code": 2492 + }, + "Tuple type '{0}' with length '{1}' cannot be assigned to tuple with length '{2}'.": { + "category": "Error", + "code": 2493 + }, + "Using a string in a 'for...of' statement is only supported in ECMAScript 5 and higher.": { + "category": "Error", + "code": 2494 + }, + "Type '{0}' is not an array type or a string type.": { + "category": "Error", + "code": 2495 + }, + "The 'arguments' object cannot be referenced in an arrow function in ES3 and ES5. Consider using a standard function expression.": { + "category": "Error", + "code": 2496 + }, + "External module '{0}' resolves to a non-module entity and cannot be imported using this construct.": { + "category": "Error", + "code": 2497 + }, + "External module '{0}' uses 'export =' and cannot be used with 'export *'.": { + "category": "Error", + "code": 2498 + }, + "An interface can only extend an identifier/qualified-name with optional type arguments.": { + "category": "Error", + "code": 2499 + }, + "A class can only implement an identifier/qualified-name with optional type arguments.": { + "category": "Error", + "code": 2500 + }, + "A rest element cannot contain a binding pattern.": { + "category": "Error", + "code": 2501 + }, + + "Import declaration '{0}' is using private name '{1}'.": { + "category": "Error", + "code": 4000 + }, + "Type parameter '{0}' of exported class has or is using private name '{1}'.": { + "category": "Error", + "code": 4002 + }, + "Type parameter '{0}' of exported interface has or is using private name '{1}'.": { + "category": "Error", + "code": 4004 + }, + "Type parameter '{0}' of constructor signature from exported interface has or is using private name '{1}'.": { + "category": "Error", + "code": 4006 + }, + "Type parameter '{0}' of call signature from exported interface has or is using private name '{1}'.": { + "category": "Error", + "code": 4008 + }, + "Type parameter '{0}' of public static method from exported class has or is using private name '{1}'.": { + "category": "Error", + "code": 4010 + }, + "Type parameter '{0}' of public method from exported class has or is using private name '{1}'.": { + "category": "Error", + "code": 4012 + }, + "Type parameter '{0}' of method from exported interface has or is using private name '{1}'.": { + "category": "Error", + "code": 4014 + }, + "Type parameter '{0}' of exported function has or is using private name '{1}'.": { + "category": "Error", + "code": 4016 + }, + "Implements clause of exported class '{0}' has or is using private name '{1}'.": { + "category": "Error", + "code": 4019 + }, + "Extends clause of exported class '{0}' has or is using private name '{1}'.": { + "category": "Error", + "code": 4020 + }, + "Extends clause of exported interface '{0}' has or is using private name '{1}'.": { + "category": "Error", + "code": 4022 + }, + "Exported variable '{0}' has or is using name '{1}' from external module {2} but cannot be named.": { + "category": "Error", + "code": 4023 + }, + "Exported variable '{0}' has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4024 + }, + "Exported variable '{0}' has or is using private name '{1}'.": { + "category": "Error", + "code": 4025 + }, + "Public static property '{0}' of exported class has or is using name '{1}' from external module {2} but cannot be named.": { + "category": "Error", + "code": 4026 + }, + "Public static property '{0}' of exported class has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4027 + }, + "Public static property '{0}' of exported class has or is using private name '{1}'.": { + "category": "Error", + "code": 4028 + }, + "Public property '{0}' of exported class has or is using name '{1}' from external module {2} but cannot be named.": { + "category": "Error", + "code": 4029 + }, + "Public property '{0}' of exported class has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4030 + }, + "Public property '{0}' of exported class has or is using private name '{1}'.": { + "category": "Error", + "code": 4031 + }, + "Property '{0}' of exported interface has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4032 + }, + "Property '{0}' of exported interface has or is using private name '{1}'.": { + "category": "Error", + "code": 4033 + }, + "Parameter '{0}' of public static property setter from exported class has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4034 + }, + "Parameter '{0}' of public static property setter from exported class has or is using private name '{1}'.": { + "category": "Error", + "code": 4035 + }, + "Parameter '{0}' of public property setter from exported class has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4036 + }, + "Parameter '{0}' of public property setter from exported class has or is using private name '{1}'.": { + "category": "Error", + "code": 4037 + }, + "Return type of public static property getter from exported class has or is using name '{0}' from external module {1} but cannot be named.": { + "category": "Error", + "code": 4038 + }, + "Return type of public static property getter from exported class has or is using name '{0}' from private module '{1}'.": { + "category": "Error", + "code": 4039 + }, + "Return type of public static property getter from exported class has or is using private name '{0}'.": { + "category": "Error", + "code": 4040 + }, + "Return type of public property getter from exported class has or is using name '{0}' from external module {1} but cannot be named.": { + "category": "Error", + "code": 4041 + }, + "Return type of public property getter from exported class has or is using name '{0}' from private module '{1}'.": { + "category": "Error", + "code": 4042 + }, + "Return type of public property getter from exported class has or is using private name '{0}'.": { + "category": "Error", + "code": 4043 + }, + "Return type of constructor signature from exported interface has or is using name '{0}' from private module '{1}'.": { + "category": "Error", + "code": 4044 + }, + "Return type of constructor signature from exported interface has or is using private name '{0}'.": { + "category": "Error", + "code": 4045 + }, + "Return type of call signature from exported interface has or is using name '{0}' from private module '{1}'.": { + "category": "Error", + "code": 4046 + }, + "Return type of call signature from exported interface has or is using private name '{0}'.": { + "category": "Error", + "code": 4047 + }, + "Return type of index signature from exported interface has or is using name '{0}' from private module '{1}'.": { + "category": "Error", + "code": 4048 + }, + "Return type of index signature from exported interface has or is using private name '{0}'.": { + "category": "Error", + "code": 4049 + }, + "Return type of public static method from exported class has or is using name '{0}' from external module {1} but cannot be named.": { + "category": "Error", + "code": 4050 + }, + "Return type of public static method from exported class has or is using name '{0}' from private module '{1}'.": { + "category": "Error", + "code": 4051 + }, + "Return type of public static method from exported class has or is using private name '{0}'.": { + "category": "Error", + "code": 4052 + }, + "Return type of public method from exported class has or is using name '{0}' from external module {1} but cannot be named.": { + "category": "Error", + "code": 4053 + }, + "Return type of public method from exported class has or is using name '{0}' from private module '{1}'.": { + "category": "Error", + "code": 4054 + }, + "Return type of public method from exported class has or is using private name '{0}'.": { + "category": "Error", + "code": 4055 + }, + "Return type of method from exported interface has or is using name '{0}' from private module '{1}'.": { + "category": "Error", + "code": 4056 + }, + "Return type of method from exported interface has or is using private name '{0}'.": { + "category": "Error", + "code": 4057 + }, + "Return type of exported function has or is using name '{0}' from external module {1} but cannot be named.": { + "category": "Error", + "code": 4058 + }, + "Return type of exported function has or is using name '{0}' from private module '{1}'.": { + "category": "Error", + "code": 4059 + }, + "Return type of exported function has or is using private name '{0}'.": { + "category": "Error", + "code": 4060 + }, + "Parameter '{0}' of constructor from exported class has or is using name '{1}' from external module {2} but cannot be named.": { + "category": "Error", + "code": 4061 + }, + "Parameter '{0}' of constructor from exported class has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4062 + }, + "Parameter '{0}' of constructor from exported class has or is using private name '{1}'.": { + "category": "Error", + "code": 4063 + }, + "Parameter '{0}' of constructor signature from exported interface has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4064 + }, + "Parameter '{0}' of constructor signature from exported interface has or is using private name '{1}'.": { + "category": "Error", + "code": 4065 + }, + "Parameter '{0}' of call signature from exported interface has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4066 + }, + "Parameter '{0}' of call signature from exported interface has or is using private name '{1}'.": { + "category": "Error", + "code": 4067 + }, + "Parameter '{0}' of public static method from exported class has or is using name '{1}' from external module {2} but cannot be named.": { + "category": "Error", + "code": 4068 + }, + "Parameter '{0}' of public static method from exported class has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4069 + }, + "Parameter '{0}' of public static method from exported class has or is using private name '{1}'.": { + "category": "Error", + "code": 4070 + }, + "Parameter '{0}' of public method from exported class has or is using name '{1}' from external module {2} but cannot be named.": { + "category": "Error", + "code": 4071 + }, + "Parameter '{0}' of public method from exported class has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4072 + }, + "Parameter '{0}' of public method from exported class has or is using private name '{1}'.": { + "category": "Error", + "code": 4073 + }, + "Parameter '{0}' of method from exported interface has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4074 + }, + "Parameter '{0}' of method from exported interface has or is using private name '{1}'.": { + "category": "Error", + "code": 4075 + }, + "Parameter '{0}' of exported function has or is using name '{1}' from external module {2} but cannot be named.": { + "category": "Error", + "code": 4076 + }, + "Parameter '{0}' of exported function has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4077 + }, + "Parameter '{0}' of exported function has or is using private name '{1}'.": { + "category": "Error", + "code": 4078 + }, + "Exported type alias '{0}' has or is using private name '{1}'.": { + "category": "Error", + "code": 4081 + }, + "Default export of the module has or is using private name '{0}'.": { + "category": "Error", + "code": 4082 + }, + "Loop contains block-scoped variable '{0}' referenced by a function in the loop. This is only supported in ECMAScript 6 or higher.": { + "category": "Error", + "code": 4091 + }, + "The current host does not support the '{0}' option.": { + "category": "Error", + "code": 5001 + }, + "Cannot find the common subdirectory path for the input files.": { + "category": "Error", + "code": 5009 + }, + "Cannot read file '{0}': {1}": { + "category": "Error", + "code": 5012 + }, + "Unsupported file encoding.": { + "category": "Error", + "code": 5013 + }, + "Failed to parse file '{0}': {1}.": { + "category": "Error", + "code": 5014 + }, + "Unknown compiler option '{0}'.": { + "category": "Error", + "code": 5023 + }, + "Compiler option '{0}' requires a value of type {1}.": { + "category": "Error", + "code": 5024 + }, + "Could not write file '{0}': {1}": { + "category": "Error", + "code": 5033 + }, + "Option 'mapRoot' cannot be specified without specifying 'sourcemap' option.": { + "category": "Error", + "code": 5038 + }, + "Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option.": { + "category": "Error", + "code": 5039 + }, + "Option 'noEmit' cannot be specified with option 'out' or 'outDir'.": { + "category": "Error", + "code": 5040 + }, + "Option 'noEmit' cannot be specified with option 'declaration'.": { + "category": "Error", + "code": 5041 + }, + "Option 'project' cannot be mixed with source files on a command line.": { + "category": "Error", + "code": 5042 + }, + "Option 'sourceMap' cannot be specified with option 'separateCompilation'.": { + "category": "Error", + "code": 5043 + }, + "Option 'declaration' cannot be specified with option 'separateCompilation'.": { + "category": "Error", + "code": 5044 + }, + "Option 'noEmitOnError' cannot be specified with option 'separateCompilation'.": { + "category": "Error", + "code": 5045 + }, + "Option 'out' cannot be specified with option 'separateCompilation'.": { + "category": "Error", + "code": 5046 + }, + "Option 'separateCompilation' can only be used when either option'--module' is provided or option 'target' is 'ES6' or higher.": { + "category": "Error", + "code": 5047 + }, + "Concatenate and emit output to single file.": { + "category": "Message", + "code": 6001 + }, + "Generates corresponding '.d.ts' file.": { + "category": "Message", + "code": 6002 + }, + "Specifies the location where debugger should locate map files instead of generated locations.": { + "category": "Message", + "code": 6003 + }, + "Specifies the location where debugger should locate TypeScript files instead of source locations.": { + "category": "Message", + "code": 6004 + }, + "Watch input files.": { + "category": "Message", + "code": 6005 + }, + "Redirect output structure to the directory.": { + "category": "Message", + "code": 6006 + }, + "Do not erase const enum declarations in generated code.": { + "category": "Message", + "code": 6007 + }, + "Do not emit outputs if any type checking errors were reported.": { + "category": "Message", + "code": 6008 + }, + "Do not emit comments to output.": { + "category": "Message", + "code": 6009 + }, + "Do not emit outputs.": { + "category": "Message", + "code": 6010 + }, + "Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES6' (experimental)": { + "category": "Message", + "code": 6015 + }, + "Specify module code generation: 'commonjs', 'amd', or 'umd'.": { + "category": "Message", + "code": 6016 + }, + "Print this message.": { + "category": "Message", + "code": 6017 + }, + "Print the compiler's version.": { + "category": "Message", + "code": 6019 + }, + "Compile the project in the given directory.": { + "category": "Message", + "code": 6020 + }, + "Syntax: {0}": { + "category": "Message", + "code": 6023 + }, + "options": { + "category": "Message", + "code": 6024 + }, + "file": { + "category": "Message", + "code": 6025 + }, + "Examples: {0}": { + "category": "Message", + "code": 6026 + }, + "Options:": { + "category": "Message", + "code": 6027 + }, + "Version {0}": { + "category": "Message", + "code": 6029 + }, + "Insert command line options and files from a file.": { + "category": "Message", + "code": 6030 + }, + "File change detected. Starting incremental compilation...": { + "category": "Message", + "code": 6032 + }, + "KIND": { + "category": "Message", + "code": 6034 + }, + "FILE": { + "category": "Message", + "code": 6035 + }, + "VERSION": { + "category": "Message", + "code": 6036 + }, + "LOCATION": { + "category": "Message", + "code": 6037 + }, + "DIRECTORY": { + "category": "Message", + "code": 6038 + }, + "Compilation complete. Watching for file changes.": { + "category": "Message", + "code": 6042 + }, + "Generates corresponding '.map' file.": { + "category": "Message", + "code": 6043 + }, + "Compiler option '{0}' expects an argument.": { + "category": "Error", + "code": 6044 + }, + "Unterminated quoted string in response file '{0}'.": { + "category": "Error", + "code": 6045 + }, + "Argument for '--module' option must be 'commonjs', 'amd', or 'umd'.": { + "category": "Error", + "code": 6046 + }, + "Argument for '--target' option must be 'ES3', 'ES5', or 'ES6'.": { + "category": "Error", + "code": 6047 + }, + "Locale must be of the form or -. For example '{0}' or '{1}'.": { + "category": "Error", + "code": 6048 + }, + "Unsupported locale '{0}'.": { + "category": "Error", + "code": 6049 + }, + "Unable to open file '{0}'.": { + "category": "Error", + "code": 6050 + }, + "Corrupted locale file {0}.": { + "category": "Error", + "code": 6051 + }, + "Raise error on expressions and declarations with an implied 'any' type.": { + "category": "Message", + "code": 6052 + }, + "File '{0}' not found.": { + "category": "Error", + "code": 6053 + }, + "File '{0}' must have extension '.ts' or '.d.ts'.": { + "category": "Error", + "code": 6054 + }, + "Suppress noImplicitAny errors for indexing objects lacking index signatures.": { + "category": "Message", + "code": 6055 + }, + "Do not emit declarations for code that has an '@internal' annotation.": { + "category": "Message", + "code": 6056 + }, + "Preserve new-lines when emitting code.": { + "category": "Message", + "code": 6057 + }, + "Specifies the root directory of input files. Use to control the output directory structure with --outDir.": { + "category": "Message", + "code": 6058 + }, + "File '{0}' is not under 'rootDir' '{1}'. 'rootDir' is expected to contain all source files.": { + "category": "Error", + "code": 6059 + }, + + + "Variable '{0}' implicitly has an '{1}' type.": { + "category": "Error", + "code": 7005 + }, + "Parameter '{0}' implicitly has an '{1}' type.": { + "category": "Error", + "code": 7006 + }, + "Member '{0}' implicitly has an '{1}' type.": { + "category": "Error", + "code": 7008 + }, + "'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.": { + "category": "Error", + "code": 7009 + }, + "'{0}', which lacks return-type annotation, implicitly has an '{1}' return type.": { + "category": "Error", + "code": 7010 + }, + "Function expression, which lacks return-type annotation, implicitly has an '{0}' return type.": { + "category": "Error", + "code": 7011 + }, + "Construct signature, which lacks return-type annotation, implicitly has an 'any' return type.": { + "category": "Error", + "code": 7013 + }, + "Property '{0}' implicitly has type 'any', because its 'set' accessor lacks a type annotation.": { + "category": "Error", + "code": 7016 + }, + "Index signature of object type implicitly has an 'any' type.": { + "category": "Error", + "code": 7017 + }, + "Object literal's property '{0}' implicitly has an '{1}' type.": { + "category": "Error", + "code": 7018 + }, + "Rest parameter '{0}' implicitly has an 'any[]' type.": { + "category": "Error", + "code": 7019 + }, + "Call signature, which lacks return-type annotation, implicitly has an 'any' return type.": { + "category": "Error", + "code": 7020 + }, + "'{0}' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation.": { + "category": "Error", + "code": 7021 + }, + "'{0}' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer.": { + "category": "Error", + "code": 7022 + }, + "'{0}' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.": { + "category": "Error", + "code": 7023 + }, + "Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.": { + "category": "Error", + "code": 7024 + }, + "You cannot rename this element.": { + "category": "Error", + "code": 8000 + }, + "You cannot rename elements that are defined in the standard TypeScript library.": { + "category": "Error", + "code": 8001 + }, + "'import ... =' can only be used in a .ts file.": { + "category": "Error", + "code": 8002 + }, + "'export=' can only be used in a .ts file.": { + "category": "Error", + "code": 8003 + }, + "'type parameter declarations' can only be used in a .ts file.": { + "category": "Error", + "code": 8004 + }, + "'implements clauses' can only be used in a .ts file.": { + "category": "Error", + "code": 8005 + }, + "'interface declarations' can only be used in a .ts file.": { + "category": "Error", + "code": 8006 + }, + "'module declarations' can only be used in a .ts file.": { + "category": "Error", + "code": 8007 + }, + "'type aliases' can only be used in a .ts file.": { + "category": "Error", + "code": 8008 + }, + "'{0}' can only be used in a .ts file.": { + "category": "Error", + "code": 8009 + }, + "'types' can only be used in a .ts file.": { + "category": "Error", + "code": 8010 + }, + "'type arguments' can only be used in a .ts file.": { + "category": "Error", + "code": 8011 + }, + "'parameter modifiers' can only be used in a .ts file.": { + "category": "Error", + "code": 8012 + }, + "'?' can only be used in a .ts file.": { + "category": "Error", + "code": 8013 + }, + "'property declarations' can only be used in a .ts file.": { + "category": "Error", + "code": 8014 + }, + "'enum declarations' can only be used in a .ts file.": { + "category": "Error", + "code": 8015 + }, + "'type assertion expressions' can only be used in a .ts file.": { + "category": "Error", + "code": 8016 + }, + "'decorators' can only be used in a .ts file.": { + "category": "Error", + "code": 8017 + }, + + "'yield' expressions are not currently supported.": { + "category": "Error", + "code": 9000 + }, + "Generators are not currently supported.": { + "category": "Error", + "code": 9001 + }, + "Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clauses.": { + "category": "Error", + "code": 9002 + }, + "'class' expressions are not currently supported.": { + "category": "Error", + "code": 9003 + }, + "'class' declarations are only supported directly inside a module or as a top level declaration.": { + "category": "Error", + "code": 9004 + } +} diff --git a/lib/typescript/compiler/emitter.ts b/lib/typescript/compiler/emitter.ts new file mode 100644 index 000000000..7c1da2005 --- /dev/null +++ b/lib/typescript/compiler/emitter.ts @@ -0,0 +1,5274 @@ +/// +/// + +/* @internal */ +module ts { + // represents one LexicalEnvironment frame to store unique generated names + interface ScopeFrame { + names: Map; + previous: ScopeFrame; + } + + export function isExternalModuleOrDeclarationFile(sourceFile: SourceFile) { + return isExternalModule(sourceFile) || isDeclarationFile(sourceFile); + } + + // Flags enum to track count of temp variables and a few dedicated names + const enum TempFlags { + Auto = 0x00000000, // No preferred name + CountMask = 0x0FFFFFFF, // Temp variable counter + _i = 0x10000000, // Use/preference flag for '_i' + _n = 0x20000000, // Use/preference flag for '_n' + } + + // targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature + export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult { + // emit output for the __extends helper function + const extendsHelper = ` +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +};`; + + // emit output for the __decorate helper function + const decorateHelper = ` +if (typeof __decorate !== "function") __decorate = function (decorators, target, key, desc) { + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc); + switch (arguments.length) { + case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target); + case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0); + case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc); + } +};`; + + // emit output for the __metadata helper function + const metadataHelper = ` +if (typeof __metadata !== "function") __metadata = function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +};`; + + // emit output for the __param helper function + const paramHelper = ` +if (typeof __param !== "function") __param = function (paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +};`; + + let compilerOptions = host.getCompilerOptions(); + let languageVersion = compilerOptions.target || ScriptTarget.ES3; + let sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap ? [] : undefined; + let diagnostics: Diagnostic[] = []; + let newLine = host.getNewLine(); + + if (targetSourceFile === undefined) { + forEach(host.getSourceFiles(), sourceFile => { + if (shouldEmitToOwnFile(sourceFile, compilerOptions)) { + let jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, ".js"); + emitFile(jsFilePath, sourceFile); + } + }); + + if (compilerOptions.out) { + emitFile(compilerOptions.out); + } + } + else { + // targetSourceFile is specified (e.g calling emitter from language service or calling getSemanticDiagnostic from language service) + if (shouldEmitToOwnFile(targetSourceFile, compilerOptions)) { + let jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, host, ".js"); + emitFile(jsFilePath, targetSourceFile); + } + else if (!isDeclarationFile(targetSourceFile) && compilerOptions.out) { + emitFile(compilerOptions.out); + } + } + + // Sort and make the unique list of diagnostics + diagnostics = sortAndDeduplicateDiagnostics(diagnostics); + + return { + emitSkipped: false, + diagnostics, + sourceMaps: sourceMapDataList + }; + + function isNodeDescendentOf(node: Node, ancestor: Node): boolean { + while (node) { + if (node === ancestor) return true; + node = node.parent; + } + return false; + } + + function isUniqueLocalName(name: string, container: Node): boolean { + for (let node = container; isNodeDescendentOf(node, container); node = node.nextContainer) { + if (node.locals && hasProperty(node.locals, name)) { + // We conservatively include alias symbols to cover cases where they're emitted as locals + if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) { + return false; + } + } + } + return true; + } + + function emitJavaScript(jsFilePath: string, root?: SourceFile) { + let writer = createTextWriter(newLine); + let write = writer.write; + let writeTextOfNode = writer.writeTextOfNode; + let writeLine = writer.writeLine; + let increaseIndent = writer.increaseIndent; + let decreaseIndent = writer.decreaseIndent; + + let currentSourceFile: SourceFile; + + let generatedNameSet: Map = {}; + let nodeToGeneratedName: string[] = []; + let blockScopedVariableToGeneratedName: string[]; + let computedPropertyNamesToGeneratedNames: string[]; + + let extendsEmitted = false; + let decorateEmitted = false; + let paramEmitted = false; + let tempFlags = 0; + let tempVariables: Identifier[]; + let tempParameters: Identifier[]; + let externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; + let exportSpecifiers: Map; + let exportEquals: ExportAssignment; + let hasExportStars: boolean; + + /** write emitted output to disk*/ + let writeEmittedFiles = writeJavaScriptFile; + + let detachedCommentsInfo: { nodePos: number; detachedCommentEndPos: number }[]; + + let writeComment = writeCommentRange; + + /** Emit a node */ + let emit = emitNodeWithoutSourceMap; + + /** Called just before starting emit of a node */ + let emitStart = function (node: Node) { }; + + /** Called once the emit of the node is done */ + let emitEnd = function (node: Node) { }; + + /** Emit the text for the given token that comes after startPos + * This by default writes the text provided with the given tokenKind + * but if optional emitFn callback is provided the text is emitted using the callback instead of default text + * @param tokenKind the kind of the token to search and emit + * @param startPos the position in the source to start searching for the token + * @param emitFn if given will be invoked to emit the text instead of actual token emit */ + let emitToken = emitTokenText; + + /** Called to before starting the lexical scopes as in function/class in the emitted code because of node + * @param scopeDeclaration node that starts the lexical scope + * @param scopeName Optional name of this scope instead of deducing one from the declaration node */ + let scopeEmitStart = function (scopeDeclaration: Node, scopeName?: string) { } + + /** Called after coming out of the scope */ + let scopeEmitEnd = function () { } + + /** Sourcemap data that will get encoded */ + let sourceMapData: SourceMapData; + + if (compilerOptions.sourceMap) { + initializeEmitterWithSourceMaps(); + } + + if (root) { + // Do not call emit directly. It does not set the currentSourceFile. + emitSourceFile(root); + } + else { + forEach(host.getSourceFiles(), sourceFile => { + if (!isExternalModuleOrDeclarationFile(sourceFile)) { + emitSourceFile(sourceFile); + } + }); + } + + writeLine(); + writeEmittedFiles(writer.getText(), /*writeByteOrderMark*/ compilerOptions.emitBOM); + return; + + function emitSourceFile(sourceFile: SourceFile): void { + currentSourceFile = sourceFile; + emit(sourceFile); + } + + function isUniqueName(name: string): boolean { + return !resolver.hasGlobalName(name) && + !hasProperty(currentSourceFile.identifiers, name) && + !hasProperty(generatedNameSet, name); + } + + // Return the next available name in the pattern _a ... _z, _0, _1, ... + // TempFlags._i or TempFlags._n may be used to express a preference for that dedicated name. + // Note that names generated by makeTempVariableName and makeUniqueName will never conflict. + function makeTempVariableName(flags: TempFlags): string { + if (flags && !(tempFlags & flags)) { + var name = flags === TempFlags._i ? "_i" : "_n" + if (isUniqueName(name)) { + tempFlags |= flags; + return name; + } + } + while (true) { + let count = tempFlags & TempFlags.CountMask; + tempFlags++; + // Skip over 'i' and 'n' + if (count !== 8 && count !== 13) { + let name = count < 26 ? "_" + String.fromCharCode(CharacterCodes.a + count) : "_" + (count - 26); + if (isUniqueName(name)) { + return name; + } + } + } + } + + // Generate a name that is unique within the current file and doesn't conflict with any names + // in global scope. The name is formed by adding an '_n' suffix to the specified base name, + // where n is a positive integer. Note that names generated by makeTempVariableName and + // makeUniqueName are guaranteed to never conflict. + function makeUniqueName(baseName: string): string { + // Find the first unique 'name_n', where n is a positive number + if (baseName.charCodeAt(baseName.length - 1) !== CharacterCodes._) { + baseName += "_"; + } + let i = 1; + while (true) { + let generatedName = baseName + i; + if (isUniqueName(generatedName)) { + return generatedNameSet[generatedName] = generatedName; + } + i++; + } + } + + function assignGeneratedName(node: Node, name: string) { + nodeToGeneratedName[getNodeId(node)] = unescapeIdentifier(name); + } + + function generateNameForFunctionOrClassDeclaration(node: Declaration) { + if (!node.name) { + assignGeneratedName(node, makeUniqueName("default")); + } + } + + function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { + if (node.name.kind === SyntaxKind.Identifier) { + let name = node.name.text; + // Use module/enum name itself if it is unique, otherwise make a unique variation + assignGeneratedName(node, isUniqueLocalName(name, node) ? name : makeUniqueName(name)); + } + } + + function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) { + let expr = getExternalModuleName(node); + let baseName = expr.kind === SyntaxKind.StringLiteral ? + escapeIdentifier(makeIdentifierFromModuleName((expr).text)) : "module"; + assignGeneratedName(node, makeUniqueName(baseName)); + } + + function generateNameForImportDeclaration(node: ImportDeclaration) { + if (node.importClause) { + generateNameForImportOrExportDeclaration(node); + } + } + + function generateNameForExportDeclaration(node: ExportDeclaration) { + if (node.moduleSpecifier) { + generateNameForImportOrExportDeclaration(node); + } + } + + function generateNameForExportAssignment(node: ExportAssignment) { + if (node.expression && node.expression.kind !== SyntaxKind.Identifier) { + assignGeneratedName(node, makeUniqueName("default")); + } + } + + function generateNameForNode(node: Node) { + switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + generateNameForFunctionOrClassDeclaration(node); + break; + case SyntaxKind.ModuleDeclaration: + generateNameForModuleOrEnum(node); + generateNameForNode((node).body); + break; + case SyntaxKind.EnumDeclaration: + generateNameForModuleOrEnum(node); + break; + case SyntaxKind.ImportDeclaration: + generateNameForImportDeclaration(node); + break; + case SyntaxKind.ExportDeclaration: + generateNameForExportDeclaration(node); + break; + case SyntaxKind.ExportAssignment: + generateNameForExportAssignment(node); + break; + } + } + + function getGeneratedNameForNode(node: Node) { + let nodeId = getNodeId(node); + if (!nodeToGeneratedName[nodeId]) { + generateNameForNode(node); + } + return nodeToGeneratedName[nodeId]; + } + + function initializeEmitterWithSourceMaps() { + let sourceMapDir: string; // The directory in which sourcemap will be + + // Current source map file and its index in the sources list + let sourceMapSourceIndex = -1; + + // Names and its index map + let sourceMapNameIndexMap: Map = {}; + let sourceMapNameIndices: number[] = []; + function getSourceMapNameIndex() { + return sourceMapNameIndices.length ? sourceMapNameIndices[sourceMapNameIndices.length - 1] : -1; + } + + // Last recorded and encoded spans + let lastRecordedSourceMapSpan: SourceMapSpan; + let lastEncodedSourceMapSpan: SourceMapSpan = { + emittedLine: 1, + emittedColumn: 1, + sourceLine: 1, + sourceColumn: 1, + sourceIndex: 0 + }; + let lastEncodedNameIndex = 0; + + // Encoding for sourcemap span + function encodeLastRecordedSourceMapSpan() { + if (!lastRecordedSourceMapSpan || lastRecordedSourceMapSpan === lastEncodedSourceMapSpan) { + return; + } + + let prevEncodedEmittedColumn = lastEncodedSourceMapSpan.emittedColumn; + // Line/Comma delimiters + if (lastEncodedSourceMapSpan.emittedLine == lastRecordedSourceMapSpan.emittedLine) { + // Emit comma to separate the entry + if (sourceMapData.sourceMapMappings) { + sourceMapData.sourceMapMappings += ","; + } + } + else { + // Emit line delimiters + for (let encodedLine = lastEncodedSourceMapSpan.emittedLine; encodedLine < lastRecordedSourceMapSpan.emittedLine; encodedLine++) { + sourceMapData.sourceMapMappings += ";"; + } + prevEncodedEmittedColumn = 1; + } + + // 1. Relative Column 0 based + sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.emittedColumn - prevEncodedEmittedColumn); + + // 2. Relative sourceIndex + sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceIndex - lastEncodedSourceMapSpan.sourceIndex); + + // 3. Relative sourceLine 0 based + sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceLine - lastEncodedSourceMapSpan.sourceLine); + + // 4. Relative sourceColumn 0 based + sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceColumn - lastEncodedSourceMapSpan.sourceColumn); + + // 5. Relative namePosition 0 based + if (lastRecordedSourceMapSpan.nameIndex >= 0) { + sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.nameIndex - lastEncodedNameIndex); + lastEncodedNameIndex = lastRecordedSourceMapSpan.nameIndex; + } + + lastEncodedSourceMapSpan = lastRecordedSourceMapSpan; + sourceMapData.sourceMapDecodedMappings.push(lastEncodedSourceMapSpan); + + function base64VLQFormatEncode(inValue: number) { + function base64FormatEncode(inValue: number) { + if (inValue < 64) { + return 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charAt(inValue); + } + throw TypeError(inValue + ": not a 64 based value"); + } + + // Add a new least significant bit that has the sign of the value. + // if negative number the least significant bit that gets added to the number has value 1 + // else least significant bit value that gets added is 0 + // eg. -1 changes to binary : 01 [1] => 3 + // +1 changes to binary : 01 [0] => 2 + if (inValue < 0) { + inValue = ((-inValue) << 1) + 1; + } + else { + inValue = inValue << 1; + } + + // Encode 5 bits at a time starting from least significant bits + let encodedStr = ""; + do { + let currentDigit = inValue & 31; // 11111 + inValue = inValue >> 5; + if (inValue > 0) { + // There are still more digits to decode, set the msb (6th bit) + currentDigit = currentDigit | 32; + } + encodedStr = encodedStr + base64FormatEncode(currentDigit); + } while (inValue > 0); + + return encodedStr; + } + } + + function recordSourceMapSpan(pos: number) { + let sourceLinePos = getLineAndCharacterOfPosition(currentSourceFile, pos); + + // Convert the location to be one-based. + sourceLinePos.line++; + sourceLinePos.character++; + + let emittedLine = writer.getLine(); + let emittedColumn = writer.getColumn(); + + // If this location wasn't recorded or the location in source is going backwards, record the span + if (!lastRecordedSourceMapSpan || + lastRecordedSourceMapSpan.emittedLine != emittedLine || + lastRecordedSourceMapSpan.emittedColumn != emittedColumn || + (lastRecordedSourceMapSpan.sourceIndex === sourceMapSourceIndex && + (lastRecordedSourceMapSpan.sourceLine > sourceLinePos.line || + (lastRecordedSourceMapSpan.sourceLine === sourceLinePos.line && lastRecordedSourceMapSpan.sourceColumn > sourceLinePos.character)))) { + // Encode the last recordedSpan before assigning new + encodeLastRecordedSourceMapSpan(); + + // New span + lastRecordedSourceMapSpan = { + emittedLine: emittedLine, + emittedColumn: emittedColumn, + sourceLine: sourceLinePos.line, + sourceColumn: sourceLinePos.character, + nameIndex: getSourceMapNameIndex(), + sourceIndex: sourceMapSourceIndex + }; + } + else { + // Take the new pos instead since there is no change in emittedLine and column since last location + lastRecordedSourceMapSpan.sourceLine = sourceLinePos.line; + lastRecordedSourceMapSpan.sourceColumn = sourceLinePos.character; + lastRecordedSourceMapSpan.sourceIndex = sourceMapSourceIndex; + } + } + + function recordEmitNodeStartSpan(node: Node) { + // Get the token pos after skipping to the token (ignoring the leading trivia) + recordSourceMapSpan(skipTrivia(currentSourceFile.text, node.pos)); + } + + function recordEmitNodeEndSpan(node: Node) { + recordSourceMapSpan(node.end); + } + + function writeTextWithSpanRecord(tokenKind: SyntaxKind, startPos: number, emitFn?: () => void) { + let tokenStartPos = ts.skipTrivia(currentSourceFile.text, startPos); + recordSourceMapSpan(tokenStartPos); + let tokenEndPos = emitTokenText(tokenKind, tokenStartPos, emitFn); + recordSourceMapSpan(tokenEndPos); + return tokenEndPos; + } + + function recordNewSourceFileStart(node: SourceFile) { + // Add the file to tsFilePaths + // If sourceroot option: Use the relative path corresponding to the common directory path + // otherwise source locations relative to map file location + let sourcesDirectoryPath = compilerOptions.sourceRoot ? host.getCommonSourceDirectory() : sourceMapDir; + + sourceMapData.sourceMapSources.push(getRelativePathToDirectoryOrUrl(sourcesDirectoryPath, + node.fileName, + host.getCurrentDirectory(), + host.getCanonicalFileName, + /*isAbsolutePathAnUrl*/ true)); + sourceMapSourceIndex = sourceMapData.sourceMapSources.length - 1; + + // The one that can be used from program to get the actual source file + sourceMapData.inputSourceFileNames.push(node.fileName); + } + + function recordScopeNameOfNode(node: Node, scopeName?: string) { + function recordScopeNameIndex(scopeNameIndex: number) { + sourceMapNameIndices.push(scopeNameIndex); + } + + function recordScopeNameStart(scopeName: string) { + let scopeNameIndex = -1; + if (scopeName) { + let parentIndex = getSourceMapNameIndex(); + if (parentIndex !== -1) { + // Child scopes are always shown with a dot (even if they have no name), + // unless it is a computed property. Then it is shown with brackets, + // but the brackets are included in the name. + let name = (node).name; + if (!name || name.kind !== SyntaxKind.ComputedPropertyName) { + scopeName = "." + scopeName; + } + scopeName = sourceMapData.sourceMapNames[parentIndex] + scopeName; + } + + scopeNameIndex = getProperty(sourceMapNameIndexMap, scopeName); + if (scopeNameIndex === undefined) { + scopeNameIndex = sourceMapData.sourceMapNames.length; + sourceMapData.sourceMapNames.push(scopeName); + sourceMapNameIndexMap[scopeName] = scopeNameIndex; + } + } + recordScopeNameIndex(scopeNameIndex); + } + + if (scopeName) { + // The scope was already given a name use it + recordScopeNameStart(scopeName); + } + else if (node.kind === SyntaxKind.FunctionDeclaration || + node.kind === SyntaxKind.FunctionExpression || + node.kind === SyntaxKind.MethodDeclaration || + node.kind === SyntaxKind.MethodSignature || + node.kind === SyntaxKind.GetAccessor || + node.kind === SyntaxKind.SetAccessor || + node.kind === SyntaxKind.ModuleDeclaration || + node.kind === SyntaxKind.ClassDeclaration || + node.kind === SyntaxKind.EnumDeclaration) { + // Declaration and has associated name use it + if ((node).name) { + let name = (node).name; + // For computed property names, the text will include the brackets + scopeName = name.kind === SyntaxKind.ComputedPropertyName + ? getTextOfNode(name) + : ((node).name).text; + } + recordScopeNameStart(scopeName); + } + else { + // Block just use the name from upper level scope + recordScopeNameIndex(getSourceMapNameIndex()); + } + } + + function recordScopeNameEnd() { + sourceMapNameIndices.pop(); + }; + + function writeCommentRangeWithMap(curentSourceFile: SourceFile, writer: EmitTextWriter, comment: CommentRange, newLine: string) { + recordSourceMapSpan(comment.pos); + writeCommentRange(currentSourceFile, writer, comment, newLine); + recordSourceMapSpan(comment.end); + } + + function serializeSourceMapContents(version: number, file: string, sourceRoot: string, sources: string[], names: string[], mappings: string) { + if (typeof JSON !== "undefined") { + return JSON.stringify({ + version: version, + file: file, + sourceRoot: sourceRoot, + sources: sources, + names: names, + mappings: mappings + }); + } + + return "{\"version\":" + version + ",\"file\":\"" + escapeString(file) + "\",\"sourceRoot\":\"" + escapeString(sourceRoot) + "\",\"sources\":[" + serializeStringArray(sources) + "],\"names\":[" + serializeStringArray(names) + "],\"mappings\":\"" + escapeString(mappings) + "\"}"; + + function serializeStringArray(list: string[]): string { + let output = ""; + for (let i = 0, n = list.length; i < n; i++) { + if (i) { + output += ","; + } + output += "\"" + escapeString(list[i]) + "\""; + } + return output; + } + } + + function writeJavaScriptAndSourceMapFile(emitOutput: string, writeByteOrderMark: boolean) { + // Write source map file + encodeLastRecordedSourceMapSpan(); + writeFile(host, diagnostics, sourceMapData.sourceMapFilePath, serializeSourceMapContents( + 3, + sourceMapData.sourceMapFile, + sourceMapData.sourceMapSourceRoot, + sourceMapData.sourceMapSources, + sourceMapData.sourceMapNames, + sourceMapData.sourceMapMappings), /*writeByteOrderMark*/ false); + sourceMapDataList.push(sourceMapData); + + // Write sourcemap url to the js file and write the js file + writeJavaScriptFile(emitOutput + "//# sourceMappingURL=" + sourceMapData.jsSourceMappingURL, writeByteOrderMark); + } + + // Initialize source map data + let sourceMapJsFile = getBaseFileName(normalizeSlashes(jsFilePath)); + sourceMapData = { + sourceMapFilePath: jsFilePath + ".map", + jsSourceMappingURL: sourceMapJsFile + ".map", + sourceMapFile: sourceMapJsFile, + sourceMapSourceRoot: compilerOptions.sourceRoot || "", + sourceMapSources: [], + inputSourceFileNames: [], + sourceMapNames: [], + sourceMapMappings: "", + sourceMapDecodedMappings: [] + }; + + // Normalize source root and make sure it has trailing "/" so that it can be used to combine paths with the + // relative paths of the sources list in the sourcemap + sourceMapData.sourceMapSourceRoot = ts.normalizeSlashes(sourceMapData.sourceMapSourceRoot); + if (sourceMapData.sourceMapSourceRoot.length && sourceMapData.sourceMapSourceRoot.charCodeAt(sourceMapData.sourceMapSourceRoot.length - 1) !== CharacterCodes.slash) { + sourceMapData.sourceMapSourceRoot += directorySeparator; + } + + if (compilerOptions.mapRoot) { + sourceMapDir = normalizeSlashes(compilerOptions.mapRoot); + if (root) { // emitting single module file + // For modules or multiple emit files the mapRoot will have directory structure like the sources + // So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map + sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(root, host, sourceMapDir)); + } + + if (!isRootedDiskPath(sourceMapDir) && !isUrl(sourceMapDir)) { + // The relative paths are relative to the common directory + sourceMapDir = combinePaths(host.getCommonSourceDirectory(), sourceMapDir); + sourceMapData.jsSourceMappingURL = getRelativePathToDirectoryOrUrl( + getDirectoryPath(normalizePath(jsFilePath)), // get the relative sourceMapDir path based on jsFilePath + combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL), // this is where user expects to see sourceMap + host.getCurrentDirectory(), + host.getCanonicalFileName, + /*isAbsolutePathAnUrl*/ true); + } + else { + sourceMapData.jsSourceMappingURL = combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL); + } + } + else { + sourceMapDir = getDirectoryPath(normalizePath(jsFilePath)); + } + + function emitNodeWithSourceMap(node: Node, allowGeneratedIdentifiers?: boolean) { + if (node) { + if (nodeIsSynthesized(node)) { + return emitNodeWithoutSourceMap(node, /*allowGeneratedIdentifiers*/ false); + } + if (node.kind != SyntaxKind.SourceFile) { + recordEmitNodeStartSpan(node); + emitNodeWithoutSourceMap(node, allowGeneratedIdentifiers); + recordEmitNodeEndSpan(node); + } + else { + recordNewSourceFileStart(node); + emitNodeWithoutSourceMap(node, /*allowGeneratedIdentifiers*/ false); + } + } + } + + writeEmittedFiles = writeJavaScriptAndSourceMapFile; + emit = emitNodeWithSourceMap; + emitStart = recordEmitNodeStartSpan; + emitEnd = recordEmitNodeEndSpan; + emitToken = writeTextWithSpanRecord; + scopeEmitStart = recordScopeNameOfNode; + scopeEmitEnd = recordScopeNameEnd; + writeComment = writeCommentRangeWithMap; + } + + function writeJavaScriptFile(emitOutput: string, writeByteOrderMark: boolean) { + writeFile(host, diagnostics, jsFilePath, emitOutput, writeByteOrderMark); + } + + // Create a temporary variable with a unique unused name. + function createTempVariable(flags: TempFlags): Identifier { + let result = createSynthesizedNode(SyntaxKind.Identifier); + result.text = makeTempVariableName(flags); + return result; + } + + function recordTempDeclaration(name: Identifier): void { + if (!tempVariables) { + tempVariables = []; + } + tempVariables.push(name); + } + + function createAndRecordTempVariable(flags: TempFlags): Identifier { + let temp = createTempVariable(flags); + recordTempDeclaration(temp); + + return temp; + } + + function emitTempDeclarations(newLine: boolean) { + if (tempVariables) { + if (newLine) { + writeLine(); + } + else { + write(" "); + } + write("var "); + emitCommaList(tempVariables); + write(";"); + } + } + + function emitTokenText(tokenKind: SyntaxKind, startPos: number, emitFn?: () => void) { + let tokenString = tokenToString(tokenKind); + if (emitFn) { + emitFn(); + } + else { + write(tokenString); + } + return startPos + tokenString.length; + } + + function emitOptional(prefix: string, node: Node) { + if (node) { + write(prefix); + emit(node); + } + } + + function emitParenthesizedIf(node: Node, parenthesized: boolean) { + if (parenthesized) { + write("("); + } + emit(node); + if (parenthesized) { + write(")"); + } + } + + function emitTrailingCommaIfPresent(nodeList: NodeArray): void { + if (nodeList.hasTrailingComma) { + write(","); + } + } + + function emitLinePreservingList(parent: Node, nodes: NodeArray, allowTrailingComma: boolean, spacesBetweenBraces: boolean) { + Debug.assert(nodes.length > 0); + + increaseIndent(); + + if (nodeStartPositionsAreOnSameLine(parent, nodes[0])) { + if (spacesBetweenBraces) { + write(" "); + } + } + else { + writeLine(); + } + + for (let i = 0, n = nodes.length; i < n; i++) { + if (i) { + if (nodeEndIsOnSameLineAsNodeStart(nodes[i - 1], nodes[i])) { + write(", "); + } + else { + write(","); + writeLine(); + } + } + + emit(nodes[i]); + } + + if (nodes.hasTrailingComma && allowTrailingComma) { + write(","); + } + + decreaseIndent(); + + if (nodeEndPositionsAreOnSameLine(parent, lastOrUndefined(nodes))) { + if (spacesBetweenBraces) { + write(" "); + } + } + else { + writeLine(); + } + } + + function emitList(nodes: TNode[], start: number, count: number, multiLine: boolean, trailingComma: boolean, leadingComma?: boolean, noTrailingNewLine?: boolean, emitNode?: (node: TNode) => void): number { + if (!emitNode) { + emitNode = emit; + } + + for (let i = 0; i < count; i++) { + if (multiLine) { + if (i || leadingComma) { + write(","); + } + writeLine(); + } + else { + if (i || leadingComma) { + write(", "); + } + } + emitNode(nodes[start + i]); + leadingComma = true; + } + if (trailingComma) { + write(","); + } + if (multiLine && !noTrailingNewLine) { + writeLine(); + } + + return count; + } + + function emitCommaList(nodes: Node[]) { + if (nodes) { + emitList(nodes, 0, nodes.length, /*multiline*/ false, /*trailingComma*/ false); + } + } + + function emitLines(nodes: Node[]) { + emitLinesStartingAt(nodes, /*startIndex*/ 0); + } + + function emitLinesStartingAt(nodes: Node[], startIndex: number): void { + for (let i = startIndex; i < nodes.length; i++) { + writeLine(); + emit(nodes[i]); + } + } + + function isBinaryOrOctalIntegerLiteral(node: LiteralExpression, text: string): boolean { + if (node.kind === SyntaxKind.NumericLiteral && text.length > 1) { + switch (text.charCodeAt(1)) { + case CharacterCodes.b: + case CharacterCodes.B: + case CharacterCodes.o: + case CharacterCodes.O: + return true; + } + } + + return false; + } + + function emitLiteral(node: LiteralExpression) { + let text = getLiteralText(node); + + if (compilerOptions.sourceMap && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { + writer.writeLiteral(text); + } + // For versions below ES6, emit binary & octal literals in their canonical decimal form. + else if (languageVersion < ScriptTarget.ES6 && isBinaryOrOctalIntegerLiteral(node, text)) { + write(node.text); + } + else { + write(text); + } + } + + function getLiteralText(node: LiteralExpression) { + // Any template literal or string literal with an extended escape + // (e.g. "\u{0067}") will need to be downleveled as a escaped string literal. + if (languageVersion < ScriptTarget.ES6 && (isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape)) { + return getQuotedEscapedLiteralText('"', node.text, '"'); + } + + // If we don't need to downlevel and we can reach the original source text using + // the node's parent reference, then simply get the text as it was originally written. + if (node.parent) { + return getSourceTextOfNodeFromSourceFile(currentSourceFile, node); + } + + // If we can't reach the original source text, use the canonical form if it's a number, + // or an escaped quoted form of the original text if it's string-like. + switch (node.kind) { + case SyntaxKind.StringLiteral: + return getQuotedEscapedLiteralText('"', node.text, '"'); + case SyntaxKind.NoSubstitutionTemplateLiteral: + return getQuotedEscapedLiteralText('`', node.text, '`'); + case SyntaxKind.TemplateHead: + return getQuotedEscapedLiteralText('`', node.text, '${'); + case SyntaxKind.TemplateMiddle: + return getQuotedEscapedLiteralText('}', node.text, '${'); + case SyntaxKind.TemplateTail: + return getQuotedEscapedLiteralText('}', node.text, '`'); + case SyntaxKind.NumericLiteral: + return node.text; + } + + Debug.fail(`Literal kind '${node.kind}' not accounted for.`); + } + + function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) { + return leftQuote + escapeNonAsciiCharacters(escapeString(text)) + rightQuote; + } + + function emitDownlevelRawTemplateLiteral(node: LiteralExpression) { + // Find original source text, since we need to emit the raw strings of the tagged template. + // The raw strings contain the (escaped) strings of what the user wrote. + // Examples: `\n` is converted to "\\n", a template string with a newline to "\n". + let text = getSourceTextOfNodeFromSourceFile(currentSourceFile, node); + + // text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"), + // thus we need to remove those characters. + // First template piece starts with "`", others with "}" + // Last template piece ends with "`", others with "${" + let isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail; + text = text.substring(1, text.length - (isLast ? 1 : 2)); + + // Newline normalization: + // ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's + // and LineTerminatorSequences are normalized to for both TV and TRV. + text = text.replace(/\r\n?/g, "\n"); + text = escapeString(text); + + write('"' + text + '"'); + } + + function emitDownlevelTaggedTemplateArray(node: TaggedTemplateExpression, literalEmitter: (literal: LiteralExpression) => void) { + write("["); + if (node.template.kind === SyntaxKind.NoSubstitutionTemplateLiteral) { + literalEmitter(node.template); + } + else { + literalEmitter((node.template).head); + forEach((node.template).templateSpans, (child) => { + write(", "); + literalEmitter(child.literal); + }); + } + write("]"); + } + + function emitDownlevelTaggedTemplate(node: TaggedTemplateExpression) { + let tempVariable = createAndRecordTempVariable(TempFlags.Auto); + write("("); + emit(tempVariable); + write(" = "); + emitDownlevelTaggedTemplateArray(node, emit); + write(", "); + + emit(tempVariable); + write(".raw = "); + emitDownlevelTaggedTemplateArray(node, emitDownlevelRawTemplateLiteral); + write(", "); + + emitParenthesizedIf(node.tag, needsParenthesisForPropertyAccessOrInvocation(node.tag)); + write("("); + emit(tempVariable); + + // Now we emit the expressions + if (node.template.kind === SyntaxKind.TemplateExpression) { + forEach((node.template).templateSpans, templateSpan => { + write(", "); + let needsParens = templateSpan.expression.kind === SyntaxKind.BinaryExpression + && (templateSpan.expression).operatorToken.kind === SyntaxKind.CommaToken; + emitParenthesizedIf(templateSpan.expression, needsParens); + }); + } + write("))"); + } + + function emitTemplateExpression(node: TemplateExpression): void { + // In ES6 mode and above, we can simply emit each portion of a template in order, but in + // ES3 & ES5 we must convert the template expression into a series of string concatenations. + if (languageVersion >= ScriptTarget.ES6) { + forEachChild(node, emit); + return; + } + + let emitOuterParens = isExpression(node.parent) + && templateNeedsParens(node, node.parent); + + if (emitOuterParens) { + write("("); + } + + let headEmitted = false; + if (shouldEmitTemplateHead()) { + emitLiteral(node.head); + headEmitted = true; + } + + for (let i = 0, n = node.templateSpans.length; i < n; i++) { + let templateSpan = node.templateSpans[i]; + + // Check if the expression has operands and binds its operands less closely than binary '+'. + // If it does, we need to wrap the expression in parentheses. Otherwise, something like + // `abc${ 1 << 2 }` + // becomes + // "abc" + 1 << 2 + "" + // which is really + // ("abc" + 1) << (2 + "") + // rather than + // "abc" + (1 << 2) + "" + let needsParens = templateSpan.expression.kind !== SyntaxKind.ParenthesizedExpression + && comparePrecedenceToBinaryPlus(templateSpan.expression) !== Comparison.GreaterThan; + + if (i > 0 || headEmitted) { + // If this is the first span and the head was not emitted, then this templateSpan's + // expression will be the first to be emitted. Don't emit the preceding ' + ' in that + // case. + write(" + "); + } + + emitParenthesizedIf(templateSpan.expression, needsParens); + + // Only emit if the literal is non-empty. + // The binary '+' operator is left-associative, so the first string concatenation + // with the head will force the result up to this point to be a string. + // Emitting a '+ ""' has no semantic effect for middles and tails. + if (templateSpan.literal.text.length !== 0) { + write(" + ") + emitLiteral(templateSpan.literal); + } + } + + if (emitOuterParens) { + write(")"); + } + + function shouldEmitTemplateHead() { + // If this expression has an empty head literal and the first template span has a non-empty + // literal, then emitting the empty head literal is not necessary. + // `${ foo } and ${ bar }` + // can be emitted as + // foo + " and " + bar + // This is because it is only required that one of the first two operands in the emit + // output must be a string literal, so that the other operand and all following operands + // are forced into strings. + // + // If the first template span has an empty literal, then the head must still be emitted. + // `${ foo }${ bar }` + // must still be emitted as + // "" + foo + bar + + // There is always atleast one templateSpan in this code path, since + // NoSubstitutionTemplateLiterals are directly emitted via emitLiteral() + Debug.assert(node.templateSpans.length !== 0); + + return node.head.text.length !== 0 || node.templateSpans[0].literal.text.length === 0; + } + + function templateNeedsParens(template: TemplateExpression, parent: Expression) { + switch (parent.kind) { + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + return (parent).expression === template; + case SyntaxKind.TaggedTemplateExpression: + case SyntaxKind.ParenthesizedExpression: + return false; + default: + return comparePrecedenceToBinaryPlus(parent) !== Comparison.LessThan; + } + } + + /** + * Returns whether the expression has lesser, greater, + * or equal precedence to the binary '+' operator + */ + function comparePrecedenceToBinaryPlus(expression: Expression): Comparison { + // All binary expressions have lower precedence than '+' apart from '*', '/', and '%' + // which have greater precedence and '-' which has equal precedence. + // All unary operators have a higher precedence apart from yield. + // Arrow functions and conditionals have a lower precedence, + // although we convert the former into regular function expressions in ES5 mode, + // and in ES6 mode this function won't get called anyway. + // + // TODO (drosen): Note that we need to account for the upcoming 'yield' and + // spread ('...') unary operators that are anticipated for ES6. + switch (expression.kind) { + case SyntaxKind.BinaryExpression: + switch ((expression).operatorToken.kind) { + case SyntaxKind.AsteriskToken: + case SyntaxKind.SlashToken: + case SyntaxKind.PercentToken: + return Comparison.GreaterThan; + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + return Comparison.EqualTo; + default: + return Comparison.LessThan; + } + case SyntaxKind.YieldExpression: + case SyntaxKind.ConditionalExpression: + return Comparison.LessThan; + default: + return Comparison.GreaterThan; + } + } + } + + function emitTemplateSpan(span: TemplateSpan) { + emit(span.expression); + emit(span.literal); + } + + // This function specifically handles numeric/string literals for enum and accessor 'identifiers'. + // In a sense, it does not actually emit identifiers as much as it declares a name for a specific property. + // For example, this is utilized when feeding in a result to Object.defineProperty. + function emitExpressionForPropertyName(node: DeclarationName) { + Debug.assert(node.kind !== SyntaxKind.BindingElement); + + if (node.kind === SyntaxKind.StringLiteral) { + emitLiteral(node); + } + else if (node.kind === SyntaxKind.ComputedPropertyName) { + // if this is a decorated computed property, we will need to capture the result + // of the property expression so that we can apply decorators later. This is to ensure + // we don't introduce unintended side effects: + // + // class C { + // [_a = x]() { } + // } + // + // The emit for the decorated computed property decorator is: + // + // Object.defineProperty(C.prototype, _a, __decorate([dec], C.prototype, _a, Object.getOwnPropertyDescriptor(C.prototype, _a))); + // + if (nodeIsDecorated(node.parent)) { + if (!computedPropertyNamesToGeneratedNames) { + computedPropertyNamesToGeneratedNames = []; + } + + let generatedName = computedPropertyNamesToGeneratedNames[getNodeId(node)]; + if (generatedName) { + // we have already generated a variable for this node, write that value instead. + write(generatedName); + return; + } + + generatedName = createAndRecordTempVariable(TempFlags.Auto).text; + computedPropertyNamesToGeneratedNames[getNodeId(node)] = generatedName; + write(generatedName); + write(" = "); + } + + emit((node).expression); + } + else { + write("\""); + + if (node.kind === SyntaxKind.NumericLiteral) { + write((node).text); + } + else { + writeTextOfNode(currentSourceFile, node); + } + + write("\""); + } + } + + function isNotExpressionIdentifier(node: Identifier) { + let parent = node.parent; + switch (parent.kind) { + case SyntaxKind.Parameter: + case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.EnumMember: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportClause: + case SyntaxKind.NamespaceImport: + return (parent).name === node; + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ExportSpecifier: + return (parent).name === node || (parent).propertyName === node; + case SyntaxKind.BreakStatement: + case SyntaxKind.ContinueStatement: + case SyntaxKind.ExportAssignment: + return false; + case SyntaxKind.LabeledStatement: + return (node.parent).label === node; + } + } + + function emitExpressionIdentifier(node: Identifier) { + let substitution = resolver.getExpressionNameSubstitution(node, getGeneratedNameForNode); + if (substitution) { + write(substitution); + } + else { + writeTextOfNode(currentSourceFile, node); + } + } + + function getGeneratedNameForIdentifier(node: Identifier): string { + if (nodeIsSynthesized(node) || !blockScopedVariableToGeneratedName) { + return undefined; + } + + var variableId = resolver.getBlockScopedVariableId(node) + if (variableId === undefined) { + return undefined; + } + + return blockScopedVariableToGeneratedName[variableId]; + } + + function emitIdentifier(node: Identifier, allowGeneratedIdentifiers: boolean) { + if (allowGeneratedIdentifiers) { + let generatedName = getGeneratedNameForIdentifier(node); + if (generatedName) { + write(generatedName); + return; + } + } + if (!node.parent) { + write(node.text); + } + else if (!isNotExpressionIdentifier(node)) { + emitExpressionIdentifier(node); + } + else { + writeTextOfNode(currentSourceFile, node); + } + } + + function emitThis(node: Node) { + if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LexicalThis) { + write("_this"); + } + else { + write("this"); + } + } + + function emitSuper(node: Node) { + if (languageVersion >= ScriptTarget.ES6) { + write("super"); + } + else { + var flags = resolver.getNodeCheckFlags(node); + if (flags & NodeCheckFlags.SuperInstance) { + write("_super.prototype"); + } + else { + write("_super"); + } + } + } + + function emitObjectBindingPattern(node: BindingPattern) { + write("{ "); + let elements = node.elements; + emitList(elements, 0, elements.length, /*multiLine*/ false, /*trailingComma*/ elements.hasTrailingComma); + write(" }"); + } + + function emitArrayBindingPattern(node: BindingPattern) { + write("["); + let elements = node.elements; + emitList(elements, 0, elements.length, /*multiLine*/ false, /*trailingComma*/ elements.hasTrailingComma); + write("]"); + } + + function emitBindingElement(node: BindingElement) { + if (node.propertyName) { + emit(node.propertyName, /*allowGeneratedIdentifiers*/ false); + write(": "); + } + if (node.dotDotDotToken) { + write("..."); + } + if (isBindingPattern(node.name)) { + emit(node.name); + } + else { + emitModuleMemberName(node); + } + emitOptional(" = ", node.initializer); + } + + function emitSpreadElementExpression(node: SpreadElementExpression) { + write("..."); + emit((node).expression); + } + + function emitYieldExpression(node: YieldExpression) { + write(tokenToString(SyntaxKind.YieldKeyword)); + if (node.asteriskToken) { + write("*"); + } + if (node.expression) { + write(" "); + emit(node.expression); + } + } + + function needsParenthesisForPropertyAccessOrInvocation(node: Expression) { + switch (node.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.ParenthesizedExpression: + // This list is not exhaustive and only includes those cases that are relevant + // to the check in emitArrayLiteral. More cases can be added as needed. + return false; + } + return true; + } + + function emitListWithSpread(elements: Expression[], multiLine: boolean, trailingComma: boolean) { + let pos = 0; + let group = 0; + let length = elements.length; + while (pos < length) { + // Emit using the pattern .concat(, , ...) + if (group === 1) { + write(".concat("); + } + else if (group > 1) { + write(", "); + } + let e = elements[pos]; + if (e.kind === SyntaxKind.SpreadElementExpression) { + e = (e).expression; + emitParenthesizedIf(e, /*parenthesized*/ group === 0 && needsParenthesisForPropertyAccessOrInvocation(e)); + pos++; + } + else { + let i = pos; + while (i < length && elements[i].kind !== SyntaxKind.SpreadElementExpression) { + i++; + } + write("["); + if (multiLine) { + increaseIndent(); + } + emitList(elements, pos, i - pos, multiLine, trailingComma && i === length); + if (multiLine) { + decreaseIndent(); + } + write("]"); + pos = i; + } + group++; + } + if (group > 1) { + write(")"); + } + } + + function isSpreadElementExpression(node: Node) { + return node.kind === SyntaxKind.SpreadElementExpression; + } + + function emitArrayLiteral(node: ArrayLiteralExpression) { + let elements = node.elements; + if (elements.length === 0) { + write("[]"); + } + else if (languageVersion >= ScriptTarget.ES6 || !forEach(elements, isSpreadElementExpression)) { + write("["); + emitLinePreservingList(node, node.elements, elements.hasTrailingComma, /*spacesBetweenBraces:*/ false); + write("]"); + } + else { + emitListWithSpread(elements, /*multiLine*/(node.flags & NodeFlags.MultiLine) !== 0, + /*trailingComma*/ elements.hasTrailingComma); + } + } + + function emitObjectLiteralBody(node: ObjectLiteralExpression, numElements: number): void { + if (numElements === 0) { + write("{}"); + return; + } + + write("{"); + + if (numElements > 0) { + var properties = node.properties; + + // If we are not doing a downlevel transformation for object literals, + // then try to preserve the original shape of the object literal. + // Otherwise just try to preserve the formatting. + if (numElements === properties.length) { + emitLinePreservingList(node, properties, /* allowTrailingComma */ languageVersion >= ScriptTarget.ES5, /* spacesBetweenBraces */ true); + } + else { + let multiLine = (node.flags & NodeFlags.MultiLine) !== 0; + if (!multiLine) { + write(" "); + } + else { + increaseIndent(); + } + + emitList(properties, 0, numElements, /*multiLine*/ multiLine, /*trailingComma*/ false); + + if (!multiLine) { + write(" "); + } + else { + decreaseIndent(); + } + } + } + + write("}"); + } + + function emitDownlevelObjectLiteralWithComputedProperties(node: ObjectLiteralExpression, firstComputedPropertyIndex: number) { + let multiLine = (node.flags & NodeFlags.MultiLine) !== 0; + let properties = node.properties; + + write("("); + + if (multiLine) { + increaseIndent(); + } + + // For computed properties, we need to create a unique handle to the object + // literal so we can modify it without risking internal assignments tainting the object. + let tempVar = createAndRecordTempVariable(TempFlags.Auto); + + // Write out the first non-computed properties + // (or all properties if none of them are computed), + // then emit the rest through indexing on the temp variable. + emit(tempVar) + write(" = "); + emitObjectLiteralBody(node, firstComputedPropertyIndex); + + for (let i = firstComputedPropertyIndex, n = properties.length; i < n; i++) { + writeComma(); + + let property = properties[i]; + + emitStart(property) + if (property.kind === SyntaxKind.GetAccessor || property.kind === SyntaxKind.SetAccessor) { + // TODO (drosen): Reconcile with 'emitMemberFunctions'. + let accessors = getAllAccessorDeclarations(node.properties, property); + if (property !== accessors.firstAccessor) { + continue; + } + write("Object.defineProperty("); + emit(tempVar); + write(", "); + emitStart(node.name); + emitExpressionForPropertyName(property.name); + emitEnd(property.name); + write(", {"); + increaseIndent(); + if (accessors.getAccessor) { + writeLine() + emitLeadingComments(accessors.getAccessor); + write("get: "); + emitStart(accessors.getAccessor); + write("function "); + emitSignatureAndBody(accessors.getAccessor); + emitEnd(accessors.getAccessor); + emitTrailingComments(accessors.getAccessor); + write(","); + } + if (accessors.setAccessor) { + writeLine(); + emitLeadingComments(accessors.setAccessor); + write("set: "); + emitStart(accessors.setAccessor); + write("function "); + emitSignatureAndBody(accessors.setAccessor); + emitEnd(accessors.setAccessor); + emitTrailingComments(accessors.setAccessor); + write(","); + } + writeLine(); + write("enumerable: true,"); + writeLine(); + write("configurable: true"); + decreaseIndent(); + writeLine(); + write("})"); + emitEnd(property); + } + else { + emitLeadingComments(property); + emitStart(property.name); + emit(tempVar); + emitMemberAccessForPropertyName(property.name); + emitEnd(property.name); + + write(" = "); + + if (property.kind === SyntaxKind.PropertyAssignment) { + emit((property).initializer); + } + else if (property.kind === SyntaxKind.ShorthandPropertyAssignment) { + emitExpressionIdentifier((property).name); + } + else if (property.kind === SyntaxKind.MethodDeclaration) { + emitFunctionDeclaration(property); + } + else { + Debug.fail("ObjectLiteralElement type not accounted for: " + property.kind); + } + } + + emitEnd(property); + } + + writeComma(); + emit(tempVar); + + if (multiLine) { + decreaseIndent(); + writeLine(); + } + + write(")"); + + function writeComma() { + if (multiLine) { + write(","); + writeLine(); + } + else { + write(", "); + } + } + } + + function emitObjectLiteral(node: ObjectLiteralExpression): void { + let properties = node.properties; + + if (languageVersion < ScriptTarget.ES6) { + let numProperties = properties.length; + + // Find the first computed property. + // Everything until that point can be emitted as part of the initial object literal. + let numInitialNonComputedProperties = numProperties; + for (let i = 0, n = properties.length; i < n; i++) { + if (properties[i].name.kind === SyntaxKind.ComputedPropertyName) { + numInitialNonComputedProperties = i; + break; + } + } + + let hasComputedProperty = numInitialNonComputedProperties !== properties.length; + if (hasComputedProperty) { + emitDownlevelObjectLiteralWithComputedProperties(node, numInitialNonComputedProperties); + return; + } + } + + // Ordinary case: either the object has no computed properties + // or we're compiling with an ES6+ target. + emitObjectLiteralBody(node, properties.length); + } + + function createBinaryExpression(left: Expression, operator: SyntaxKind, right: Expression, startsOnNewLine?: boolean): BinaryExpression { + let result = createSynthesizedNode(SyntaxKind.BinaryExpression, startsOnNewLine); + result.operatorToken = createSynthesizedNode(operator); + result.left = left; + result.right = right; + + return result; + } + + function createPropertyAccessExpression(expression: Expression, name: Identifier): PropertyAccessExpression { + let result = createSynthesizedNode(SyntaxKind.PropertyAccessExpression); + result.expression = parenthesizeForAccess(expression); + result.dotToken = createSynthesizedNode(SyntaxKind.DotToken); + result.name = name; + + return result; + } + + function createElementAccessExpression(expression: Expression, argumentExpression: Expression): ElementAccessExpression { + let result = createSynthesizedNode(SyntaxKind.ElementAccessExpression); + result.expression = parenthesizeForAccess(expression); + result.argumentExpression = argumentExpression; + + return result; + } + + function parenthesizeForAccess(expr: Expression): LeftHandSideExpression { + // isLeftHandSideExpression is almost the correct criterion for when it is not necessary + // to parenthesize the expression before a dot. The known exceptions are: + // + // NewExpression: + // new C.x -> not the same as (new C).x + // NumberLiteral + // 1.x -> not the same as (1).x + // + if (isLeftHandSideExpression(expr) && expr.kind !== SyntaxKind.NewExpression && expr.kind !== SyntaxKind.NumericLiteral) { + return expr; + } + let node = createSynthesizedNode(SyntaxKind.ParenthesizedExpression); + node.expression = expr; + return node; + } + + function emitComputedPropertyName(node: ComputedPropertyName) { + write("["); + emitExpressionForPropertyName(node); + write("]"); + } + + function emitMethod(node: MethodDeclaration) { + if (languageVersion >= ScriptTarget.ES6 && node.asteriskToken) { + write("*"); + } + + emit(node.name, /*allowGeneratedIdentifiers*/ false); + if (languageVersion < ScriptTarget.ES6) { + write(": function "); + } + emitSignatureAndBody(node); + } + + function emitPropertyAssignment(node: PropertyDeclaration) { + emit(node.name, /*allowGeneratedIdentifiers*/ false); + write(": "); + emit(node.initializer); + } + + function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) { + emit(node.name, /*allowGeneratedIdentifiers*/ false); + // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment. For example: + // module m { + // export let y; + // } + // module m { + // export let obj = { y }; + // } + // The short-hand property in obj need to emit as such ... = { y : m.y } regardless of the TargetScript version + if (languageVersion < ScriptTarget.ES6) { + // Emit identifier as an identifier + write(": "); + var generatedName = getGeneratedNameForIdentifier(node.name); + if (generatedName) { + write(generatedName); + } + else { + // Even though this is stored as identifier treat it as an expression + // Short-hand, { x }, is equivalent of normal form { x: x } + emitExpressionIdentifier(node.name); + } + } + else if (resolver.getExpressionNameSubstitution(node.name, getGeneratedNameForNode)) { + // Emit identifier as an identifier + write(": "); + // Even though this is stored as identifier treat it as an expression + // Short-hand, { x }, is equivalent of normal form { x: x } + emitExpressionIdentifier(node.name); + } + } + + function tryEmitConstantValue(node: PropertyAccessExpression | ElementAccessExpression): boolean { + if (compilerOptions.separateCompilation) { + // do not inline enum values in separate compilation mode + return false; + } + + let constantValue = resolver.getConstantValue(node); + if (constantValue !== undefined) { + write(constantValue.toString()); + if (!compilerOptions.removeComments) { + let propertyName: string = node.kind === SyntaxKind.PropertyAccessExpression ? declarationNameToString((node).name) : getTextOfNode((node).argumentExpression); + write(" /* " + propertyName + " */"); + } + return true; + } + return false; + } + + // Returns 'true' if the code was actually indented, false otherwise. + // If the code is not indented, an optional valueToWriteWhenNotIndenting will be + // emitted instead. + function indentIfOnDifferentLines(parent: Node, node1: Node, node2: Node, valueToWriteWhenNotIndenting?: string): boolean { + let realNodesAreOnDifferentLines = !nodeIsSynthesized(parent) && !nodeEndIsOnSameLineAsNodeStart(node1, node2); + + // Always use a newline for synthesized code if the synthesizer desires it. + let synthesizedNodeIsOnDifferentLine = synthesizedNodeStartsOnNewLine(node2); + + if (realNodesAreOnDifferentLines || synthesizedNodeIsOnDifferentLine) { + increaseIndent(); + writeLine(); + return true; + } + else { + if (valueToWriteWhenNotIndenting) { + write(valueToWriteWhenNotIndenting); + } + return false; + } + } + + function emitPropertyAccess(node: PropertyAccessExpression) { + if (tryEmitConstantValue(node)) { + return; + } + + emit(node.expression); + let indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, node.dotToken); + write("."); + let indentedAfterDot = indentIfOnDifferentLines(node, node.dotToken, node.name); + emit(node.name, /*allowGeneratedIdentifiers*/ false); + decreaseIndentIf(indentedBeforeDot, indentedAfterDot); + } + + function emitQualifiedName(node: QualifiedName) { + emit(node.left); + write("."); + emit(node.right); + } + + function emitIndexedAccess(node: ElementAccessExpression) { + if (tryEmitConstantValue(node)) { + return; + } + emit(node.expression); + write("["); + emit(node.argumentExpression); + write("]"); + } + + function hasSpreadElement(elements: Expression[]) { + return forEach(elements, e => e.kind === SyntaxKind.SpreadElementExpression); + } + + function skipParentheses(node: Expression): Expression { + while (node.kind === SyntaxKind.ParenthesizedExpression || node.kind === SyntaxKind.TypeAssertionExpression) { + node = (node).expression; + } + return node; + } + + function emitCallTarget(node: Expression): Expression { + if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword) { + emit(node); + return node; + } + let temp = createAndRecordTempVariable(TempFlags.Auto); + + write("("); + emit(temp); + write(" = "); + emit(node); + write(")"); + return temp; + } + + function emitCallWithSpread(node: CallExpression) { + let target: Expression; + let expr = skipParentheses(node.expression); + if (expr.kind === SyntaxKind.PropertyAccessExpression) { + // Target will be emitted as "this" argument + target = emitCallTarget((expr).expression); + write("."); + emit((expr).name); + } + else if (expr.kind === SyntaxKind.ElementAccessExpression) { + // Target will be emitted as "this" argument + target = emitCallTarget((expr).expression); + write("["); + emit((expr).argumentExpression); + write("]"); + } + else if (expr.kind === SyntaxKind.SuperKeyword) { + target = expr; + write("_super"); + } + else { + emit(node.expression); + } + write(".apply("); + if (target) { + if (target.kind === SyntaxKind.SuperKeyword) { + // Calls of form super(...) and super.foo(...) + emitThis(target); + } + else { + // Calls of form obj.foo(...) + emit(target); + } + } + else { + // Calls of form foo(...) + write("void 0"); + } + write(", "); + emitListWithSpread(node.arguments, /*multiLine*/ false, /*trailingComma*/ false); + write(")"); + } + + function emitCallExpression(node: CallExpression) { + if (languageVersion < ScriptTarget.ES6 && hasSpreadElement(node.arguments)) { + emitCallWithSpread(node); + return; + } + let superCall = false; + if (node.expression.kind === SyntaxKind.SuperKeyword) { + emitSuper(node.expression); + superCall = true; + } + else { + emit(node.expression); + superCall = node.expression.kind === SyntaxKind.PropertyAccessExpression && (node.expression).expression.kind === SyntaxKind.SuperKeyword; + } + if (superCall && languageVersion < ScriptTarget.ES6) { + write(".call("); + emitThis(node.expression); + if (node.arguments.length) { + write(", "); + emitCommaList(node.arguments); + } + write(")"); + } + else { + write("("); + emitCommaList(node.arguments); + write(")"); + } + } + + function emitNewExpression(node: NewExpression) { + write("new "); + emit(node.expression); + if (node.arguments) { + write("("); + emitCommaList(node.arguments); + write(")"); + } + } + + function emitTaggedTemplateExpression(node: TaggedTemplateExpression): void { + if (languageVersion >= ScriptTarget.ES6) { + emit(node.tag); + write(" "); + emit(node.template); + } + else { + emitDownlevelTaggedTemplate(node); + } + } + + function emitParenExpression(node: ParenthesizedExpression) { + if (!node.parent || node.parent.kind !== SyntaxKind.ArrowFunction) { + if (node.expression.kind === SyntaxKind.TypeAssertionExpression) { + let operand = (node.expression).expression; + + // Make sure we consider all nested cast expressions, e.g.: + // (-A).x; + while (operand.kind == SyntaxKind.TypeAssertionExpression) { + operand = (operand).expression; + } + + // We have an expression of the form: (SubExpr) + // Emitting this as (SubExpr) is really not desirable. We would like to emit the subexpr as is. + // Omitting the parentheses, however, could cause change in the semantics of the generated + // code if the casted expression has a lower precedence than the rest of the expression, e.g.: + // (new A).foo should be emitted as (new A).foo and not new A.foo + // (typeof A).toString() should be emitted as (typeof A).toString() and not typeof A.toString() + // new (A()) should be emitted as new (A()) and not new A() + // (function foo() { })() should be emitted as an IIF (function foo(){})() and not declaration function foo(){} () + if (operand.kind !== SyntaxKind.PrefixUnaryExpression && + operand.kind !== SyntaxKind.VoidExpression && + operand.kind !== SyntaxKind.TypeOfExpression && + operand.kind !== SyntaxKind.DeleteExpression && + operand.kind !== SyntaxKind.PostfixUnaryExpression && + operand.kind !== SyntaxKind.NewExpression && + !(operand.kind === SyntaxKind.CallExpression && node.parent.kind === SyntaxKind.NewExpression) && + !(operand.kind === SyntaxKind.FunctionExpression && node.parent.kind === SyntaxKind.CallExpression)) { + emit(operand); + return; + } + } + } + + write("("); + emit(node.expression); + write(")"); + } + + function emitDeleteExpression(node: DeleteExpression) { + write(tokenToString(SyntaxKind.DeleteKeyword)); + write(" "); + emit(node.expression); + } + + function emitVoidExpression(node: VoidExpression) { + write(tokenToString(SyntaxKind.VoidKeyword)); + write(" "); + emit(node.expression); + } + + function emitTypeOfExpression(node: TypeOfExpression) { + write(tokenToString(SyntaxKind.TypeOfKeyword)); + write(" "); + emit(node.expression); + } + + function emitPrefixUnaryExpression(node: PrefixUnaryExpression) { + write(tokenToString(node.operator)); + // In some cases, we need to emit a space between the operator and the operand. One obvious case + // is when the operator is an identifier, like delete or typeof. We also need to do this for plus + // and minus expressions in certain cases. Specifically, consider the following two cases (parens + // are just for clarity of exposition, and not part of the source code): + // + // (+(+1)) + // (+(++1)) + // + // We need to emit a space in both cases. In the first case, the absence of a space will make + // the resulting expression a prefix increment operation. And in the second, it will make the resulting + // expression a prefix increment whose operand is a plus expression - (++(+x)) + // The same is true of minus of course. + if (node.operand.kind === SyntaxKind.PrefixUnaryExpression) { + let operand = node.operand; + if (node.operator === SyntaxKind.PlusToken && (operand.operator === SyntaxKind.PlusToken || operand.operator === SyntaxKind.PlusPlusToken)) { + write(" "); + } + else if (node.operator === SyntaxKind.MinusToken && (operand.operator === SyntaxKind.MinusToken || operand.operator === SyntaxKind.MinusMinusToken)) { + write(" "); + } + } + emit(node.operand); + } + + function emitPostfixUnaryExpression(node: PostfixUnaryExpression) { + emit(node.operand); + write(tokenToString(node.operator)); + } + + function emitBinaryExpression(node: BinaryExpression) { + if (languageVersion < ScriptTarget.ES6 && node.operatorToken.kind === SyntaxKind.EqualsToken && + (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { + emitDestructuring(node, node.parent.kind === SyntaxKind.ExpressionStatement); + } + else { + emit(node.left); + let indentedBeforeOperator = indentIfOnDifferentLines(node, node.left, node.operatorToken, node.operatorToken.kind !== SyntaxKind.CommaToken ? " " : undefined); + write(tokenToString(node.operatorToken.kind)); + let indentedAfterOperator = indentIfOnDifferentLines(node, node.operatorToken, node.right, " "); + emit(node.right); + decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator); + } + } + + function synthesizedNodeStartsOnNewLine(node: Node) { + return nodeIsSynthesized(node) && (node).startsOnNewLine; + } + + function emitConditionalExpression(node: ConditionalExpression) { + emit(node.condition); + let indentedBeforeQuestion = indentIfOnDifferentLines(node, node.condition, node.questionToken, " "); + write("?"); + let indentedAfterQuestion = indentIfOnDifferentLines(node, node.questionToken, node.whenTrue, " "); + emit(node.whenTrue); + decreaseIndentIf(indentedBeforeQuestion, indentedAfterQuestion); + let indentedBeforeColon = indentIfOnDifferentLines(node, node.whenTrue, node.colonToken, " "); + write(":"); + let indentedAfterColon = indentIfOnDifferentLines(node, node.colonToken, node.whenFalse, " "); + emit(node.whenFalse); + decreaseIndentIf(indentedBeforeColon, indentedAfterColon); + } + + // Helper function to decrease the indent if we previously indented. Allows multiple + // previous indent values to be considered at a time. This also allows caller to just + // call this once, passing in all their appropriate indent values, instead of needing + // to call this helper function multiple times. + function decreaseIndentIf(value1: boolean, value2?: boolean) { + if (value1) { + decreaseIndent(); + } + if (value2) { + decreaseIndent(); + } + } + + function isSingleLineEmptyBlock(node: Node) { + if (node && node.kind === SyntaxKind.Block) { + let block = node; + return block.statements.length === 0 && nodeEndIsOnSameLineAsNodeStart(block, block); + } + } + + function emitBlock(node: Block) { + if (isSingleLineEmptyBlock(node)) { + emitToken(SyntaxKind.OpenBraceToken, node.pos); + write(" "); + emitToken(SyntaxKind.CloseBraceToken, node.statements.end); + return; + } + + emitToken(SyntaxKind.OpenBraceToken, node.pos); + increaseIndent(); + scopeEmitStart(node.parent); + if (node.kind === SyntaxKind.ModuleBlock) { + Debug.assert(node.parent.kind === SyntaxKind.ModuleDeclaration); + emitCaptureThisForNodeIfNecessary(node.parent); + } + emitLines(node.statements); + if (node.kind === SyntaxKind.ModuleBlock) { + emitTempDeclarations(/*newLine*/ true); + } + decreaseIndent(); + writeLine(); + emitToken(SyntaxKind.CloseBraceToken, node.statements.end); + scopeEmitEnd(); + } + + function emitEmbeddedStatement(node: Node) { + if (node.kind === SyntaxKind.Block) { + write(" "); + emit(node); + } + else { + increaseIndent(); + writeLine(); + emit(node); + decreaseIndent(); + } + } + + function emitExpressionStatement(node: ExpressionStatement) { + emitParenthesizedIf(node.expression, /*parenthesized*/ node.expression.kind === SyntaxKind.ArrowFunction); + write(";"); + } + + function emitIfStatement(node: IfStatement) { + let endPos = emitToken(SyntaxKind.IfKeyword, node.pos); + write(" "); + endPos = emitToken(SyntaxKind.OpenParenToken, endPos); + emit(node.expression); + emitToken(SyntaxKind.CloseParenToken, node.expression.end); + emitEmbeddedStatement(node.thenStatement); + if (node.elseStatement) { + writeLine(); + emitToken(SyntaxKind.ElseKeyword, node.thenStatement.end); + if (node.elseStatement.kind === SyntaxKind.IfStatement) { + write(" "); + emit(node.elseStatement); + } + else { + emitEmbeddedStatement(node.elseStatement); + } + } + } + + function emitDoStatement(node: DoStatement) { + write("do"); + emitEmbeddedStatement(node.statement); + if (node.statement.kind === SyntaxKind.Block) { + write(" "); + } + else { + writeLine(); + } + write("while ("); + emit(node.expression); + write(");"); + } + + function emitWhileStatement(node: WhileStatement) { + write("while ("); + emit(node.expression); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitStartOfVariableDeclarationList(decl: Node, startPos?: number): void { + let tokenKind = SyntaxKind.VarKeyword; + if (decl && languageVersion >= ScriptTarget.ES6) { + if (isLet(decl)) { + tokenKind = SyntaxKind.LetKeyword; + } + else if (isConst(decl)) { + tokenKind = SyntaxKind.ConstKeyword; + } + } + + if (startPos !== undefined) { + emitToken(tokenKind, startPos); + } + else { + switch (tokenKind) { + case SyntaxKind.VarKeyword: + return write("var "); + case SyntaxKind.LetKeyword: + return write("let "); + case SyntaxKind.ConstKeyword: + return write("const "); + } + } + } + + function emitForStatement(node: ForStatement) { + let endPos = emitToken(SyntaxKind.ForKeyword, node.pos); + write(" "); + endPos = emitToken(SyntaxKind.OpenParenToken, endPos); + if (node.initializer && node.initializer.kind === SyntaxKind.VariableDeclarationList) { + let variableDeclarationList = node.initializer; + let declarations = variableDeclarationList.declarations; + emitStartOfVariableDeclarationList(declarations[0], endPos); + write(" "); + emitCommaList(declarations); + } + else if (node.initializer) { + emit(node.initializer); + } + write(";"); + emitOptional(" ", node.condition); + write(";"); + emitOptional(" ", node.incrementor); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitForInOrForOfStatement(node: ForInStatement | ForOfStatement) { + if (languageVersion < ScriptTarget.ES6 && node.kind === SyntaxKind.ForOfStatement) { + return emitDownLevelForOfStatement(node); + } + + let endPos = emitToken(SyntaxKind.ForKeyword, node.pos); + write(" "); + endPos = emitToken(SyntaxKind.OpenParenToken, endPos); + if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { + let variableDeclarationList = node.initializer; + if (variableDeclarationList.declarations.length >= 1) { + let decl = variableDeclarationList.declarations[0]; + emitStartOfVariableDeclarationList(decl, endPos); + write(" "); + emit(decl); + } + } + else { + emit(node.initializer); + } + + if (node.kind === SyntaxKind.ForInStatement) { + write(" in "); + } + else { + write(" of "); + } + emit(node.expression); + emitToken(SyntaxKind.CloseParenToken, node.expression.end); + emitEmbeddedStatement(node.statement); + } + + function emitDownLevelForOfStatement(node: ForOfStatement) { + // The following ES6 code: + // + // for (let v of expr) { } + // + // should be emitted as + // + // for (let _i = 0, _a = expr; _i < _a.length; _i++) { + // let v = _a[_i]; + // } + // + // where _a and _i are temps emitted to capture the RHS and the counter, + // respectively. + // When the left hand side is an expression instead of a let declaration, + // the "let v" is not emitted. + // When the left hand side is a let/const, the v is renamed if there is + // another v in scope. + // Note that all assignments to the LHS are emitted in the body, including + // all destructuring. + // Note also that because an extra statement is needed to assign to the LHS, + // for-of bodies are always emitted as blocks. + + let endPos = emitToken(SyntaxKind.ForKeyword, node.pos); + write(" "); + endPos = emitToken(SyntaxKind.OpenParenToken, endPos); + + // Do not emit the LHS let declaration yet, because it might contain destructuring. + + // Do not call recordTempDeclaration because we are declaring the temps + // right here. Recording means they will be declared later. + // In the case where the user wrote an identifier as the RHS, like this: + // + // for (let v of arr) { } + // + // we don't want to emit a temporary variable for the RHS, just use it directly. + let rhsIsIdentifier = node.expression.kind === SyntaxKind.Identifier; + let counter = createTempVariable(TempFlags._i); + let rhsReference = rhsIsIdentifier ? node.expression : createTempVariable(TempFlags.Auto); + + // This is the let keyword for the counter and rhsReference. The let keyword for + // the LHS will be emitted inside the body. + emitStart(node.expression); + write("var "); + + // _i = 0 + emitNodeWithoutSourceMap(counter); + write(" = 0"); + emitEnd(node.expression); + + if (!rhsIsIdentifier) { + // , _a = expr + write(", "); + emitStart(node.expression); + emitNodeWithoutSourceMap(rhsReference); + write(" = "); + emitNodeWithoutSourceMap(node.expression); + emitEnd(node.expression); + } + + write("; "); + + // _i < _a.length; + emitStart(node.initializer); + emitNodeWithoutSourceMap(counter); + write(" < "); + + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + + emitEnd(node.initializer); + write("; "); + + // _i++) + emitStart(node.initializer); + emitNodeWithoutSourceMap(counter); + write("++"); + emitEnd(node.initializer); + emitToken(SyntaxKind.CloseParenToken, node.expression.end); + + // Body + write(" {"); + writeLine(); + increaseIndent(); + + // Initialize LHS + // let v = _a[_i]; + let rhsIterationValue = createElementAccessExpression(rhsReference, counter); + emitStart(node.initializer); + if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { + write("var "); + let variableDeclarationList = node.initializer; + if (variableDeclarationList.declarations.length > 0) { + let declaration = variableDeclarationList.declarations[0]; + if (isBindingPattern(declaration.name)) { + // This works whether the declaration is a var, let, or const. + // It will use rhsIterationValue _a[_i] as the initializer. + emitDestructuring(declaration, /*isAssignmentExpressionStatement*/ false, rhsIterationValue); + } + else { + // The following call does not include the initializer, so we have + // to emit it separately. + emitNodeWithoutSourceMap(declaration); + write(" = "); + emitNodeWithoutSourceMap(rhsIterationValue); + } + } + else { + // It's an empty declaration list. This can only happen in an error case, if the user wrote + // for (let of []) {} + emitNodeWithoutSourceMap(createTempVariable(TempFlags.Auto)); + write(" = "); + emitNodeWithoutSourceMap(rhsIterationValue); + } + } + else { + // Initializer is an expression. Emit the expression in the body, so that it's + // evaluated on every iteration. + let assignmentExpression = createBinaryExpression(node.initializer, SyntaxKind.EqualsToken, rhsIterationValue, /*startsOnNewLine*/ false); + if (node.initializer.kind === SyntaxKind.ArrayLiteralExpression || node.initializer.kind === SyntaxKind.ObjectLiteralExpression) { + // This is a destructuring pattern, so call emitDestructuring instead of emit. Calling emit will not work, because it will cause + // the BinaryExpression to be passed in instead of the expression statement, which will cause emitDestructuring to crash. + emitDestructuring(assignmentExpression, /*isAssignmentExpressionStatement*/ true, /*value*/ undefined); + } + else { + emitNodeWithoutSourceMap(assignmentExpression); + } + } + emitEnd(node.initializer); + write(";"); + + if (node.statement.kind === SyntaxKind.Block) { + emitLines((node.statement).statements); + } + else { + writeLine(); + emit(node.statement); + } + + writeLine(); + decreaseIndent(); + write("}"); + } + + function emitBreakOrContinueStatement(node: BreakOrContinueStatement) { + emitToken(node.kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword, node.pos); + emitOptional(" ", node.label); + write(";"); + } + + function emitReturnStatement(node: ReturnStatement) { + emitToken(SyntaxKind.ReturnKeyword, node.pos); + emitOptional(" ", node.expression); + write(";"); + } + + function emitWithStatement(node: WhileStatement) { + write("with ("); + emit(node.expression); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitSwitchStatement(node: SwitchStatement) { + let endPos = emitToken(SyntaxKind.SwitchKeyword, node.pos); + write(" "); + emitToken(SyntaxKind.OpenParenToken, endPos); + emit(node.expression); + endPos = emitToken(SyntaxKind.CloseParenToken, node.expression.end); + write(" "); + emitCaseBlock(node.caseBlock, endPos) + } + + function emitCaseBlock(node: CaseBlock, startPos: number): void { + emitToken(SyntaxKind.OpenBraceToken, startPos); + increaseIndent(); + emitLines(node.clauses); + decreaseIndent(); + writeLine(); + emitToken(SyntaxKind.CloseBraceToken, node.clauses.end); + } + + function nodeStartPositionsAreOnSameLine(node1: Node, node2: Node) { + return getLineOfLocalPosition(currentSourceFile, skipTrivia(currentSourceFile.text, node1.pos)) === + getLineOfLocalPosition(currentSourceFile, skipTrivia(currentSourceFile.text, node2.pos)); + } + + function nodeEndPositionsAreOnSameLine(node1: Node, node2: Node) { + return getLineOfLocalPosition(currentSourceFile, node1.end) === + getLineOfLocalPosition(currentSourceFile, node2.end); + } + + function nodeEndIsOnSameLineAsNodeStart(node1: Node, node2: Node) { + return getLineOfLocalPosition(currentSourceFile, node1.end) === + getLineOfLocalPosition(currentSourceFile, skipTrivia(currentSourceFile.text, node2.pos)); + } + + function emitCaseOrDefaultClause(node: CaseOrDefaultClause) { + if (node.kind === SyntaxKind.CaseClause) { + write("case "); + emit((node).expression); + write(":"); + } + else { + write("default:"); + } + + if (node.statements.length === 1 && nodeStartPositionsAreOnSameLine(node, node.statements[0])) { + write(" "); + emit(node.statements[0]); + } + else { + increaseIndent(); + emitLines(node.statements); + decreaseIndent(); + } + } + + function emitThrowStatement(node: ThrowStatement) { + write("throw "); + emit(node.expression); + write(";"); + } + + function emitTryStatement(node: TryStatement) { + write("try "); + emit(node.tryBlock); + emit(node.catchClause); + if (node.finallyBlock) { + writeLine(); + write("finally "); + emit(node.finallyBlock); + } + } + + function emitCatchClause(node: CatchClause) { + writeLine(); + let endPos = emitToken(SyntaxKind.CatchKeyword, node.pos); + write(" "); + emitToken(SyntaxKind.OpenParenToken, endPos); + emit(node.variableDeclaration); + emitToken(SyntaxKind.CloseParenToken, node.variableDeclaration ? node.variableDeclaration.end : endPos); + write(" "); + emitBlock(node.block); + } + + function emitDebuggerStatement(node: Node) { + emitToken(SyntaxKind.DebuggerKeyword, node.pos); + write(";"); + } + + function emitLabelledStatement(node: LabeledStatement) { + emit(node.label); + write(": "); + emit(node.statement); + } + + function getContainingModule(node: Node): ModuleDeclaration { + do { + node = node.parent; + } while (node && node.kind !== SyntaxKind.ModuleDeclaration); + return node; + } + + function emitContainingModuleName(node: Node) { + let container = getContainingModule(node); + write(container ? getGeneratedNameForNode(container) : "exports"); + } + + function emitModuleMemberName(node: Declaration) { + emitStart(node.name); + if (getCombinedNodeFlags(node) & NodeFlags.Export) { + var container = getContainingModule(node); + if (container) { + write(getGeneratedNameForNode(container)); + write("."); + } + else if (languageVersion < ScriptTarget.ES6) { + write("exports."); + } + } + emitNodeWithoutSourceMap(node.name); + emitEnd(node.name); + } + + function createVoidZero(): Expression { + let zero = createSynthesizedNode(SyntaxKind.NumericLiteral); + zero.text = "0"; + let result = createSynthesizedNode(SyntaxKind.VoidExpression); + result.expression = zero; + return result; + } + + function emitExportMemberAssignment(node: FunctionLikeDeclaration | ClassDeclaration) { + if (node.flags & NodeFlags.Export) { + writeLine(); + emitStart(node); + if (node.flags & NodeFlags.Default) { + if (languageVersion === ScriptTarget.ES3) { + write("exports[\"default\"]"); + } else { + write("exports.default"); + } + } + else { + emitModuleMemberName(node); + } + write(" = "); + emitDeclarationName(node); + emitEnd(node); + write(";"); + } + } + + function emitExportMemberAssignments(name: Identifier) { + if (!exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) { + for (let specifier of exportSpecifiers[name.text]) { + writeLine(); + emitStart(specifier.name); + emitContainingModuleName(specifier); + write("."); + emitNodeWithoutSourceMap(specifier.name); + emitEnd(specifier.name); + write(" = "); + emitExpressionIdentifier(name); + write(";"); + } + } + } + + function emitDestructuring(root: BinaryExpression | VariableDeclaration | ParameterDeclaration, isAssignmentExpressionStatement: boolean, value?: Expression) { + let emitCount = 0; + // An exported declaration is actually emitted as an assignment (to a property on the module object), so + // temporary variables in an exported declaration need to have real declarations elsewhere + let isDeclaration = (root.kind === SyntaxKind.VariableDeclaration && !(getCombinedNodeFlags(root) & NodeFlags.Export)) || root.kind === SyntaxKind.Parameter; + if (root.kind === SyntaxKind.BinaryExpression) { + emitAssignmentExpression(root); + } + else { + Debug.assert(!isAssignmentExpressionStatement); + emitBindingElement(root, value); + } + + function emitAssignment(name: Identifier, value: Expression) { + if (emitCount++) { + write(", "); + } + + renameNonTopLevelLetAndConst(name); + if (name.parent && (name.parent.kind === SyntaxKind.VariableDeclaration || name.parent.kind === SyntaxKind.BindingElement)) { + emitModuleMemberName(name.parent); + } + else { + emit(name); + } + write(" = "); + emit(value); + } + + function ensureIdentifier(expr: Expression): Expression { + if (expr.kind !== SyntaxKind.Identifier) { + let identifier = createTempVariable(TempFlags.Auto); + if (!isDeclaration) { + recordTempDeclaration(identifier); + } + emitAssignment(identifier, expr); + expr = identifier; + } + return expr; + } + + function createDefaultValueCheck(value: Expression, defaultValue: Expression): Expression { + // The value expression will be evaluated twice, so for anything but a simple identifier + // we need to generate a temporary variable + value = ensureIdentifier(value); + // Return the expression 'value === void 0 ? defaultValue : value' + let equals = createSynthesizedNode(SyntaxKind.BinaryExpression); + equals.left = value; + equals.operatorToken = createSynthesizedNode(SyntaxKind.EqualsEqualsEqualsToken); + equals.right = createVoidZero(); + return createConditionalExpression(equals, defaultValue, value); + } + + function createConditionalExpression(condition: Expression, whenTrue: Expression, whenFalse: Expression) { + let cond = createSynthesizedNode(SyntaxKind.ConditionalExpression); + cond.condition = condition; + cond.questionToken = createSynthesizedNode(SyntaxKind.QuestionToken); + cond.whenTrue = whenTrue; + cond.colonToken = createSynthesizedNode(SyntaxKind.ColonToken); + cond.whenFalse = whenFalse; + return cond; + } + + function createNumericLiteral(value: number) { + let node = createSynthesizedNode(SyntaxKind.NumericLiteral); + node.text = "" + value; + return node; + } + + function createPropertyAccessForDestructuringProperty(object: Expression, propName: Identifier | LiteralExpression): Expression { + if (propName.kind !== SyntaxKind.Identifier) { + return createElementAccessExpression(object, propName); + } + + return createPropertyAccessExpression(object, propName); + } + + function createSliceCall(value: Expression, sliceIndex: number): CallExpression { + let call = createSynthesizedNode(SyntaxKind.CallExpression); + let sliceIdentifier = createSynthesizedNode(SyntaxKind.Identifier); + sliceIdentifier.text = "slice"; + call.expression = createPropertyAccessExpression(value, sliceIdentifier); + call.arguments = >createSynthesizedNodeArray(); + call.arguments[0] = createNumericLiteral(sliceIndex); + return call; + } + + function emitObjectLiteralAssignment(target: ObjectLiteralExpression, value: Expression) { + let properties = target.properties; + if (properties.length !== 1) { + // For anything but a single element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. + value = ensureIdentifier(value); + } + for (let p of properties) { + if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { + // TODO(andersh): Computed property support + let propName = ((p).name); + emitDestructuringAssignment((p).initializer || propName, createPropertyAccessForDestructuringProperty(value, propName)); + } + } + } + + function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression) { + let elements = target.elements; + if (elements.length !== 1) { + // For anything but a single element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. + value = ensureIdentifier(value); + } + for (let i = 0; i < elements.length; i++) { + let e = elements[i]; + if (e.kind !== SyntaxKind.OmittedExpression) { + if (e.kind !== SyntaxKind.SpreadElementExpression) { + emitDestructuringAssignment(e, createElementAccessExpression(value, createNumericLiteral(i))); + } + else if (i === elements.length - 1) { + emitDestructuringAssignment((e).expression, createSliceCall(value, i)); + } + } + } + } + + function emitDestructuringAssignment(target: Expression, value: Expression) { + if (target.kind === SyntaxKind.BinaryExpression && (target).operatorToken.kind === SyntaxKind.EqualsToken) { + value = createDefaultValueCheck(value, (target).right); + target = (target).left; + } + if (target.kind === SyntaxKind.ObjectLiteralExpression) { + emitObjectLiteralAssignment(target, value); + } + else if (target.kind === SyntaxKind.ArrayLiteralExpression) { + emitArrayLiteralAssignment(target, value); + } + else { + emitAssignment(target, value); + } + } + + function emitAssignmentExpression(root: BinaryExpression) { + let target = root.left; + let value = root.right; + if (isAssignmentExpressionStatement) { + emitDestructuringAssignment(target, value); + } + else { + if (root.parent.kind !== SyntaxKind.ParenthesizedExpression) { + write("("); + } + value = ensureIdentifier(value); + emitDestructuringAssignment(target, value); + write(", "); + emit(value); + if (root.parent.kind !== SyntaxKind.ParenthesizedExpression) { + write(")"); + } + } + } + + function emitBindingElement(target: BindingElement, value: Expression) { + if (target.initializer) { + // Combine value and initializer + value = value ? createDefaultValueCheck(value, target.initializer) : target.initializer; + } + else if (!value) { + // Use 'void 0' in absence of value and initializer + value = createVoidZero(); + } + if (isBindingPattern(target.name)) { + let pattern = target.name; + let elements = pattern.elements; + if (elements.length !== 1) { + // For anything but a single element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. + value = ensureIdentifier(value); + } + for (let i = 0; i < elements.length; i++) { + let element = elements[i]; + if (pattern.kind === SyntaxKind.ObjectBindingPattern) { + // Rewrite element to a declaration with an initializer that fetches property + let propName = element.propertyName || element.name; + emitBindingElement(element, createPropertyAccessForDestructuringProperty(value, propName)); + } + else if (element.kind !== SyntaxKind.OmittedExpression) { + if (!element.dotDotDotToken) { + // Rewrite element to a declaration that accesses array element at index i + emitBindingElement(element, createElementAccessExpression(value, createNumericLiteral(i))); + } + else if (i === elements.length - 1) { + emitBindingElement(element, createSliceCall(value, i)); + } + } + } + } + else { + emitAssignment(target.name, value); + } + } + } + + function emitVariableDeclaration(node: VariableDeclaration) { + if (isBindingPattern(node.name)) { + if (languageVersion < ScriptTarget.ES6) { + emitDestructuring(node, /*isAssignmentExpressionStatement*/ false); + } + else { + emit(node.name); + emitOptional(" = ", node.initializer); + } + } + else { + renameNonTopLevelLetAndConst(node.name); + emitModuleMemberName(node); + + let initializer = node.initializer; + if (!initializer && languageVersion < ScriptTarget.ES6) { + + // downlevel emit for non-initialized let bindings defined in loops + // for (...) { let x; } + // should be + // for (...) { var = void 0; } + // this is necessary to preserve ES6 semantic in scenarios like + // for (...) { let x; console.log(x); x = 1 } // assignment on one iteration should not affect other iterations + let isUninitializedLet = + (resolver.getNodeCheckFlags(node) & NodeCheckFlags.BlockScopedBindingInLoop) && + (getCombinedFlagsForIdentifier(node.name) & NodeFlags.Let); + + // NOTE: default initialization should not be added to let bindings in for-in\for-of statements + if (isUninitializedLet && + node.parent.parent.kind !== SyntaxKind.ForInStatement && + node.parent.parent.kind !== SyntaxKind.ForOfStatement) { + initializer = createVoidZero(); + } + } + + emitOptional(" = ", initializer); + } + } + + function emitExportVariableAssignments(node: VariableDeclaration | BindingElement) { + if (node.kind === SyntaxKind.OmittedExpression) { + return; + } + let name = node.name; + if (name.kind === SyntaxKind.Identifier) { + emitExportMemberAssignments(name); + } + else if (isBindingPattern(name)) { + forEach((name).elements, emitExportVariableAssignments); + } + } + + function getCombinedFlagsForIdentifier(node: Identifier): NodeFlags { + if (!node.parent || (node.parent.kind !== SyntaxKind.VariableDeclaration && node.parent.kind !== SyntaxKind.BindingElement)) { + return 0; + } + + return getCombinedNodeFlags(node.parent); + } + + function renameNonTopLevelLetAndConst(node: Node): void { + // do not rename if + // - language version is ES6+ + // - node is synthesized + // - node is not identifier (can happen when tree is malformed) + // - node is definitely not name of variable declaration. + // it still can be part of parameter declaration, this check will be done next + if (languageVersion >= ScriptTarget.ES6 || + nodeIsSynthesized(node) || + node.kind !== SyntaxKind.Identifier || + (node.parent.kind !== SyntaxKind.VariableDeclaration && node.parent.kind !== SyntaxKind.BindingElement)) { + return; + } + + let combinedFlags = getCombinedFlagsForIdentifier(node); + if (((combinedFlags & NodeFlags.BlockScoped) === 0) || combinedFlags & NodeFlags.Export) { + // do not rename exported or non-block scoped variables + return; + } + + // here it is known that node is a block scoped variable + let list = getAncestor(node, SyntaxKind.VariableDeclarationList); + if (list.parent.kind === SyntaxKind.VariableStatement) { + let isSourceFileLevelBinding = list.parent.parent.kind === SyntaxKind.SourceFile; + let isModuleLevelBinding = list.parent.parent.kind === SyntaxKind.ModuleBlock; + let isFunctionLevelBinding = + list.parent.parent.kind === SyntaxKind.Block && isFunctionLike(list.parent.parent.parent); + if (isSourceFileLevelBinding || isModuleLevelBinding || isFunctionLevelBinding) { + return; + } + } + + let blockScopeContainer = getEnclosingBlockScopeContainer(node); + let parent = blockScopeContainer.kind === SyntaxKind.SourceFile + ? blockScopeContainer + : blockScopeContainer.parent; + + if (resolver.resolvesToSomeValue(parent, (node).text)) { + let variableId = resolver.getBlockScopedVariableId(node); + if (!blockScopedVariableToGeneratedName) { + blockScopedVariableToGeneratedName = []; + } + + let generatedName = makeUniqueName((node).text); + blockScopedVariableToGeneratedName[variableId] = generatedName; + } + } + + function isES6ExportedDeclaration(node: Node) { + return !!(node.flags & NodeFlags.Export) && + languageVersion >= ScriptTarget.ES6 && + node.parent.kind === SyntaxKind.SourceFile; + } + + function emitVariableStatement(node: VariableStatement) { + if (!(node.flags & NodeFlags.Export)) { + emitStartOfVariableDeclarationList(node.declarationList); + } + else if (isES6ExportedDeclaration(node)) { + // Exported ES6 module member + write("export "); + emitStartOfVariableDeclarationList(node.declarationList); + } + emitCommaList(node.declarationList.declarations); + write(";"); + if (languageVersion < ScriptTarget.ES6 && node.parent === currentSourceFile) { + forEach(node.declarationList.declarations, emitExportVariableAssignments); + } + } + + function emitParameter(node: ParameterDeclaration) { + if (languageVersion < ScriptTarget.ES6) { + if (isBindingPattern(node.name)) { + let name = createTempVariable(TempFlags.Auto); + if (!tempParameters) { + tempParameters = []; + } + tempParameters.push(name); + emit(name); + } + else { + emit(node.name); + } + } + else { + if (node.dotDotDotToken) { + write("..."); + } + emit(node.name); + emitOptional(" = ", node.initializer); + } + } + + function emitDefaultValueAssignments(node: FunctionLikeDeclaration) { + if (languageVersion < ScriptTarget.ES6) { + let tempIndex = 0; + forEach(node.parameters, p => { + // A rest parameter cannot have a binding pattern or an initializer, + // so let's just ignore it. + if (p.dotDotDotToken) { + return; + } + + if (isBindingPattern(p.name)) { + writeLine(); + write("var "); + emitDestructuring(p, /*isAssignmentExpressionStatement*/ false, tempParameters[tempIndex]); + write(";"); + tempIndex++; + } + else if (p.initializer) { + writeLine(); + emitStart(p); + write("if ("); + emitNodeWithoutSourceMap(p.name); + write(" === void 0)"); + emitEnd(p); + write(" { "); + emitStart(p); + emitNodeWithoutSourceMap(p.name); + write(" = "); + emitNodeWithoutSourceMap(p.initializer); + emitEnd(p); + write("; }"); + } + }); + } + } + + function emitRestParameter(node: FunctionLikeDeclaration) { + if (languageVersion < ScriptTarget.ES6 && hasRestParameters(node)) { + let restIndex = node.parameters.length - 1; + let restParam = node.parameters[restIndex]; + + // A rest parameter cannot have a binding pattern, so let's just ignore it if it does. + if (isBindingPattern(restParam.name)) { + return; + } + + let tempName = createTempVariable(TempFlags._i).text; + writeLine(); + emitLeadingComments(restParam); + emitStart(restParam); + write("var "); + emitNodeWithoutSourceMap(restParam.name); + write(" = [];"); + emitEnd(restParam); + emitTrailingComments(restParam); + writeLine(); + write("for ("); + emitStart(restParam); + write("var " + tempName + " = " + restIndex + ";"); + emitEnd(restParam); + write(" "); + emitStart(restParam); + write(tempName + " < arguments.length;"); + emitEnd(restParam); + write(" "); + emitStart(restParam); + write(tempName + "++"); + emitEnd(restParam); + write(") {"); + increaseIndent(); + writeLine(); + emitStart(restParam); + emitNodeWithoutSourceMap(restParam.name); + write("[" + tempName + " - " + restIndex + "] = arguments[" + tempName + "];"); + emitEnd(restParam); + decreaseIndent(); + writeLine(); + write("}"); + } + } + + function emitAccessor(node: AccessorDeclaration) { + write(node.kind === SyntaxKind.GetAccessor ? "get " : "set "); + emit(node.name, /*allowGeneratedIdentifiers*/ false); + emitSignatureAndBody(node); + } + + function shouldEmitAsArrowFunction(node: FunctionLikeDeclaration): boolean { + return node.kind === SyntaxKind.ArrowFunction && languageVersion >= ScriptTarget.ES6; + } + + function emitDeclarationName(node: Declaration) { + if (node.name) { + emitNodeWithoutSourceMap(node.name); + } + else { + write(getGeneratedNameForNode(node)); + } + } + + function shouldEmitFunctionName(node: FunctionLikeDeclaration) { + if (node.kind === SyntaxKind.FunctionExpression) { + // Emit name if one is present + return !!node.name; + } + if (node.kind === SyntaxKind.FunctionDeclaration) { + // Emit name if one is present, or emit generated name in down-level case (for export default case) + return !!node.name || languageVersion < ScriptTarget.ES6; + } + } + + function emitFunctionDeclaration(node: FunctionLikeDeclaration) { + if (nodeIsMissing(node.body)) { + return emitOnlyPinnedOrTripleSlashComments(node); + } + + if (node.kind !== SyntaxKind.MethodDeclaration && node.kind !== SyntaxKind.MethodSignature) { + // Methods will emit the comments as part of emitting method declaration + emitLeadingComments(node); + } + + // For targeting below es6, emit functions-like declaration including arrow function using function keyword. + // When targeting ES6, emit arrow function natively in ES6 by omitting function keyword and using fat arrow instead + if (!shouldEmitAsArrowFunction(node)) { + if (isES6ExportedDeclaration(node)) { + write("export "); + if (node.flags & NodeFlags.Default) { + write("default "); + } + } + + write("function"); + if (languageVersion >= ScriptTarget.ES6 && node.asteriskToken) { + write("*"); + } + write(" "); + } + + if (shouldEmitFunctionName(node)) { + emitDeclarationName(node); + } + + emitSignatureAndBody(node); + if (languageVersion < ScriptTarget.ES6 && node.kind === SyntaxKind.FunctionDeclaration && node.parent === currentSourceFile && node.name) { + emitExportMemberAssignments((node).name); + } + if (node.kind !== SyntaxKind.MethodDeclaration && node.kind !== SyntaxKind.MethodSignature) { + emitTrailingComments(node); + } + } + + function emitCaptureThisForNodeIfNecessary(node: Node): void { + if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.CaptureThis) { + writeLine(); + emitStart(node); + write("var _this = this;"); + emitEnd(node); + } + } + + function emitSignatureParameters(node: FunctionLikeDeclaration) { + increaseIndent(); + write("("); + if (node) { + let parameters = node.parameters; + let omitCount = languageVersion < ScriptTarget.ES6 && hasRestParameters(node) ? 1 : 0; + emitList(parameters, 0, parameters.length - omitCount, /*multiLine*/ false, /*trailingComma*/ false); + } + write(")"); + decreaseIndent(); + } + + function emitSignatureParametersForArrow(node: FunctionLikeDeclaration) { + // Check whether the parameter list needs parentheses and preserve no-parenthesis + if (node.parameters.length === 1 && node.pos === node.parameters[0].pos) { + emit(node.parameters[0]); + return; + } + emitSignatureParameters(node); + } + + function emitSignatureAndBody(node: FunctionLikeDeclaration) { + let saveTempFlags = tempFlags; + let saveTempVariables = tempVariables; + let saveTempParameters = tempParameters; + tempFlags = 0; + tempVariables = undefined; + tempParameters = undefined; + + // When targeting ES6, emit arrow function natively in ES6 + if (shouldEmitAsArrowFunction(node)) { + emitSignatureParametersForArrow(node); + write(" =>"); + } + else { + emitSignatureParameters(node); + } + + if (!node.body) { + // There can be no body when there are parse errors. Just emit an empty block + // in that case. + write(" { }"); + } + else if (node.body.kind === SyntaxKind.Block) { + emitBlockFunctionBody(node, node.body); + } + else { + emitExpressionFunctionBody(node, node.body); + } + + if (!isES6ExportedDeclaration(node)) { + emitExportMemberAssignment(node); + } + + tempFlags = saveTempFlags; + tempVariables = saveTempVariables; + tempParameters = saveTempParameters; + } + + // Returns true if any preamble code was emitted. + function emitFunctionBodyPreamble(node: FunctionLikeDeclaration): void { + emitCaptureThisForNodeIfNecessary(node); + emitDefaultValueAssignments(node); + emitRestParameter(node); + } + + function emitExpressionFunctionBody(node: FunctionLikeDeclaration, body: Expression) { + if (languageVersion < ScriptTarget.ES6) { + emitDownLevelExpressionFunctionBody(node, body); + return; + } + + // For es6 and higher we can emit the expression as is. However, in the case + // where the expression might end up looking like a block when emitted, we'll + // also wrap it in parentheses first. For example if you have: a => {} + // then we need to generate: a => ({}) + write(" "); + + // Unwrap all type assertions. + let current = body; + while (current.kind === SyntaxKind.TypeAssertionExpression) { + current = (current).expression; + } + + emitParenthesizedIf(body, current.kind === SyntaxKind.ObjectLiteralExpression); + } + + function emitDownLevelExpressionFunctionBody(node: FunctionLikeDeclaration, body: Expression) { + write(" {"); + scopeEmitStart(node); + + increaseIndent(); + let outPos = writer.getTextPos(); + emitDetachedComments(node.body); + emitFunctionBodyPreamble(node); + let preambleEmitted = writer.getTextPos() !== outPos; + decreaseIndent(); + + // If we didn't have to emit any preamble code, then attempt to keep the arrow + // function on one line. + if (!preambleEmitted && nodeStartPositionsAreOnSameLine(node, body)) { + write(" "); + emitStart(body); + write("return "); + emit(body); + emitEnd(body); + write(";"); + emitTempDeclarations(/*newLine*/ false); + write(" "); + } + else { + increaseIndent(); + writeLine(); + emitLeadingComments(node.body); + write("return "); + emit(body); + write(";"); + emitTrailingComments(node.body); + + emitTempDeclarations(/*newLine*/ true); + decreaseIndent(); + writeLine(); + } + + emitStart(node.body); + write("}"); + emitEnd(node.body); + + scopeEmitEnd(); + } + + function emitBlockFunctionBody(node: FunctionLikeDeclaration, body: Block) { + write(" {"); + scopeEmitStart(node); + + let initialTextPos = writer.getTextPos(); + + increaseIndent(); + emitDetachedComments(body.statements); + + // Emit all the directive prologues (like "use strict"). These have to come before + // any other preamble code we write (like parameter initializers). + let startIndex = emitDirectivePrologues(body.statements, /*startWithNewLine*/ true); + emitFunctionBodyPreamble(node); + decreaseIndent(); + + let preambleEmitted = writer.getTextPos() !== initialTextPos; + + if (!preambleEmitted && nodeEndIsOnSameLineAsNodeStart(body, body)) { + for (let statement of body.statements) { + write(" "); + emit(statement); + } + emitTempDeclarations(/*newLine*/ false); + write(" "); + emitLeadingCommentsOfPosition(body.statements.end); + } + else { + increaseIndent(); + emitLinesStartingAt(body.statements, startIndex); + emitTempDeclarations(/*newLine*/ true); + + writeLine(); + emitLeadingCommentsOfPosition(body.statements.end); + decreaseIndent(); + } + + emitToken(SyntaxKind.CloseBraceToken, body.statements.end); + scopeEmitEnd(); + } + + function findInitialSuperCall(ctor: ConstructorDeclaration): ExpressionStatement { + if (ctor.body) { + let statement = (ctor.body).statements[0]; + if (statement && statement.kind === SyntaxKind.ExpressionStatement) { + let expr = (statement).expression; + if (expr && expr.kind === SyntaxKind.CallExpression) { + let func = (expr).expression; + if (func && func.kind === SyntaxKind.SuperKeyword) { + return statement; + } + } + } + } + } + + function emitParameterPropertyAssignments(node: ConstructorDeclaration) { + forEach(node.parameters, param => { + if (param.flags & NodeFlags.AccessibilityModifier) { + writeLine(); + emitStart(param); + emitStart(param.name); + write("this."); + emitNodeWithoutSourceMap(param.name); + emitEnd(param.name); + write(" = "); + emit(param.name); + write(";"); + emitEnd(param); + } + }); + } + + function emitMemberAccessForPropertyName(memberName: DeclarationName) { + // TODO: (jfreeman,drosen): comment on why this is emitNodeWithoutSourceMap instead of emit here. + if (memberName.kind === SyntaxKind.StringLiteral || memberName.kind === SyntaxKind.NumericLiteral) { + write("["); + emitNodeWithoutSourceMap(memberName); + write("]"); + } + else if (memberName.kind === SyntaxKind.ComputedPropertyName) { + emitComputedPropertyName(memberName); + } + else { + write("."); + emitNodeWithoutSourceMap(memberName); + } + } + + function getInitializedProperties(node: ClassLikeDeclaration, static: boolean) { + let properties: PropertyDeclaration[] = []; + for (let member of node.members) { + if (member.kind === SyntaxKind.PropertyDeclaration && static === ((member.flags & NodeFlags.Static) !== 0) && (member).initializer) { + properties.push(member); + } + } + + return properties; + } + + function emitPropertyDeclarations(node: ClassLikeDeclaration, properties: PropertyDeclaration[]) { + for (let property of properties) { + emitPropertyDeclaration(node, property); + } + } + + function emitPropertyDeclaration(node: ClassLikeDeclaration, property: PropertyDeclaration, receiver?: Identifier, isExpression?: boolean) { + writeLine(); + emitLeadingComments(property); + emitStart(property); + emitStart(property.name); + if (receiver) { + emit(receiver); + } + else { + if (property.flags & NodeFlags.Static) { + emitDeclarationName(node); + } + else { + write("this"); + } + } + emitMemberAccessForPropertyName(property.name); + emitEnd(property.name); + write(" = "); + emit(property.initializer); + if (!isExpression) { + write(";"); + } + + emitEnd(property); + emitTrailingComments(property); + } + + function emitMemberFunctionsForES5AndLower(node: ClassLikeDeclaration) { + forEach(node.members, member => { + if (member.kind === SyntaxKind.SemicolonClassElement) { + writeLine(); + write(";"); + } + else if (member.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) { + if (!(member).body) { + return emitOnlyPinnedOrTripleSlashComments(member); + } + + writeLine(); + emitLeadingComments(member); + emitStart(member); + emitStart((member).name); + emitClassMemberPrefix(node, member); + emitMemberAccessForPropertyName((member).name); + emitEnd((member).name); + write(" = "); + emitStart(member); + emitFunctionDeclaration(member); + emitEnd(member); + emitEnd(member); + write(";"); + emitTrailingComments(member); + } + else if (member.kind === SyntaxKind.GetAccessor || member.kind === SyntaxKind.SetAccessor) { + let accessors = getAllAccessorDeclarations(node.members, member); + if (member === accessors.firstAccessor) { + writeLine(); + emitStart(member); + write("Object.defineProperty("); + emitStart((member).name); + emitClassMemberPrefix(node, member); + write(", "); + emitExpressionForPropertyName((member).name); + emitEnd((member).name); + write(", {"); + increaseIndent(); + if (accessors.getAccessor) { + writeLine(); + emitLeadingComments(accessors.getAccessor); + write("get: "); + emitStart(accessors.getAccessor); + write("function "); + emitSignatureAndBody(accessors.getAccessor); + emitEnd(accessors.getAccessor); + emitTrailingComments(accessors.getAccessor); + write(","); + } + if (accessors.setAccessor) { + writeLine(); + emitLeadingComments(accessors.setAccessor); + write("set: "); + emitStart(accessors.setAccessor); + write("function "); + emitSignatureAndBody(accessors.setAccessor); + emitEnd(accessors.setAccessor); + emitTrailingComments(accessors.setAccessor); + write(","); + } + writeLine(); + write("enumerable: true,"); + writeLine(); + write("configurable: true"); + decreaseIndent(); + writeLine(); + write("});"); + emitEnd(member); + } + } + }); + } + + function emitMemberFunctionsForES6AndHigher(node: ClassLikeDeclaration) { + for (let member of node.members) { + if ((member.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) && !(member).body) { + emitOnlyPinnedOrTripleSlashComments(member); + } + else if (member.kind === SyntaxKind.MethodDeclaration || + member.kind === SyntaxKind.GetAccessor || + member.kind === SyntaxKind.SetAccessor) { + writeLine(); + emitLeadingComments(member); + emitStart(member); + if (member.flags & NodeFlags.Static) { + write("static "); + } + + if (member.kind === SyntaxKind.GetAccessor) { + write("get "); + } + else if (member.kind === SyntaxKind.SetAccessor) { + write("set "); + } + if ((member).asteriskToken) { + write("*"); + } + emit((member).name); + emitSignatureAndBody(member); + emitEnd(member); + emitTrailingComments(member); + } + else if (member.kind === SyntaxKind.SemicolonClassElement) { + writeLine(); + write(";"); + } + } + } + + function emitConstructor(node: ClassLikeDeclaration, baseTypeElement: HeritageClauseElement) { + let saveTempFlags = tempFlags; + let saveTempVariables = tempVariables; + let saveTempParameters = tempParameters; + tempFlags = 0; + tempVariables = undefined; + tempParameters = undefined; + + emitConstructorWorker(node, baseTypeElement); + + tempFlags = saveTempFlags; + tempVariables = saveTempVariables; + tempParameters = saveTempParameters; + } + + function emitConstructorWorker(node: ClassLikeDeclaration, baseTypeElement: HeritageClauseElement) { + // Check if we have property assignment inside class declaration. + // If there is property assignment, we need to emit constructor whether users define it or not + // If there is no property assignment, we can omit constructor if users do not define it + let hasInstancePropertyWithInitializer = false; + + // Emit the constructor overload pinned comments + forEach(node.members, member => { + if (member.kind === SyntaxKind.Constructor && !(member).body) { + emitOnlyPinnedOrTripleSlashComments(member); + } + // Check if there is any non-static property assignment + if (member.kind === SyntaxKind.PropertyDeclaration && (member).initializer && (member.flags & NodeFlags.Static) === 0) { + hasInstancePropertyWithInitializer = true; + } + }); + + let ctor = getFirstConstructorWithBody(node); + + // For target ES6 and above, if there is no user-defined constructor and there is no property assignment + // do not emit constructor in class declaration. + if (languageVersion >= ScriptTarget.ES6 && !ctor && !hasInstancePropertyWithInitializer) { + return; + } + + if (ctor) { + emitLeadingComments(ctor); + } + emitStart(ctor || node); + + if (languageVersion < ScriptTarget.ES6) { + write("function "); + emitDeclarationName(node); + emitSignatureParameters(ctor); + } + else { + write("constructor"); + if (ctor) { + emitSignatureParameters(ctor); + } + else { + // Based on EcmaScript6 section 14.5.14: Runtime Semantics: ClassDefinitionEvaluation. + // If constructor is empty, then, + // If ClassHeritageopt is present, then + // Let constructor be the result of parsing the String "constructor(... args){ super (...args);}" using the syntactic grammar with the goal symbol MethodDefinition. + // Else, + // Let constructor be the result of parsing the String "constructor( ){ }" using the syntactic grammar with the goal symbol MethodDefinition + if (baseTypeElement) { + write("(...args)"); + } + else { + write("()"); + } + } + } + + write(" {"); + scopeEmitStart(node, "constructor"); + increaseIndent(); + if (ctor) { + emitDetachedComments(ctor.body.statements); + } + emitCaptureThisForNodeIfNecessary(node); + if (ctor) { + emitDefaultValueAssignments(ctor); + emitRestParameter(ctor); + if (baseTypeElement) { + var superCall = findInitialSuperCall(ctor); + if (superCall) { + writeLine(); + emit(superCall); + } + } + emitParameterPropertyAssignments(ctor); + } + else { + if (baseTypeElement) { + writeLine(); + emitStart(baseTypeElement); + if (languageVersion < ScriptTarget.ES6) { + write("_super.apply(this, arguments);"); + } + else { + write("super(...args);"); + } + emitEnd(baseTypeElement); + } + } + emitPropertyDeclarations(node, getInitializedProperties(node, /*static:*/ false)); + if (ctor) { + var statements: Node[] = (ctor.body).statements; + if (superCall) { + statements = statements.slice(1); + } + emitLines(statements); + } + emitTempDeclarations(/*newLine*/ true); + writeLine(); + if (ctor) { + emitLeadingCommentsOfPosition((ctor.body).statements.end); + } + decreaseIndent(); + emitToken(SyntaxKind.CloseBraceToken, ctor ? (ctor.body).statements.end : node.members.end); + scopeEmitEnd(); + emitEnd(ctor || node); + if (ctor) { + emitTrailingComments(ctor); + } + } + + function emitClassExpression(node: ClassExpression) { + return emitClassLikeDeclaration(node); + } + + function emitClassDeclaration(node: ClassDeclaration) { + return emitClassLikeDeclaration(node); + } + + function emitClassLikeDeclaration(node: ClassLikeDeclaration) { + if (languageVersion < ScriptTarget.ES6) { + emitClassLikeDeclarationBelowES6(node); + } + else { + emitClassLikeDeclarationForES6AndHigher(node); + } + } + + function emitClassLikeDeclarationForES6AndHigher(node: ClassLikeDeclaration) { + let thisNodeIsDecorated = nodeIsDecorated(node); + if (node.kind === SyntaxKind.ClassDeclaration) { + if (thisNodeIsDecorated) { + // To preserve the correct runtime semantics when decorators are applied to the class, + // the emit needs to follow one of the following rules: + // + // * For a local class declaration: + // + // @dec class C { + // } + // + // The emit should be: + // + // let C = class { + // }; + // Object.defineProperty(C, "name", { value: "C", configurable: true }); + // C = __decorate([dec], C); + // + // * For an exported class declaration: + // + // @dec export class C { + // } + // + // The emit should be: + // + // export let C = class { + // }; + // Object.defineProperty(C, "name", { value: "C", configurable: true }); + // C = __decorate([dec], C); + // + // * For a default export of a class declaration with a name: + // + // @dec default export class C { + // } + // + // The emit should be: + // + // let C = class { + // } + // Object.defineProperty(C, "name", { value: "C", configurable: true }); + // C = __decorate([dec], C); + // export default C; + // + // * For a default export of a class declaration without a name: + // + // @dec default export class { + // } + // + // The emit should be: + // + // let _default = class { + // } + // _default = __decorate([dec], _default); + // export default _default; + // + if (isES6ExportedDeclaration(node) && !(node.flags & NodeFlags.Default)) { + write("export "); + } + + write("let "); + emitDeclarationName(node); + write(" = "); + } + else if (isES6ExportedDeclaration(node)) { + write("export "); + if (node.flags & NodeFlags.Default) { + write("default "); + } + } + } + + // If the class has static properties, and it's a class expression, then we'll need + // to specialize the emit a bit. for a class expression of the form: + // + // class C { static a = 1; static b = 2; ... } + // + // We'll emit: + // + // (_temp = class C { ... }, _temp.a = 1, _temp.b = 2, _temp) + // + // This keeps the expression as an expression, while ensuring that the static parts + // of it have been initialized by the time it is used. + let staticProperties = getInitializedProperties(node, /*static:*/ true); + let isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === SyntaxKind.ClassExpression; + let tempVariable: Identifier; + + if (isClassExpressionWithStaticProperties) { + tempVariable = createAndRecordTempVariable(TempFlags.Auto); + write("("); + increaseIndent(); + emit(tempVariable); + write(" = ") + } + + write("class"); + + // check if this is an "export default class" as it may not have a name. Do not emit the name if the class is decorated. + if ((node.name || !(node.flags & NodeFlags.Default)) && !thisNodeIsDecorated) { + write(" "); + emitDeclarationName(node); + } + + var baseTypeNode = getClassExtendsHeritageClauseElement(node); + if (baseTypeNode) { + write(" extends "); + emit(baseTypeNode.expression); + } + + write(" {"); + increaseIndent(); + scopeEmitStart(node); + writeLine(); + emitConstructor(node, baseTypeNode); + emitMemberFunctionsForES6AndHigher(node); + decreaseIndent(); + writeLine(); + emitToken(SyntaxKind.CloseBraceToken, node.members.end); + scopeEmitEnd(); + + // For a decorated class, we need to assign its name (if it has one). This is because we emit + // the class as a class expression to avoid the double-binding of the identifier: + // + // let C = class { + // } + // Object.defineProperty(C, "name", { value: "C", configurable: true }); + // + if (thisNodeIsDecorated) { + write(";"); + if (node.name) { + writeLine(); + write("Object.defineProperty("); + emitDeclarationName(node); + write(", \"name\", { value: \""); + emitDeclarationName(node); + write("\", configurable: true });"); + writeLine(); + } + } + + // Emit static property assignment. Because classDeclaration is lexically evaluated, + // it is safe to emit static property assignment after classDeclaration + // From ES6 specification: + // HasLexicalDeclaration (N) : Determines if the argument identifier has a binding in this environment record that was created using + // a lexical declaration such as a LexicalDeclaration or a ClassDeclaration. + + if (isClassExpressionWithStaticProperties) { + for (var property of staticProperties) { + write(","); + writeLine(); + emitPropertyDeclaration(node, property, /*receiver:*/ tempVariable, /*isExpression:*/ true); + } + write(","); + writeLine(); + emit(tempVariable); + decreaseIndent(); + write(")"); + } + else { + writeLine(); + emitPropertyDeclarations(node, staticProperties); + emitDecoratorsOfClass(node); + } + + // If this is an exported class, but not on the top level (i.e. on an internal + // module), export it + if (!isES6ExportedDeclaration(node) && (node.flags & NodeFlags.Export)) { + writeLine(); + emitStart(node); + emitModuleMemberName(node); + write(" = "); + emitDeclarationName(node); + emitEnd(node); + write(";"); + } + else if (isES6ExportedDeclaration(node) && (node.flags & NodeFlags.Default) && thisNodeIsDecorated) { + // if this is a top level default export of decorated class, write the export after the declaration. + writeLine(); + write("export default "); + emitDeclarationName(node); + write(";"); + } + } + + function emitClassLikeDeclarationBelowES6(node: ClassLikeDeclaration) { + if (node.kind === SyntaxKind.ClassDeclaration) { + write("var "); + emitDeclarationName(node); + write(" = "); + } + + write("(function ("); + let baseTypeNode = getClassExtendsHeritageClauseElement(node); + if (baseTypeNode) { + write("_super"); + } + write(") {"); + let saveTempFlags = tempFlags; + let saveTempVariables = tempVariables; + let saveTempParameters = tempParameters; + let saveComputedPropertyNamesToGeneratedNames = computedPropertyNamesToGeneratedNames; + tempFlags = 0; + tempVariables = undefined; + tempParameters = undefined; + computedPropertyNamesToGeneratedNames = undefined; + increaseIndent(); + scopeEmitStart(node); + if (baseTypeNode) { + writeLine(); + emitStart(baseTypeNode); + write("__extends("); + emitDeclarationName(node); + write(", _super);"); + emitEnd(baseTypeNode); + } + writeLine(); + emitConstructor(node, baseTypeNode); + emitMemberFunctionsForES5AndLower(node); + emitPropertyDeclarations(node, getInitializedProperties(node, /*static:*/ true)); + writeLine(); + emitDecoratorsOfClass(node); + writeLine(); + emitToken(SyntaxKind.CloseBraceToken, node.members.end, () => { + write("return "); + emitDeclarationName(node); + }); + write(";"); + emitTempDeclarations(/*newLine*/ true); + tempFlags = saveTempFlags; + tempVariables = saveTempVariables; + tempParameters = saveTempParameters; + computedPropertyNamesToGeneratedNames = saveComputedPropertyNamesToGeneratedNames; + decreaseIndent(); + writeLine(); + emitToken(SyntaxKind.CloseBraceToken, node.members.end); + scopeEmitEnd(); + emitStart(node); + write(")("); + if (baseTypeNode) { + emit(baseTypeNode.expression); + } + write(")"); + if (node.kind === SyntaxKind.ClassDeclaration) { + write(";"); + } + emitEnd(node); + + if (node.kind === SyntaxKind.ClassDeclaration) { + emitExportMemberAssignment(node); + } + + if (languageVersion < ScriptTarget.ES6 && node.parent === currentSourceFile && node.name) { + emitExportMemberAssignments(node.name); + } + } + + function emitClassMemberPrefix(node: ClassLikeDeclaration, member: Node) { + emitDeclarationName(node); + if (!(member.flags & NodeFlags.Static)) { + write(".prototype"); + } + } + + function emitDecoratorsOfClass(node: ClassLikeDeclaration) { + emitDecoratorsOfMembers(node, /*staticFlag*/ 0); + emitDecoratorsOfMembers(node, NodeFlags.Static); + emitDecoratorsOfConstructor(node); + } + + function emitDecoratorsOfConstructor(node: ClassLikeDeclaration) { + let decorators = node.decorators; + let constructor = getFirstConstructorWithBody(node); + let hasDecoratedParameters = constructor && forEach(constructor.parameters, nodeIsDecorated); + + // skip decoration of the constructor if neither it nor its parameters are decorated + if (!decorators && !hasDecoratedParameters) { + return; + } + + // Emit the call to __decorate. Given the class: + // + // @dec + // class C { + // } + // + // The emit for the class is: + // + // C = __decorate([dec], C); + // + + writeLine(); + emitStart(node); + emitDeclarationName(node); + write(" = __decorate(["); + increaseIndent(); + writeLine(); + + let decoratorCount = decorators ? decorators.length : 0; + let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, decorator => { + emitStart(decorator); + emit(decorator.expression); + emitEnd(decorator); + }); + + argumentsWritten += emitDecoratorsOfParameters(constructor, /*leadingComma*/ argumentsWritten > 0); + emitSerializedTypeMetadata(node, /*leadingComma*/ argumentsWritten >= 0); + + decreaseIndent(); + writeLine(); + write("], "); + emitDeclarationName(node); + write(");"); + emitEnd(node); + writeLine(); + } + + function emitDecoratorsOfMembers(node: ClassLikeDeclaration, staticFlag: NodeFlags) { + for (let member of node.members) { + // only emit members in the correct group + if ((member.flags & NodeFlags.Static) !== staticFlag) { + continue; + } + + // skip members that cannot be decorated (such as the constructor) + if (!nodeCanBeDecorated(member)) { + continue; + } + + // skip a member if it or any of its parameters are not decorated + if (!nodeOrChildIsDecorated(member)) { + continue; + } + + // skip an accessor declaration if it is not the first accessor + let decorators: NodeArray; + let functionLikeMember: FunctionLikeDeclaration; + if (isAccessor(member)) { + let accessors = getAllAccessorDeclarations(node.members, member); + if (member !== accessors.firstAccessor) { + continue; + } + + // get the decorators from the first accessor with decorators + decorators = accessors.firstAccessor.decorators; + if (!decorators && accessors.secondAccessor) { + decorators = accessors.secondAccessor.decorators; + } + + // we only decorate parameters of the set accessor + functionLikeMember = accessors.setAccessor; + } + else { + decorators = member.decorators; + + // we only decorate the parameters here if this is a method + if (member.kind === SyntaxKind.MethodDeclaration) { + functionLikeMember = member; + } + } + + // Emit the call to __decorate. Given the following: + // + // class C { + // @dec method(@dec2 x) {} + // @dec get accessor() {} + // @dec prop; + // } + // + // The emit for a method is: + // + // Object.defineProperty(C.prototype, "method", + // __decorate([ + // dec, + // __param(0, dec2), + // __metadata("design:type", Function), + // __metadata("design:paramtypes", [Object]), + // __metadata("design:returntype", void 0) + // ], C.prototype, "method", Object.getOwnPropertyDescriptor(C.prototype, "method"))); + // + // The emit for an accessor is: + // + // Object.defineProperty(C.prototype, "accessor", + // __decorate([ + // dec + // ], C.prototype, "accessor", Object.getOwnPropertyDescriptor(C.prototype, "accessor"))); + // + // The emit for a property is: + // + // __decorate([ + // dec + // ], C.prototype, "prop"); + // + + writeLine(); + emitStart(member); + if (member.kind !== SyntaxKind.PropertyDeclaration) { + write("Object.defineProperty("); + emitStart(member.name); + emitClassMemberPrefix(node, member); + write(", "); + emitExpressionForPropertyName(member.name); + emitEnd(member.name); + write(","); + increaseIndent(); + writeLine(); + } + + write("__decorate(["); + increaseIndent(); + writeLine(); + + let decoratorCount = decorators ? decorators.length : 0; + let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, decorator => { + emitStart(decorator); + emit(decorator.expression); + emitEnd(decorator); + }); + + argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0); + emitSerializedTypeMetadata(member, argumentsWritten > 0); + + decreaseIndent(); + writeLine(); + write("], "); + emitStart(member.name); + emitClassMemberPrefix(node, member); + write(", "); + emitExpressionForPropertyName(member.name); + emitEnd(member.name); + + if (member.kind !== SyntaxKind.PropertyDeclaration) { + write(", Object.getOwnPropertyDescriptor("); + emitStart(member.name); + emitClassMemberPrefix(node, member); + write(", "); + emitExpressionForPropertyName(member.name); + emitEnd(member.name); + write("))"); + decreaseIndent(); + } + + write(");"); + emitEnd(member); + writeLine(); + } + } + + function emitDecoratorsOfParameters(node: FunctionLikeDeclaration, leadingComma: boolean): number { + let argumentsWritten = 0; + if (node) { + let parameterIndex = 0; + for (let parameter of node.parameters) { + if (nodeIsDecorated(parameter)) { + let decorators = parameter.decorators; + argumentsWritten += emitList(decorators, 0, decorators.length, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ leadingComma, /*noTrailingNewLine*/ true, decorator => { + emitStart(decorator); + write(`__param(${parameterIndex}, `); + emit(decorator.expression); + write(")"); + emitEnd(decorator); + }); + leadingComma = true; + } + ++parameterIndex; + } + } + return argumentsWritten; + } + + function shouldEmitTypeMetadata(node: Declaration): boolean { + // This method determines whether to emit the "design:type" metadata based on the node's kind. + // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata + // compiler option is set. + switch (node.kind) { + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.PropertyDeclaration: + return true; + } + + return false; + } + + function shouldEmitReturnTypeMetadata(node: Declaration): boolean { + // This method determines whether to emit the "design:returntype" metadata based on the node's kind. + // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata + // compiler option is set. + switch (node.kind) { + case SyntaxKind.MethodDeclaration: + return true; + } + return false; + } + + function shouldEmitParamTypesMetadata(node: Declaration): boolean { + // This method determines whether to emit the "design:paramtypes" metadata based on the node's kind. + // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata + // compiler option is set. + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.SetAccessor: + return true; + } + return false; + } + + function emitSerializedTypeMetadata(node: Declaration, writeComma: boolean): number { + // This method emits the serialized type metadata for a decorator target. + // The caller should have already tested whether the node has decorators. + let argumentsWritten = 0; + if (compilerOptions.emitDecoratorMetadata) { + if (shouldEmitTypeMetadata(node)) { + var serializedType = resolver.serializeTypeOfNode(node, getGeneratedNameForNode); + if (serializedType) { + if (writeComma) { + write(", "); + } + writeLine(); + write("__metadata('design:type', "); + emitSerializedType(node, serializedType); + write(")"); + argumentsWritten++; + } + } + if (shouldEmitParamTypesMetadata(node)) { + var serializedTypes = resolver.serializeParameterTypesOfNode(node, getGeneratedNameForNode); + if (serializedTypes) { + if (writeComma || argumentsWritten) { + write(", "); + } + writeLine(); + write("__metadata('design:paramtypes', ["); + for (var i = 0; i < serializedTypes.length; ++i) { + if (i > 0) { + write(", "); + } + emitSerializedType(node, serializedTypes[i]); + } + write("])"); + argumentsWritten++; + } + } + if (shouldEmitReturnTypeMetadata(node)) { + var serializedType = resolver.serializeReturnTypeOfNode(node, getGeneratedNameForNode); + if (serializedType) { + if (writeComma || argumentsWritten) { + write(", "); + } + writeLine(); + write("__metadata('design:returntype', "); + emitSerializedType(node, serializedType); + write(")"); + argumentsWritten++; + } + } + } + return argumentsWritten; + } + + function serializeTypeNameSegment(location: Node, path: string[], index: number): string { + switch (index) { + case 0: + return `typeof ${path[index]} !== 'undefined' && ${path[index]}`; + case 1: + return `${serializeTypeNameSegment(location, path, index - 1) }.${path[index]}`; + default: + let temp = createAndRecordTempVariable(TempFlags.Auto).text; + return `(${temp} = ${serializeTypeNameSegment(location, path, index - 1) }) && ${temp}.${path[index]}`; + } + } + + function emitSerializedType(location: Node, name: string | string[]): void { + if (typeof name === "string") { + write(name); + return; + } + else { + Debug.assert(name.length > 0, "Invalid serialized type name"); + write(`(${serializeTypeNameSegment(location, name, name.length - 1) }) || Object`); + } + } + + function emitInterfaceDeclaration(node: InterfaceDeclaration) { + emitOnlyPinnedOrTripleSlashComments(node); + } + + function shouldEmitEnumDeclaration(node: EnumDeclaration) { + let isConstEnum = isConst(node); + return !isConstEnum || compilerOptions.preserveConstEnums || compilerOptions.separateCompilation; + } + + function emitEnumDeclaration(node: EnumDeclaration) { + // const enums are completely erased during compilation. + if (!shouldEmitEnumDeclaration(node)) { + return; + } + + if (!(node.flags & NodeFlags.Export) || isES6ExportedDeclaration(node)) { + emitStart(node); + if (isES6ExportedDeclaration(node)) { + write("export "); + } + write("var "); + emit(node.name); + emitEnd(node); + write(";"); + } + writeLine(); + emitStart(node); + write("(function ("); + emitStart(node.name); + write(getGeneratedNameForNode(node)); + emitEnd(node.name); + write(") {"); + increaseIndent(); + scopeEmitStart(node); + emitLines(node.members); + decreaseIndent(); + writeLine(); + emitToken(SyntaxKind.CloseBraceToken, node.members.end); + scopeEmitEnd(); + write(")("); + emitModuleMemberName(node); + write(" || ("); + emitModuleMemberName(node); + write(" = {}));"); + emitEnd(node); + if (!isES6ExportedDeclaration(node) && node.flags & NodeFlags.Export) { + writeLine(); + emitStart(node); + write("var "); + emit(node.name); + write(" = "); + emitModuleMemberName(node); + emitEnd(node); + write(";"); + } + if (languageVersion < ScriptTarget.ES6 && node.parent === currentSourceFile) { + emitExportMemberAssignments(node.name); + } + } + + function emitEnumMember(node: EnumMember) { + let enumParent = node.parent; + emitStart(node); + write(getGeneratedNameForNode(enumParent)); + write("["); + write(getGeneratedNameForNode(enumParent)); + write("["); + emitExpressionForPropertyName(node.name); + write("] = "); + writeEnumMemberDeclarationValue(node); + write("] = "); + emitExpressionForPropertyName(node.name); + emitEnd(node); + write(";"); + } + + function writeEnumMemberDeclarationValue(member: EnumMember) { + let value = resolver.getConstantValue(member); + if (value !== undefined) { + write(value.toString()); + return; + } + else if (member.initializer) { + emit(member.initializer); + } + else { + write("undefined"); + } + } + + function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration: ModuleDeclaration): ModuleDeclaration { + if (moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) { + let recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration.body); + return recursiveInnerModule || moduleDeclaration.body; + } + } + + function shouldEmitModuleDeclaration(node: ModuleDeclaration) { + return isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.separateCompilation); + } + + function isModuleMergedWithES6Class(node: ModuleDeclaration) { + return languageVersion === ScriptTarget.ES6 && !!(resolver.getNodeCheckFlags(node) & NodeCheckFlags.LexicalModuleMergesWithClass); + } + + function emitModuleDeclaration(node: ModuleDeclaration) { + // Emit only if this module is non-ambient. + let shouldEmit = shouldEmitModuleDeclaration(node); + + if (!shouldEmit) { + return emitOnlyPinnedOrTripleSlashComments(node); + } + + if (!isModuleMergedWithES6Class(node)) { + emitStart(node); + if (isES6ExportedDeclaration(node)) { + write("export "); + } + + write("var "); + emit(node.name); + write(";"); + emitEnd(node); + writeLine(); + } + + emitStart(node); + write("(function ("); + emitStart(node.name); + write(getGeneratedNameForNode(node)); + emitEnd(node.name); + write(") "); + if (node.body.kind === SyntaxKind.ModuleBlock) { + let saveTempFlags = tempFlags; + let saveTempVariables = tempVariables; + tempFlags = 0; + tempVariables = undefined; + + emit(node.body); + + tempFlags = saveTempFlags; + tempVariables = saveTempVariables; + } + else { + write("{"); + increaseIndent(); + scopeEmitStart(node); + emitCaptureThisForNodeIfNecessary(node); + writeLine(); + emit(node.body); + decreaseIndent(); + writeLine(); + let moduleBlock = getInnerMostModuleDeclarationFromDottedModule(node).body; + emitToken(SyntaxKind.CloseBraceToken, moduleBlock.statements.end); + scopeEmitEnd(); + } + write(")("); + // write moduleDecl = containingModule.m only if it is not exported es6 module member + if ((node.flags & NodeFlags.Export) && !isES6ExportedDeclaration(node)) { + emit(node.name); + write(" = "); + } + emitModuleMemberName(node); + write(" || ("); + emitModuleMemberName(node); + write(" = {}));"); + emitEnd(node); + if (!isES6ExportedDeclaration(node) && node.name.kind === SyntaxKind.Identifier && node.parent === currentSourceFile) { + emitExportMemberAssignments(node.name); + } + } + + function emitRequire(moduleName: Expression) { + if (moduleName.kind === SyntaxKind.StringLiteral) { + write("require("); + emitStart(moduleName); + emitLiteral(moduleName); + emitEnd(moduleName); + emitToken(SyntaxKind.CloseParenToken, moduleName.end); + } + else { + write("require()"); + } + } + + function getNamespaceDeclarationNode(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { + if (node.kind === SyntaxKind.ImportEqualsDeclaration) { + return node; + } + let importClause = (node).importClause; + if (importClause && importClause.namedBindings && importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + return importClause.namedBindings; + } + } + + function isDefaultImport(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { + return node.kind === SyntaxKind.ImportDeclaration && (node).importClause && !!(node).importClause.name; + } + + function emitExportImportAssignments(node: Node) { + if (isAliasSymbolDeclaration(node) && resolver.isValueAliasDeclaration(node)) { + emitExportMemberAssignments((node).name); + } + forEachChild(node, emitExportImportAssignments); + } + + function emitImportDeclaration(node: ImportDeclaration) { + if (languageVersion < ScriptTarget.ES6) { + return emitExternalImportDeclaration(node); + } + + // ES6 import + if (node.importClause) { + let shouldEmitDefaultBindings = resolver.isReferencedAliasDeclaration(node.importClause); + let shouldEmitNamedBindings = node.importClause.namedBindings && resolver.isReferencedAliasDeclaration(node.importClause.namedBindings, /* checkChildren */ true); + if (shouldEmitDefaultBindings || shouldEmitNamedBindings) { + write("import "); + emitStart(node.importClause); + if (shouldEmitDefaultBindings) { + emit(node.importClause.name); + if (shouldEmitNamedBindings) { + write(", "); + } + } + if (shouldEmitNamedBindings) { + emitLeadingComments(node.importClause.namedBindings); + emitStart(node.importClause.namedBindings); + if (node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + write("* as "); + emit((node.importClause.namedBindings).name); + } + else { + write("{ "); + emitExportOrImportSpecifierList((node.importClause.namedBindings).elements, resolver.isReferencedAliasDeclaration); + write(" }"); + } + emitEnd(node.importClause.namedBindings); + emitTrailingComments(node.importClause.namedBindings); + } + + emitEnd(node.importClause); + write(" from "); + emit(node.moduleSpecifier); + write(";"); + } + } + else { + write("import "); + emit(node.moduleSpecifier); + write(";"); + } + } + + function emitExternalImportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration) { + if (contains(externalImports, node)) { + let isExportedImport = node.kind === SyntaxKind.ImportEqualsDeclaration && (node.flags & NodeFlags.Export) !== 0; + let namespaceDeclaration = getNamespaceDeclarationNode(node); + + if (compilerOptions.module !== ModuleKind.AMD) { + emitLeadingComments(node); + emitStart(node); + if (namespaceDeclaration && !isDefaultImport(node)) { + // import x = require("foo") + // import * as x from "foo" + if (!isExportedImport) write("var "); + emitModuleMemberName(namespaceDeclaration); + write(" = "); + } + else { + // import "foo" + // import x from "foo" + // import { x, y } from "foo" + // import d, * as x from "foo" + // import d, { x, y } from "foo" + let isNakedImport = SyntaxKind.ImportDeclaration && !(node).importClause; + if (!isNakedImport) { + write("var "); + write(getGeneratedNameForNode(node)); + write(" = "); + } + } + emitRequire(getExternalModuleName(node)); + if (namespaceDeclaration && isDefaultImport(node)) { + // import d, * as x from "foo" + write(", "); + emitModuleMemberName(namespaceDeclaration); + write(" = "); + write(getGeneratedNameForNode(node)); + } + write(";"); + emitEnd(node); + emitExportImportAssignments(node); + emitTrailingComments(node); + } + else { + if (isExportedImport) { + emitModuleMemberName(namespaceDeclaration); + write(" = "); + emit(namespaceDeclaration.name); + write(";"); + } + else if (namespaceDeclaration && isDefaultImport(node)) { + // import d, * as x from "foo" + write("var "); + emitModuleMemberName(namespaceDeclaration); + write(" = "); + write(getGeneratedNameForNode(node)); + write(";"); + } + emitExportImportAssignments(node); + } + } + } + + function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) { + if (isExternalModuleImportEqualsDeclaration(node)) { + emitExternalImportDeclaration(node); + return; + } + // preserve old compiler's behavior: emit 'var' for import declaration (even if we do not consider them referenced) when + // - current file is not external module + // - import declaration is top level and target is value imported by entity name + if (resolver.isReferencedAliasDeclaration(node) || + (!isExternalModule(currentSourceFile) && resolver.isTopLevelValueImportEqualsWithEntityName(node))) { + emitLeadingComments(node); + emitStart(node); + if (isES6ExportedDeclaration(node)) { + write("export "); + write("var "); + } + else if (!(node.flags & NodeFlags.Export)) { + write("var "); + } + emitModuleMemberName(node); + write(" = "); + emit(node.moduleReference); + write(";"); + emitEnd(node); + emitExportImportAssignments(node); + emitTrailingComments(node); + } + } + + function emitExportDeclaration(node: ExportDeclaration) { + if (languageVersion < ScriptTarget.ES6) { + if (node.moduleSpecifier && (!node.exportClause || resolver.isValueAliasDeclaration(node))) { + emitStart(node); + let generatedName = getGeneratedNameForNode(node); + if (node.exportClause) { + // export { x, y, ... } from "foo" + if (compilerOptions.module !== ModuleKind.AMD) { + write("var "); + write(generatedName); + write(" = "); + emitRequire(getExternalModuleName(node)); + write(";"); + } + for (let specifier of node.exportClause.elements) { + if (resolver.isValueAliasDeclaration(specifier)) { + writeLine(); + emitStart(specifier); + emitContainingModuleName(specifier); + write("."); + emitNodeWithoutSourceMap(specifier.name); + write(" = "); + write(generatedName); + write("."); + emitNodeWithoutSourceMap(specifier.propertyName || specifier.name); + write(";"); + emitEnd(specifier); + } + } + } + else { + // export * from "foo" + writeLine(); + write("__export("); + if (compilerOptions.module !== ModuleKind.AMD) { + emitRequire(getExternalModuleName(node)); + } + else { + write(generatedName); + } + write(");"); + } + emitEnd(node); + } + } + else { + if (!node.exportClause || resolver.isValueAliasDeclaration(node)) { + emitStart(node); + write("export "); + if (node.exportClause) { + // export { x, y, ... } + write("{ "); + emitExportOrImportSpecifierList(node.exportClause.elements, resolver.isValueAliasDeclaration); + write(" }"); + } + else { + write("*"); + } + if (node.moduleSpecifier) { + write(" from "); + emitNodeWithoutSourceMap(node.moduleSpecifier); + } + write(";"); + emitEnd(node); + } + } + } + + function emitExportOrImportSpecifierList(specifiers: ImportOrExportSpecifier[], shouldEmit: (node: Node) => boolean) { + Debug.assert(languageVersion >= ScriptTarget.ES6); + + let needsComma = false; + for (let specifier of specifiers) { + if (shouldEmit(specifier)) { + if (needsComma) { + write(", "); + } + emitStart(specifier); + if (specifier.propertyName) { + emitNodeWithoutSourceMap(specifier.propertyName); + write(" as "); + } + emitNodeWithoutSourceMap(specifier.name); + emitEnd(specifier); + needsComma = true; + } + } + } + + function emitExportAssignment(node: ExportAssignment) { + if (!node.isExportEquals && resolver.isValueAliasDeclaration(node)) { + if (languageVersion >= ScriptTarget.ES6) { + writeLine(); + emitStart(node); + write("export default "); + var expression = node.expression; + emit(expression); + if (expression.kind !== SyntaxKind.FunctionDeclaration && + expression.kind !== SyntaxKind.ClassDeclaration) { + write(";"); + } + emitEnd(node); + } + else { + writeLine(); + emitStart(node); + emitContainingModuleName(node); + if (languageVersion === ScriptTarget.ES3) { + write("[\"default\"] = "); + } else { + write(".default = "); + } + emit(node.expression); + write(";"); + emitEnd(node); + } + } + } + + function collectExternalModuleInfo(sourceFile: SourceFile) { + externalImports = []; + exportSpecifiers = {}; + exportEquals = undefined; + hasExportStars = false; + for (let node of sourceFile.statements) { + switch (node.kind) { + case SyntaxKind.ImportDeclaration: + if (!(node).importClause || + resolver.isReferencedAliasDeclaration((node).importClause, /*checkChildren*/ true)) { + // import "mod" + // import x from "mod" where x is referenced + // import * as x from "mod" where x is referenced + // import { x, y } from "mod" where at least one import is referenced + externalImports.push(node); + } + break; + case SyntaxKind.ImportEqualsDeclaration: + if ((node).moduleReference.kind === SyntaxKind.ExternalModuleReference && resolver.isReferencedAliasDeclaration(node)) { + // import x = require("mod") where x is referenced + externalImports.push(node); + } + break; + case SyntaxKind.ExportDeclaration: + if ((node).moduleSpecifier) { + if (!(node).exportClause) { + // export * from "mod" + externalImports.push(node); + hasExportStars = true; + } + else if (resolver.isValueAliasDeclaration(node)) { + // export { x, y } from "mod" where at least one export is a value symbol + externalImports.push(node); + } + } + else { + // export { x, y } + for (let specifier of (node).exportClause.elements) { + let name = (specifier.propertyName || specifier.name).text; + (exportSpecifiers[name] || (exportSpecifiers[name] = [])).push(specifier); + } + } + break; + case SyntaxKind.ExportAssignment: + if ((node).isExportEquals && !exportEquals) { + // export = x + exportEquals = node; + } + break; + } + } + } + + function emitExportStarHelper() { + if (hasExportStars) { + writeLine(); + write("function __export(m) {"); + increaseIndent(); + writeLine(); + write("for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];"); + decreaseIndent(); + writeLine(); + write("}"); + } + } + + function emitAMDDependencies(node: SourceFile, includeNonAmdDependencies: boolean) { + // An AMD define function has the following shape: + // define(id?, dependencies?, factory); + // + // This has the shape of + // define(name, ["module1", "module2"], function (module1Alias) { + // The location of the alias in the parameter list in the factory function needs to + // match the position of the module name in the dependency list. + // + // To ensure this is true in cases of modules with no aliases, e.g.: + // `import "module"` or `` + // we need to add modules without alias names to the end of the dependencies list + + let aliasedModuleNames: string[] = []; // names of modules with corresponding parameter in the + // factory function. + let unaliasedModuleNames: string[] = []; // names of modules with no corresponding parameters in + // factory function. + let importAliasNames: string[] = []; // names of the parameters in the factory function; these + // parameters need to match the indexes of the corresponding + // module names in aliasedModuleNames. + + // Fill in amd-dependency tags + for (let amdDependency of node.amdDependencies) { + if (amdDependency.name) { + aliasedModuleNames.push("\"" + amdDependency.path + "\""); + importAliasNames.push(amdDependency.name); + } + else { + unaliasedModuleNames.push("\"" + amdDependency.path + "\""); + } + } + + for (let importNode of externalImports) { + // Find the name of the external module + let externalModuleName = ""; + let moduleName = getExternalModuleName(importNode); + if (moduleName.kind === SyntaxKind.StringLiteral) { + externalModuleName = getLiteralText(moduleName); + } + + // Find the name of the module alias, if there is one + let importAliasName: string; + let namespaceDeclaration = getNamespaceDeclarationNode(importNode); + if (namespaceDeclaration && !isDefaultImport(importNode)) { + importAliasName = getSourceTextOfNodeFromSourceFile(currentSourceFile, namespaceDeclaration.name); + } + else { + importAliasName = getGeneratedNameForNode(importNode); + } + + if (includeNonAmdDependencies && importAliasName) { + aliasedModuleNames.push(externalModuleName); + importAliasNames.push(importAliasName); + } + else { + unaliasedModuleNames.push(externalModuleName); + } + } + + write("[\"require\", \"exports\""); + if (aliasedModuleNames.length) { + write(", "); + write(aliasedModuleNames.join(", ")); + } + if (unaliasedModuleNames.length) { + write(", "); + write(unaliasedModuleNames.join(", ")); + } + write("], function (require, exports"); + if (importAliasNames.length) { + write(", "); + write(importAliasNames.join(", ")); + } + } + + function emitAMDModule(node: SourceFile, startIndex: number) { + collectExternalModuleInfo(node); + + writeLine(); + write("define("); + if (node.amdModuleName) { + write("\"" + node.amdModuleName + "\", "); + } + emitAMDDependencies(node, /*includeNonAmdDependencies*/ true); + write(") {"); + increaseIndent(); + emitExportStarHelper(); + emitCaptureThisForNodeIfNecessary(node); + emitLinesStartingAt(node.statements, startIndex); + emitTempDeclarations(/*newLine*/ true); + emitExportEquals(/*emitAsReturn*/ true); + decreaseIndent(); + writeLine(); + write("});"); + } + + function emitCommonJSModule(node: SourceFile, startIndex: number) { + collectExternalModuleInfo(node); + emitExportStarHelper(); + emitCaptureThisForNodeIfNecessary(node); + emitLinesStartingAt(node.statements, startIndex); + emitTempDeclarations(/*newLine*/ true); + emitExportEquals(/*emitAsReturn*/ false); + } + + function emitUMDModule(node: SourceFile, startIndex: number) { + collectExternalModuleInfo(node); + + // Module is detected first to support Browserify users that load into a browser with an AMD loader + writeLines(`(function (deps, factory) { + if (typeof module === 'object' && typeof module.exports === 'object') { + var v = factory(require, exports); if (v !== undefined) module.exports = v; + } + else if (typeof define === 'function' && define.amd) { + define(deps, factory); + } +})(`); + emitAMDDependencies(node, false); + write(") {"); + increaseIndent(); + emitExportStarHelper(); + emitCaptureThisForNodeIfNecessary(node); + emitLinesStartingAt(node.statements, startIndex); + emitTempDeclarations(/*newLine*/ true); + emitExportEquals(/*emitAsReturn*/ true); + decreaseIndent(); + writeLine(); + write("});"); + } + + function emitES6Module(node: SourceFile, startIndex: number) { + externalImports = undefined; + exportSpecifiers = undefined; + exportEquals = undefined; + hasExportStars = false; + emitCaptureThisForNodeIfNecessary(node); + emitLinesStartingAt(node.statements, startIndex); + emitTempDeclarations(/*newLine*/ true); + // Emit exportDefault if it exists will happen as part + // or normal statement emit. + } + + function emitExportEquals(emitAsReturn: boolean) { + if (exportEquals && resolver.isValueAliasDeclaration(exportEquals)) { + writeLine(); + emitStart(exportEquals); + write(emitAsReturn ? "return " : "module.exports = "); + emit((exportEquals).expression); + write(";"); + emitEnd(exportEquals); + } + } + + function emitDirectivePrologues(statements: Node[], startWithNewLine: boolean): number { + for (let i = 0; i < statements.length; ++i) { + if (isPrologueDirective(statements[i])) { + if (startWithNewLine || i > 0) { + writeLine(); + } + emit(statements[i]); + } + else { + // return index of the first non prologue directive + return i; + } + } + return statements.length; + } + + function writeLines(text: string): void { + let lines = text.split(/\r\n|\r|\n/g); + for (let i = 0; i < lines.length; ++i) { + let line = lines[i]; + if (line.length) { + writeLine(); + write(line); + } + } + } + + function emitSourceFileNode(node: SourceFile) { + // Start new file on new line + writeLine(); + emitDetachedComments(node); + + // emit prologue directives prior to __extends + var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ false); + // Only Emit __extends function when target ES5. + // For target ES6 and above, we can emit classDeclaration as is. + if ((languageVersion < ScriptTarget.ES6) && (!extendsEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitExtends)) { + writeLines(extendsHelper); + extendsEmitted = true; + } + + if (!decorateEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitDecorate) { + writeLines(decorateHelper); + if (compilerOptions.emitDecoratorMetadata) { + writeLines(metadataHelper); + } + decorateEmitted = true; + } + + if (!paramEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitParam) { + writeLines(paramHelper); + paramEmitted = true; + } + + if (isExternalModule(node)) { + if (languageVersion >= ScriptTarget.ES6) { + emitES6Module(node, startIndex); + } + else if (compilerOptions.module === ModuleKind.AMD) { + emitAMDModule(node, startIndex); + } + else if (compilerOptions.module === ModuleKind.UMD) { + emitUMDModule(node, startIndex); + } + else { + emitCommonJSModule(node, startIndex); + } + } + else { + externalImports = undefined; + exportSpecifiers = undefined; + exportEquals = undefined; + hasExportStars = false; + emitCaptureThisForNodeIfNecessary(node); + emitLinesStartingAt(node.statements, startIndex); + emitTempDeclarations(/*newLine*/ true); + } + + emitLeadingComments(node.endOfFileToken); + } + + function emitNodeWithoutSourceMap(node: Node, allowGeneratedIdentifiers?: boolean): void { + if (!node) { + return; + } + + if (node.flags & NodeFlags.Ambient) { + return emitOnlyPinnedOrTripleSlashComments(node); + } + + let emitComments = shouldEmitLeadingAndTrailingComments(node); + if (emitComments) { + emitLeadingComments(node); + } + + emitJavaScriptWorker(node, allowGeneratedIdentifiers); + + if (emitComments) { + emitTrailingComments(node); + } + } + + function shouldEmitLeadingAndTrailingComments(node: Node) { + switch (node.kind) { + // All of these entities are emitted in a specialized fashion. As such, we allow + // the specialized methods for each to handle the comments on the nodes. + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.ExportAssignment: + return false; + + case SyntaxKind.ModuleDeclaration: + // Only emit the leading/trailing comments for a module if we're actually + // emitting the module as well. + return shouldEmitModuleDeclaration(node); + + case SyntaxKind.EnumDeclaration: + // Only emit the leading/trailing comments for an enum if we're actually + // emitting the module as well. + return shouldEmitEnumDeclaration(node); + } + + // If this is the expression body of an arrow function that we're down-leveling, + // then we don't want to emit comments when we emit the body. It will have already + // been taken care of when we emitted the 'return' statement for the function + // expression body. + if (node.kind !== SyntaxKind.Block && + node.parent && + node.parent.kind === SyntaxKind.ArrowFunction && + (node.parent).body === node && + compilerOptions.target <= ScriptTarget.ES5) { + + return false; + } + + // Emit comments for everything else. + return true; + } + + function emitJavaScriptWorker(node: Node, allowGeneratedIdentifiers: boolean = true) { + // Check if the node can be emitted regardless of the ScriptTarget + switch (node.kind) { + case SyntaxKind.Identifier: + return emitIdentifier(node, allowGeneratedIdentifiers); + case SyntaxKind.Parameter: + return emitParameter(node); + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + return emitMethod(node); + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return emitAccessor(node); + case SyntaxKind.ThisKeyword: + return emitThis(node); + case SyntaxKind.SuperKeyword: + return emitSuper(node); + case SyntaxKind.NullKeyword: + return write("null"); + case SyntaxKind.TrueKeyword: + return write("true"); + case SyntaxKind.FalseKeyword: + return write("false"); + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + return emitLiteral(node); + case SyntaxKind.TemplateExpression: + return emitTemplateExpression(node); + case SyntaxKind.TemplateSpan: + return emitTemplateSpan(node); + case SyntaxKind.QualifiedName: + return emitQualifiedName(node); + case SyntaxKind.ObjectBindingPattern: + return emitObjectBindingPattern(node); + case SyntaxKind.ArrayBindingPattern: + return emitArrayBindingPattern(node); + case SyntaxKind.BindingElement: + return emitBindingElement(node); + case SyntaxKind.ArrayLiteralExpression: + return emitArrayLiteral(node); + case SyntaxKind.ObjectLiteralExpression: + return emitObjectLiteral(node); + case SyntaxKind.PropertyAssignment: + return emitPropertyAssignment(node); + case SyntaxKind.ShorthandPropertyAssignment: + return emitShorthandPropertyAssignment(node); + case SyntaxKind.ComputedPropertyName: + return emitComputedPropertyName(node); + case SyntaxKind.PropertyAccessExpression: + return emitPropertyAccess(node); + case SyntaxKind.ElementAccessExpression: + return emitIndexedAccess(node); + case SyntaxKind.CallExpression: + return emitCallExpression(node); + case SyntaxKind.NewExpression: + return emitNewExpression(node); + case SyntaxKind.TaggedTemplateExpression: + return emitTaggedTemplateExpression(node); + case SyntaxKind.TypeAssertionExpression: + return emit((node).expression); + case SyntaxKind.ParenthesizedExpression: + return emitParenExpression(node); + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + return emitFunctionDeclaration(node); + case SyntaxKind.DeleteExpression: + return emitDeleteExpression(node); + case SyntaxKind.TypeOfExpression: + return emitTypeOfExpression(node); + case SyntaxKind.VoidExpression: + return emitVoidExpression(node); + case SyntaxKind.PrefixUnaryExpression: + return emitPrefixUnaryExpression(node); + case SyntaxKind.PostfixUnaryExpression: + return emitPostfixUnaryExpression(node); + case SyntaxKind.BinaryExpression: + return emitBinaryExpression(node); + case SyntaxKind.ConditionalExpression: + return emitConditionalExpression(node); + case SyntaxKind.SpreadElementExpression: + return emitSpreadElementExpression(node); + case SyntaxKind.YieldExpression: + return emitYieldExpression(node); + case SyntaxKind.OmittedExpression: + return; + case SyntaxKind.Block: + case SyntaxKind.ModuleBlock: + return emitBlock(node); + case SyntaxKind.VariableStatement: + return emitVariableStatement(node); + case SyntaxKind.EmptyStatement: + return write(";"); + case SyntaxKind.ExpressionStatement: + return emitExpressionStatement(node); + case SyntaxKind.IfStatement: + return emitIfStatement(node); + case SyntaxKind.DoStatement: + return emitDoStatement(node); + case SyntaxKind.WhileStatement: + return emitWhileStatement(node); + case SyntaxKind.ForStatement: + return emitForStatement(node); + case SyntaxKind.ForOfStatement: + case SyntaxKind.ForInStatement: + return emitForInOrForOfStatement(node); + case SyntaxKind.ContinueStatement: + case SyntaxKind.BreakStatement: + return emitBreakOrContinueStatement(node); + case SyntaxKind.ReturnStatement: + return emitReturnStatement(node); + case SyntaxKind.WithStatement: + return emitWithStatement(node); + case SyntaxKind.SwitchStatement: + return emitSwitchStatement(node); + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + return emitCaseOrDefaultClause(node); + case SyntaxKind.LabeledStatement: + return emitLabelledStatement(node); + case SyntaxKind.ThrowStatement: + return emitThrowStatement(node); + case SyntaxKind.TryStatement: + return emitTryStatement(node); + case SyntaxKind.CatchClause: + return emitCatchClause(node); + case SyntaxKind.DebuggerStatement: + return emitDebuggerStatement(node); + case SyntaxKind.VariableDeclaration: + return emitVariableDeclaration(node); + case SyntaxKind.ClassExpression: + return emitClassExpression(node); + case SyntaxKind.ClassDeclaration: + return emitClassDeclaration(node); + case SyntaxKind.InterfaceDeclaration: + return emitInterfaceDeclaration(node); + case SyntaxKind.EnumDeclaration: + return emitEnumDeclaration(node); + case SyntaxKind.EnumMember: + return emitEnumMember(node); + case SyntaxKind.ModuleDeclaration: + return emitModuleDeclaration(node); + case SyntaxKind.ImportDeclaration: + return emitImportDeclaration(node); + case SyntaxKind.ImportEqualsDeclaration: + return emitImportEqualsDeclaration(node); + case SyntaxKind.ExportDeclaration: + return emitExportDeclaration(node); + case SyntaxKind.ExportAssignment: + return emitExportAssignment(node); + case SyntaxKind.SourceFile: + return emitSourceFileNode(node); + } + } + + function hasDetachedComments(pos: number) { + return detachedCommentsInfo !== undefined && detachedCommentsInfo[detachedCommentsInfo.length - 1].nodePos === pos; + } + + function getLeadingCommentsWithoutDetachedComments() { + // get the leading comments from detachedPos + let leadingComments = getLeadingCommentRanges(currentSourceFile.text, + detachedCommentsInfo[detachedCommentsInfo.length - 1].detachedCommentEndPos); + if (detachedCommentsInfo.length - 1) { + detachedCommentsInfo.pop(); + } + else { + detachedCommentsInfo = undefined; + } + + return leadingComments; + } + + function filterComments(ranges: CommentRange[], onlyPinnedOrTripleSlashComments: boolean): CommentRange[] { + // If we're removing comments, then we want to strip out all but the pinned or + // triple slash comments. + if (ranges && onlyPinnedOrTripleSlashComments) { + ranges = filter(ranges, isPinnedOrTripleSlashComment); + if (ranges.length === 0) { + return undefined; + } + } + + return ranges; + } + + function getLeadingCommentsToEmit(node: Node) { + // Emit the leading comments only if the parent's pos doesn't match because parent should take care of emitting these comments + if (node.parent) { + if (node.parent.kind === SyntaxKind.SourceFile || node.pos !== node.parent.pos) { + if (hasDetachedComments(node.pos)) { + // get comments without detached comments + return getLeadingCommentsWithoutDetachedComments(); + } + else { + // get the leading comments from the node + return getLeadingCommentRangesOfNode(node, currentSourceFile); + } + } + } + } + + function getTrailingCommentsToEmit(node: Node) { + // Emit the trailing comments only if the parent's pos doesn't match because parent should take care of emitting these comments + if (node.parent) { + if (node.parent.kind === SyntaxKind.SourceFile || node.end !== node.parent.end) { + return getTrailingCommentRanges(currentSourceFile.text, node.end); + } + } + } + + function emitOnlyPinnedOrTripleSlashComments(node: Node) { + emitLeadingCommentsWorker(node, /*onlyPinnedOrTripleSlashComments:*/ true); + } + + function emitLeadingComments(node: Node) { + return emitLeadingCommentsWorker(node, /*onlyPinnedOrTripleSlashComments:*/ compilerOptions.removeComments); + } + + function emitLeadingCommentsWorker(node: Node, onlyPinnedOrTripleSlashComments: boolean) { + // If the caller only wants pinned or triple slash comments, then always filter + // down to that set. Otherwise, filter based on the current compiler options. + let leadingComments = filterComments(getLeadingCommentsToEmit(node), onlyPinnedOrTripleSlashComments); + + emitNewLineBeforeLeadingComments(currentSourceFile, writer, node, leadingComments); + + // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space + emitComments(currentSourceFile, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment); + } + + function emitTrailingComments(node: Node) { + // Emit the trailing comments only if the parent's end doesn't match + var trailingComments = filterComments(getTrailingCommentsToEmit(node), /*onlyPinnedOrTripleSlashComments:*/ compilerOptions.removeComments); + + // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/ + emitComments(currentSourceFile, writer, trailingComments, /*trailingSeparator*/ false, newLine, writeComment); + } + + function emitLeadingCommentsOfPosition(pos: number) { + let leadingComments: CommentRange[]; + if (hasDetachedComments(pos)) { + // get comments without detached comments + leadingComments = getLeadingCommentsWithoutDetachedComments(); + } + else { + // get the leading comments from the node + leadingComments = getLeadingCommentRanges(currentSourceFile.text, pos); + } + + leadingComments = filterComments(leadingComments, compilerOptions.removeComments); + emitNewLineBeforeLeadingComments(currentSourceFile, writer, { pos: pos, end: pos }, leadingComments); + + // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space + emitComments(currentSourceFile, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment); + } + + function emitDetachedComments(node: TextRange) { + let leadingComments = getLeadingCommentRanges(currentSourceFile.text, node.pos); + if (leadingComments) { + let detachedComments: CommentRange[] = []; + let lastComment: CommentRange; + + forEach(leadingComments, comment => { + if (lastComment) { + let lastCommentLine = getLineOfLocalPosition(currentSourceFile, lastComment.end); + let commentLine = getLineOfLocalPosition(currentSourceFile, comment.pos); + + if (commentLine >= lastCommentLine + 2) { + // There was a blank line between the last comment and this comment. This + // comment is not part of the copyright comments. Return what we have so + // far. + return detachedComments; + } + } + + detachedComments.push(comment); + lastComment = comment; + }); + + if (detachedComments.length) { + // All comments look like they could have been part of the copyright header. Make + // sure there is at least one blank line between it and the node. If not, it's not + // a copyright header. + let lastCommentLine = getLineOfLocalPosition(currentSourceFile, detachedComments[detachedComments.length - 1].end); + let nodeLine = getLineOfLocalPosition(currentSourceFile, skipTrivia(currentSourceFile.text, node.pos)); + if (nodeLine >= lastCommentLine + 2) { + // Valid detachedComments + emitNewLineBeforeLeadingComments(currentSourceFile, writer, node, leadingComments); + emitComments(currentSourceFile, writer, detachedComments, /*trailingSeparator*/ true, newLine, writeComment); + let currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: detachedComments[detachedComments.length - 1].end }; + if (detachedCommentsInfo) { + detachedCommentsInfo.push(currentDetachedCommentInfo); + } + else { + detachedCommentsInfo = [currentDetachedCommentInfo]; + } + } + } + } + } + + function isPinnedOrTripleSlashComment(comment: CommentRange) { + if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) { + return currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation; + } + // Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text + // so that we don't end up computing comment string and doing match for all // comments + else if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.slash && + comment.pos + 2 < comment.end && + currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.slash && + currentSourceFile.text.substring(comment.pos, comment.end).match(fullTripleSlashReferencePathRegEx)) { + return true; + } + } + } + + function emitFile(jsFilePath: string, sourceFile?: SourceFile) { + emitJavaScript(jsFilePath, sourceFile); + + if (compilerOptions.declaration) { + writeDeclarationFile(jsFilePath, sourceFile, host, resolver, diagnostics); + } + } + } +} diff --git a/lib/typescript/compiler/parser.ts b/lib/typescript/compiler/parser.ts new file mode 100644 index 000000000..642db3e78 --- /dev/null +++ b/lib/typescript/compiler/parser.ts @@ -0,0 +1,5420 @@ +/// +/// + +module ts { + let nodeConstructors = new Array Node>(SyntaxKind.Count); + /* @internal */ export let parseTime = 0; + + export function getNodeConstructor(kind: SyntaxKind): new () => Node { + return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind)); + } + + export function createNode(kind: SyntaxKind): Node { + return new (getNodeConstructor(kind))(); + } + + function visitNode(cbNode: (node: Node) => T, node: Node): T { + if (node) { + return cbNode(node); + } + } + + function visitNodeArray(cbNodes: (nodes: Node[]) => T, nodes: Node[]) { + if (nodes) { + return cbNodes(nodes); + } + } + + function visitEachNode(cbNode: (node: Node) => T, nodes: Node[]) { + if (nodes) { + for (let node of nodes) { + let result = cbNode(node); + if (result) { + return result; + } + } + } + } + + // Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes + // stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, + // embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns + // a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. + export function forEachChild(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T { + if (!node) { + return; + } + // The visitXXX functions could be written as local functions that close over the cbNode and cbNodeArray + // callback parameters, but that causes a closure allocation for each invocation with noticeable effects + // on performance. + let visitNodes: (cb: (node: Node | Node[]) => T, nodes: Node[]) => T = cbNodeArray ? visitNodeArray : visitEachNode; + let cbNodes = cbNodeArray || cbNode; + switch (node.kind) { + case SyntaxKind.QualifiedName: + return visitNode(cbNode, (node).left) || + visitNode(cbNode, (node).right); + case SyntaxKind.TypeParameter: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).constraint) || + visitNode(cbNode, (node).expression); + case SyntaxKind.Parameter: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).propertyName) || + visitNode(cbNode, (node).dotDotDotToken) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNodes(cbNodes, (node).typeParameters) || + visitNodes(cbNodes, (node).parameters) || + visitNode(cbNode, (node).type); + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).asteriskToken) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNodes(cbNodes, (node).typeParameters) || + visitNodes(cbNodes, (node).parameters) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).equalsGreaterThanToken) || + visitNode(cbNode, (node).body); + case SyntaxKind.TypeReference: + return visitNode(cbNode, (node).typeName) || + visitNodes(cbNodes, (node).typeArguments); + case SyntaxKind.TypeQuery: + return visitNode(cbNode, (node).exprName); + case SyntaxKind.TypeLiteral: + return visitNodes(cbNodes, (node).members); + case SyntaxKind.ArrayType: + return visitNode(cbNode, (node).elementType); + case SyntaxKind.TupleType: + return visitNodes(cbNodes, (node).elementTypes); + case SyntaxKind.UnionType: + return visitNodes(cbNodes, (node).types); + case SyntaxKind.ParenthesizedType: + return visitNode(cbNode, (node).type); + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + return visitNodes(cbNodes, (node).elements); + case SyntaxKind.ArrayLiteralExpression: + return visitNodes(cbNodes, (node).elements); + case SyntaxKind.ObjectLiteralExpression: + return visitNodes(cbNodes, (node).properties); + case SyntaxKind.PropertyAccessExpression: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).dotToken) || + visitNode(cbNode, (node).name); + case SyntaxKind.ElementAccessExpression: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).argumentExpression); + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + return visitNode(cbNode, (node).expression) || + visitNodes(cbNodes, (node).typeArguments) || + visitNodes(cbNodes, (node).arguments); + case SyntaxKind.TaggedTemplateExpression: + return visitNode(cbNode, (node).tag) || + visitNode(cbNode, (node).template); + case SyntaxKind.TypeAssertionExpression: + return visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).expression); + case SyntaxKind.ParenthesizedExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.DeleteExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.TypeOfExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.VoidExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.PrefixUnaryExpression: + return visitNode(cbNode, (node).operand); + case SyntaxKind.YieldExpression: + return visitNode(cbNode, (node).asteriskToken) || + visitNode(cbNode, (node).expression); + case SyntaxKind.PostfixUnaryExpression: + return visitNode(cbNode, (node).operand); + case SyntaxKind.BinaryExpression: + return visitNode(cbNode, (node).left) || + visitNode(cbNode, (node).operatorToken) || + visitNode(cbNode, (node).right); + case SyntaxKind.ConditionalExpression: + return visitNode(cbNode, (node).condition) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).whenTrue) || + visitNode(cbNode, (node).colonToken) || + visitNode(cbNode, (node).whenFalse); + case SyntaxKind.SpreadElementExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.Block: + case SyntaxKind.ModuleBlock: + return visitNodes(cbNodes, (node).statements); + case SyntaxKind.SourceFile: + return visitNodes(cbNodes, (node).statements) || + visitNode(cbNode, (node).endOfFileToken); + case SyntaxKind.VariableStatement: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).declarationList); + case SyntaxKind.VariableDeclarationList: + return visitNodes(cbNodes, (node).declarations); + case SyntaxKind.ExpressionStatement: + return visitNode(cbNode, (node).expression); + case SyntaxKind.IfStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).thenStatement) || + visitNode(cbNode, (node).elseStatement); + case SyntaxKind.DoStatement: + return visitNode(cbNode, (node).statement) || + visitNode(cbNode, (node).expression); + case SyntaxKind.WhileStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ForStatement: + return visitNode(cbNode, (node).initializer) || + visitNode(cbNode, (node).condition) || + visitNode(cbNode, (node).incrementor) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ForInStatement: + return visitNode(cbNode, (node).initializer) || + visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ForOfStatement: + return visitNode(cbNode, (node).initializer) || + visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ContinueStatement: + case SyntaxKind.BreakStatement: + return visitNode(cbNode, (node).label); + case SyntaxKind.ReturnStatement: + return visitNode(cbNode, (node).expression); + case SyntaxKind.WithStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.SwitchStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).caseBlock); + case SyntaxKind.CaseBlock: + return visitNodes(cbNodes, (node).clauses); + case SyntaxKind.CaseClause: + return visitNode(cbNode, (node).expression) || + visitNodes(cbNodes, (node).statements); + case SyntaxKind.DefaultClause: + return visitNodes(cbNodes, (node).statements); + case SyntaxKind.LabeledStatement: + return visitNode(cbNode, (node).label) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ThrowStatement: + return visitNode(cbNode, (node).expression); + case SyntaxKind.TryStatement: + return visitNode(cbNode, (node).tryBlock) || + visitNode(cbNode, (node).catchClause) || + visitNode(cbNode, (node).finallyBlock); + case SyntaxKind.CatchClause: + return visitNode(cbNode, (node).variableDeclaration) || + visitNode(cbNode, (node).block); + case SyntaxKind.Decorator: + return visitNode(cbNode, (node).expression); + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNodes, (node).typeParameters) || + visitNodes(cbNodes, (node).heritageClauses) || + visitNodes(cbNodes, (node).members); + case SyntaxKind.InterfaceDeclaration: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNodes, (node).typeParameters) || + visitNodes(cbNodes, (node).heritageClauses) || + visitNodes(cbNodes, (node).members); + case SyntaxKind.TypeAliasDeclaration: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).type); + case SyntaxKind.EnumDeclaration: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNodes, (node).members); + case SyntaxKind.EnumMember: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.ModuleDeclaration: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).body); + case SyntaxKind.ImportEqualsDeclaration: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).moduleReference); + case SyntaxKind.ImportDeclaration: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).importClause) || + visitNode(cbNode, (node).moduleSpecifier); + case SyntaxKind.ImportClause: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).namedBindings); + case SyntaxKind.NamespaceImport: + return visitNode(cbNode, (node).name); + case SyntaxKind.NamedImports: + case SyntaxKind.NamedExports: + return visitNodes(cbNodes, (node).elements); + case SyntaxKind.ExportDeclaration: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).exportClause) || + visitNode(cbNode, (node).moduleSpecifier); + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ExportSpecifier: + return visitNode(cbNode, (node).propertyName) || + visitNode(cbNode, (node).name); + case SyntaxKind.ExportAssignment: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).expression); + case SyntaxKind.TemplateExpression: + return visitNode(cbNode, (node).head) || visitNodes(cbNodes, (node).templateSpans); + case SyntaxKind.TemplateSpan: + return visitNode(cbNode, (node).expression) || visitNode(cbNode, (node).literal); + case SyntaxKind.ComputedPropertyName: + return visitNode(cbNode, (node).expression); + case SyntaxKind.HeritageClause: + return visitNodes(cbNodes, (node).types); + case SyntaxKind.HeritageClauseElement: + return visitNode(cbNode, (node).expression) || + visitNodes(cbNodes, (node).typeArguments); + case SyntaxKind.ExternalModuleReference: + return visitNode(cbNode, (node).expression); + case SyntaxKind.MissingDeclaration: + return visitNodes(cbNodes, node.decorators); + } + } + + export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false): SourceFile { + let start = new Date().getTime(); + let result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes); + + parseTime += new Date().getTime() - start; + return result; + } + + // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter + // indicates what changed between the 'text' that this SourceFile has and the 'newText'. + // The SourceFile will be created with the compiler attempting to reuse as many nodes from + // this file as possible. + // + // Note: this function mutates nodes from this SourceFile. That means any existing nodes + // from this SourceFile that are being held onto may change as a result (including + // becoming detached from any SourceFile). It is recommended that this SourceFile not + // be used once 'update' is called on it. + export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile { + return IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); + } + + // Implement the parser as a singleton module. We do this for perf reasons because creating + // parser instances can actually be expensive enough to impact us on projects with many source + // files. + module Parser { + // Share a single scanner across all calls to parse a source file. This helps speed things + // up by avoiding the cost of creating/compiling scanners over and over again. + const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia:*/ true); + const disallowInAndDecoratorContext = ParserContextFlags.DisallowIn | ParserContextFlags.Decorator; + + let sourceFile: SourceFile; + let syntaxCursor: IncrementalParser.SyntaxCursor; + + let token: SyntaxKind; + let sourceText: string; + let nodeCount: number; + let identifiers: Map; + let identifierCount: number; + + let parsingContext: ParsingContext; + + // Flags that dictate what parsing context we're in. For example: + // Whether or not we are in strict parsing mode. All that changes in strict parsing mode is + // that some tokens that would be considered identifiers may be considered keywords. + // + // When adding more parser context flags, consider which is the more common case that the + // flag will be in. This should be the 'false' state for that flag. The reason for this is + // that we don't store data in our nodes unless the value is in the *non-default* state. So, + // for example, more often than code 'allows-in' (or doesn't 'disallow-in'). We opt for + // 'disallow-in' set to 'false'. Otherwise, if we had 'allowsIn' set to 'true', then almost + // all nodes would need extra state on them to store this info. + // + // Note: 'allowIn' and 'allowYield' track 1:1 with the [in] and [yield] concepts in the ES6 + // grammar specification. + // + // An important thing about these context concepts. By default they are effectively inherited + // while parsing through every grammar production. i.e. if you don't change them, then when + // you parse a sub-production, it will have the same context values as the parent production. + // This is great most of the time. After all, consider all the 'expression' grammar productions + // and how nearly all of them pass along the 'in' and 'yield' context values: + // + // EqualityExpression[In, Yield] : + // RelationalExpression[?In, ?Yield] + // EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield] + // EqualityExpression[?In, ?Yield] != RelationalExpression[?In, ?Yield] + // EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield] + // EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield] + // + // Where you have to be careful is then understanding what the points are in the grammar + // where the values are *not* passed along. For example: + // + // SingleNameBinding[Yield,GeneratorParameter] + // [+GeneratorParameter]BindingIdentifier[Yield] Initializer[In]opt + // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt + // + // Here this is saying that if the GeneratorParameter context flag is set, that we should + // explicitly set the 'yield' context flag to false before calling into the BindingIdentifier + // and we should explicitly unset the 'yield' context flag before calling into the Initializer. + // production. Conversely, if the GeneratorParameter context flag is not set, then we + // should leave the 'yield' context flag alone. + // + // Getting this all correct is tricky and requires careful reading of the grammar to + // understand when these values should be changed versus when they should be inherited. + // + // Note: it should not be necessary to save/restore these flags during speculative/lookahead + // parsing. These context flags are naturally stored and restored through normal recursive + // descent parsing and unwinding. + let contextFlags: ParserContextFlags = 0; + + // Whether or not we've had a parse error since creating the last AST node. If we have + // encountered an error, it will be stored on the next AST node we create. Parse errors + // can be broken down into three categories: + // + // 1) An error that occurred during scanning. For example, an unterminated literal, or a + // character that was completely not understood. + // + // 2) A token was expected, but was not present. This type of error is commonly produced + // by the 'parseExpected' function. + // + // 3) A token was present that no parsing function was able to consume. This type of error + // only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser + // decides to skip the token. + // + // In all of these cases, we want to mark the next node as having had an error before it. + // With this mark, we can know in incremental settings if this node can be reused, or if + // we have to reparse it. If we don't keep this information around, we may just reuse the + // node. in that event we would then not produce the same errors as we did before, causing + // significant confusion problems. + // + // Note: it is necessary that this value be saved/restored during speculative/lookahead + // parsing. During lookahead parsing, we will often create a node. That node will have + // this value attached, and then this value will be set back to 'false'. If we decide to + // rewind, we must get back to the same value we had prior to the lookahead. + // + // Note: any errors at the end of the file that do not precede a regular node, should get + // attached to the EOF token. + let parseErrorBeforeNextFinishedNode: boolean = false; + + export function parseSourceFile(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, setParentNodes?: boolean): SourceFile { + sourceText = _sourceText; + syntaxCursor = _syntaxCursor; + + parsingContext = 0; + identifiers = {}; + identifierCount = 0; + nodeCount = 0; + + contextFlags = 0; + parseErrorBeforeNextFinishedNode = false; + + createSourceFile(fileName, languageVersion); + + // Initialize and prime the scanner before parsing the source elements. + scanner.setText(sourceText); + scanner.setOnError(scanError); + scanner.setScriptTarget(languageVersion); + token = nextToken(); + + processReferenceComments(sourceFile); + + sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement); + Debug.assert(token === SyntaxKind.EndOfFileToken); + sourceFile.endOfFileToken = parseTokenNode(); + + setExternalModuleIndicator(sourceFile); + + sourceFile.nodeCount = nodeCount; + sourceFile.identifierCount = identifierCount; + sourceFile.identifiers = identifiers; + + if (setParentNodes) { + fixupParentReferences(sourceFile); + } + + syntaxCursor = undefined; + + // Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily. + scanner.setText(""); + scanner.setOnError(undefined); + + let result = sourceFile; + + // Clear any data. We don't want to accidently hold onto it for too long. + sourceFile = undefined; + identifiers = undefined; + syntaxCursor = undefined; + sourceText = undefined; + + return result; + } + + function fixupParentReferences(sourceFile: SourceFile) { + // normally parent references are set during binding. However, for clients that only need + // a syntax tree, and no semantic features, then the binding process is an unnecessary + // overhead. This functions allows us to set all the parents, without all the expense of + // binding. + + let parent: Node = sourceFile; + forEachChild(sourceFile, visitNode); + return; + + function visitNode(n: Node): void { + // walk down setting parents that differ from the parent we think it should be. This + // allows us to quickly bail out of setting parents for subtrees during incremental + // parsing + if (n.parent !== parent) { + n.parent = parent; + + let saveParent = parent; + parent = n; + forEachChild(n, visitNode); + parent = saveParent; + } + } + } + + function createSourceFile(fileName: string, languageVersion: ScriptTarget) { + sourceFile = createNode(SyntaxKind.SourceFile, /*pos*/ 0); + + sourceFile.pos = 0; + sourceFile.end = sourceText.length; + sourceFile.text = sourceText; + + sourceFile.parseDiagnostics = []; + sourceFile.bindDiagnostics = []; + sourceFile.languageVersion = languageVersion; + sourceFile.fileName = normalizePath(fileName); + sourceFile.flags = fileExtensionIs(sourceFile.fileName, ".d.ts") ? NodeFlags.DeclarationFile : 0; + } + + function setContextFlag(val: Boolean, flag: ParserContextFlags) { + if (val) { + contextFlags |= flag; + } + else { + contextFlags &= ~flag; + } + } + + function setStrictModeContext(val: boolean) { + setContextFlag(val, ParserContextFlags.StrictMode); + } + + function setDisallowInContext(val: boolean) { + setContextFlag(val, ParserContextFlags.DisallowIn); + } + + function setYieldContext(val: boolean) { + setContextFlag(val, ParserContextFlags.Yield); + } + + function setGeneratorParameterContext(val: boolean) { + setContextFlag(val, ParserContextFlags.GeneratorParameter); + } + + function setDecoratorContext(val: boolean) { + setContextFlag(val, ParserContextFlags.Decorator); + } + + function doOutsideOfContext(flags: ParserContextFlags, func: () => T): T { + let currentContextFlags = contextFlags & flags; + if (currentContextFlags) { + setContextFlag(false, currentContextFlags); + let result = func(); + setContextFlag(true, currentContextFlags); + return result; + } + + // no need to do anything special as we are not in any of the requested contexts + return func(); + } + + function allowInAnd(func: () => T): T { + if (contextFlags & ParserContextFlags.DisallowIn) { + setDisallowInContext(false); + let result = func(); + setDisallowInContext(true); + return result; + } + + // no need to do anything special if 'in' is already allowed. + return func(); + } + + function disallowInAnd(func: () => T): T { + if (contextFlags & ParserContextFlags.DisallowIn) { + // no need to do anything special if 'in' is already disallowed. + return func(); + } + + setDisallowInContext(true); + let result = func(); + setDisallowInContext(false); + return result; + } + + function doInYieldContext(func: () => T): T { + if (contextFlags & ParserContextFlags.Yield) { + // no need to do anything special if we're already in the [Yield] context. + return func(); + } + + setYieldContext(true); + let result = func(); + setYieldContext(false); + return result; + } + + function doOutsideOfYieldContext(func: () => T): T { + if (contextFlags & ParserContextFlags.Yield) { + setYieldContext(false); + let result = func(); + setYieldContext(true); + return result; + } + + // no need to do anything special if we're not in the [Yield] context. + return func(); + } + + function doInDecoratorContext(func: () => T): T { + if (contextFlags & ParserContextFlags.Decorator) { + // no need to do anything special if we're already in the [Decorator] context. + return func(); + } + + setDecoratorContext(true); + let result = func(); + setDecoratorContext(false); + return result; + } + + function inYieldContext() { + return (contextFlags & ParserContextFlags.Yield) !== 0; + } + + function inStrictModeContext() { + return (contextFlags & ParserContextFlags.StrictMode) !== 0; + } + + function inGeneratorParameterContext() { + return (contextFlags & ParserContextFlags.GeneratorParameter) !== 0; + } + + function inDisallowInContext() { + return (contextFlags & ParserContextFlags.DisallowIn) !== 0; + } + + function inDecoratorContext() { + return (contextFlags & ParserContextFlags.Decorator) !== 0; + } + + function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): void { + let start = scanner.getTokenPos(); + let length = scanner.getTextPos() - start; + + parseErrorAtPosition(start, length, message, arg0); + } + + function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): void { + // Don't report another error if it would just be at the same position as the last error. + let lastError = lastOrUndefined(sourceFile.parseDiagnostics); + if (!lastError || start !== lastError.start) { + sourceFile.parseDiagnostics.push(createFileDiagnostic(sourceFile, start, length, message, arg0)); + } + + // Mark that we've encountered an error. We'll set an appropriate bit on the next + // node we finish so that it can't be reused incrementally. + parseErrorBeforeNextFinishedNode = true; + } + + function scanError(message: DiagnosticMessage, length?: number) { + let pos = scanner.getTextPos(); + parseErrorAtPosition(pos, length || 0, message); + } + + function getNodePos(): number { + return scanner.getStartPos(); + } + + function getNodeEnd(): number { + return scanner.getStartPos(); + } + + function nextToken(): SyntaxKind { + return token = scanner.scan(); + } + + function getTokenPos(pos: number): number { + return skipTrivia(sourceText, pos); + } + + function reScanGreaterToken(): SyntaxKind { + return token = scanner.reScanGreaterToken(); + } + + function reScanSlashToken(): SyntaxKind { + return token = scanner.reScanSlashToken(); + } + + function reScanTemplateToken(): SyntaxKind { + return token = scanner.reScanTemplateToken(); + } + + function speculationHelper(callback: () => T, isLookAhead: boolean): T { + // Keep track of the state we'll need to rollback to if lookahead fails (or if the + // caller asked us to always reset our state). + let saveToken = token; + let saveParseDiagnosticsLength = sourceFile.parseDiagnostics.length; + let saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; + + // Note: it is not actually necessary to save/restore the context flags here. That's + // because the saving/restorating of these flags happens naturally through the recursive + // descent nature of our parser. However, we still store this here just so we can + // assert that that invariant holds. + let saveContextFlags = contextFlags; + + // If we're only looking ahead, then tell the scanner to only lookahead as well. + // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the + // same. + let result = isLookAhead + ? scanner.lookAhead(callback) + : scanner.tryScan(callback); + + Debug.assert(saveContextFlags === contextFlags); + + // If our callback returned something 'falsy' or we're just looking ahead, + // then unconditionally restore us to where we were. + if (!result || isLookAhead) { + token = saveToken; + sourceFile.parseDiagnostics.length = saveParseDiagnosticsLength; + parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; + } + + return result; + } + + // Invokes the provided callback then unconditionally restores the parser to the state it + // was in immediately prior to invoking the callback. The result of invoking the callback + // is returned from this function. + function lookAhead(callback: () => T): T { + return speculationHelper(callback, /*isLookAhead:*/ true); + } + + // Invokes the provided callback. If the callback returns something falsy, then it restores + // the parser to the state it was in immediately prior to invoking the callback. If the + // callback returns something truthy, then the parser state is not rolled back. The result + // of invoking the callback is returned from this function. + function tryParse(callback: () => T): T { + return speculationHelper(callback, /*isLookAhead:*/ false); + } + + // Ignore strict mode flag because we will report an error in type checker instead. + function isIdentifier(): boolean { + if (token === SyntaxKind.Identifier) { + return true; + } + + // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is + // considered a keyword and is not an identifier. + if (token === SyntaxKind.YieldKeyword && inYieldContext()) { + return false; + } + + return token > SyntaxKind.LastReservedWord; + } + + function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage): boolean { + if (token === kind) { + nextToken(); + return true; + } + + // Report specific message if provided with one. Otherwise, report generic fallback message. + if (diagnosticMessage) { + parseErrorAtCurrentToken(diagnosticMessage); + } + else { + parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind)); + } + return false; + } + + function parseOptional(t: SyntaxKind): boolean { + if (token === t) { + nextToken(); + return true; + } + return false; + } + + function parseOptionalToken(t: SyntaxKind): Node { + if (token === t) { + return parseTokenNode(); + } + return undefined; + } + + function parseExpectedToken(t: SyntaxKind, reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): Node { + return parseOptionalToken(t) || + createMissingNode(t, reportAtCurrentPosition, diagnosticMessage, arg0); + } + + function parseTokenNode(): T { + let node = createNode(token); + nextToken(); + return finishNode(node); + } + + function canParseSemicolon() { + // If there's a real semicolon, then we can always parse it out. + if (token === SyntaxKind.SemicolonToken) { + return true; + } + + // We can parse out an optional semicolon in ASI cases in the following cases. + return token === SyntaxKind.CloseBraceToken || token === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak(); + } + + function parseSemicolon(): boolean { + if (canParseSemicolon()) { + if (token === SyntaxKind.SemicolonToken) { + // consume the semicolon if it was explicitly provided. + nextToken(); + } + + return true; + } + else { + return parseExpected(SyntaxKind.SemicolonToken); + } + } + + function createNode(kind: SyntaxKind, pos?: number): Node { + nodeCount++; + let node = new (nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind)))(); + if (!(pos >= 0)) { + pos = scanner.getStartPos(); + } + + node.pos = pos; + node.end = pos; + return node; + } + + function finishNode(node: T): T { + node.end = scanner.getStartPos(); + + if (contextFlags) { + node.parserContextFlags = contextFlags; + } + + // Keep track on the node if we encountered an error while parsing it. If we did, then + // we cannot reuse the node incrementally. Once we've marked this node, clear out the + // flag so that we don't mark any subsequent nodes. + if (parseErrorBeforeNextFinishedNode) { + parseErrorBeforeNextFinishedNode = false; + node.parserContextFlags |= ParserContextFlags.ThisNodeHasError; + } + + return node; + } + + function createMissingNode(kind: SyntaxKind, reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): Node { + if (reportAtCurrentPosition) { + parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0); + } + else { + parseErrorAtCurrentToken(diagnosticMessage, arg0); + } + + let result = createNode(kind, scanner.getStartPos()); + (result).text = ""; + return finishNode(result); + } + + function internIdentifier(text: string): string { + text = escapeIdentifier(text); + return hasProperty(identifiers, text) ? identifiers[text] : (identifiers[text] = text); + } + + // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues + // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for + // each identifier in order to reduce memory consumption. + function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage): Identifier { + identifierCount++; + if (isIdentifier) { + let node = createNode(SyntaxKind.Identifier); + + // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker + if (token !== SyntaxKind.Identifier) { + node.originalKeywordKind = token; + } + node.text = internIdentifier(scanner.getTokenValue()); + nextToken(); + return finishNode(node); + } + + return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition:*/ false, diagnosticMessage || Diagnostics.Identifier_expected); + } + + function parseIdentifier(diagnosticMessage?: DiagnosticMessage): Identifier { + return createIdentifier(isIdentifier(), diagnosticMessage); + } + + function parseIdentifierName(): Identifier { + return createIdentifier(isIdentifierOrKeyword()); + } + + function isLiteralPropertyName(): boolean { + return isIdentifierOrKeyword() || + token === SyntaxKind.StringLiteral || + token === SyntaxKind.NumericLiteral; + } + + function parsePropertyName(): DeclarationName { + if (token === SyntaxKind.StringLiteral || token === SyntaxKind.NumericLiteral) { + return parseLiteralNode(/*internName:*/ true); + } + if (token === SyntaxKind.OpenBracketToken) { + return parseComputedPropertyName(); + } + return parseIdentifierName(); + } + + function parseComputedPropertyName(): ComputedPropertyName { + // PropertyName[Yield,GeneratorParameter] : + // LiteralPropertyName + // [+GeneratorParameter] ComputedPropertyName + // [~GeneratorParameter] ComputedPropertyName[?Yield] + // + // ComputedPropertyName[Yield] : + // [ AssignmentExpression[In, ?Yield] ] + // + let node = createNode(SyntaxKind.ComputedPropertyName); + parseExpected(SyntaxKind.OpenBracketToken); + + // We parse any expression (including a comma expression). But the grammar + // says that only an assignment expression is allowed, so the grammar checker + // will error if it sees a comma expression. + let yieldContext = inYieldContext(); + if (inGeneratorParameterContext()) { + setYieldContext(false); + } + + node.expression = allowInAnd(parseExpression); + if (inGeneratorParameterContext()) { + setYieldContext(yieldContext); + } + + parseExpected(SyntaxKind.CloseBracketToken); + return finishNode(node); + } + + function parseContextualModifier(t: SyntaxKind): boolean { + return token === t && tryParse(nextTokenCanFollowModifier); + } + + function nextTokenCanFollowModifier() { + nextToken(); + return canFollowModifier(); + } + + function parseAnyContextualModifier(): boolean { + return isModifier(token) && tryParse(nextTokenCanFollowContextualModifier); + } + + function nextTokenCanFollowContextualModifier() { + if (token === SyntaxKind.ConstKeyword) { + // 'const' is only a modifier if followed by 'enum'. + return nextToken() === SyntaxKind.EnumKeyword; + } + if (token === SyntaxKind.ExportKeyword) { + nextToken(); + if (token === SyntaxKind.DefaultKeyword) { + return lookAhead(nextTokenIsClassOrFunction); + } + return token !== SyntaxKind.AsteriskToken && token !== SyntaxKind.OpenBraceToken && canFollowModifier(); + } + if (token === SyntaxKind.DefaultKeyword) { + return nextTokenIsClassOrFunction(); + } + nextToken(); + return canFollowModifier(); + } + + function canFollowModifier(): boolean { + return token === SyntaxKind.OpenBracketToken + || token === SyntaxKind.OpenBraceToken + || token === SyntaxKind.AsteriskToken + || isLiteralPropertyName(); + } + + function nextTokenIsClassOrFunction(): boolean { + nextToken(); + return token === SyntaxKind.ClassKeyword || token === SyntaxKind.FunctionKeyword; + } + + // True if positioned at the start of a list element + function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean { + let node = currentNode(parsingContext); + if (node) { + return true; + } + + switch (parsingContext) { + case ParsingContext.SourceElements: + case ParsingContext.ModuleElements: + return isSourceElement(inErrorRecovery); + case ParsingContext.BlockStatements: + case ParsingContext.SwitchClauseStatements: + return isStartOfStatement(inErrorRecovery); + case ParsingContext.SwitchClauses: + return token === SyntaxKind.CaseKeyword || token === SyntaxKind.DefaultKeyword; + case ParsingContext.TypeMembers: + return isStartOfTypeMember(); + case ParsingContext.ClassMembers: + // We allow semicolons as class elements (as specified by ES6) as long as we're + // not in error recovery. If we're in error recovery, we don't want an errant + // semicolon to be treated as a class member (since they're almost always used + // for statements. + return lookAhead(isClassMemberStart) || (token === SyntaxKind.SemicolonToken && !inErrorRecovery); + case ParsingContext.EnumMembers: + // Include open bracket computed properties. This technically also lets in indexers, + // which would be a candidate for improved error reporting. + return token === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); + case ParsingContext.ObjectLiteralMembers: + return token === SyntaxKind.OpenBracketToken || token === SyntaxKind.AsteriskToken || isLiteralPropertyName(); + case ParsingContext.ObjectBindingElements: + return isLiteralPropertyName(); + case ParsingContext.HeritageClauseElement: + // If we see { } then only consume it as an expression if it is followed by , or { + // That way we won't consume the body of a class in its heritage clause. + if (token === SyntaxKind.OpenBraceToken) { + return lookAhead(isValidHeritageClauseObjectLiteral); + } + + if (!inErrorRecovery) { + return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword(); + } + else { + // If we're in error recovery we tighten up what we're willing to match. + // That way we don't treat something like "this" as a valid heritage clause + // element during recovery. + return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword(); + } + case ParsingContext.VariableDeclarations: + return isIdentifierOrPattern(); + case ParsingContext.ArrayBindingElements: + return token === SyntaxKind.CommaToken || token === SyntaxKind.DotDotDotToken || isIdentifierOrPattern(); + case ParsingContext.TypeParameters: + return isIdentifier(); + case ParsingContext.ArgumentExpressions: + case ParsingContext.ArrayLiteralMembers: + return token === SyntaxKind.CommaToken || token === SyntaxKind.DotDotDotToken || isStartOfExpression(); + case ParsingContext.Parameters: + return isStartOfParameter(); + case ParsingContext.TypeArguments: + case ParsingContext.TupleElementTypes: + return token === SyntaxKind.CommaToken || isStartOfType(); + case ParsingContext.HeritageClauses: + return isHeritageClause(); + case ParsingContext.ImportOrExportSpecifiers: + return isIdentifierOrKeyword(); + } + + Debug.fail("Non-exhaustive case in 'isListElement'."); + } + + function isValidHeritageClauseObjectLiteral() { + Debug.assert(token === SyntaxKind.OpenBraceToken); + if (nextToken() === SyntaxKind.CloseBraceToken) { + // if we see "extends {}" then only treat the {} as what we're extending (and not + // the class body) if we have: + // + // extends {} { + // extends {}, + // extends {} extends + // extends {} implements + + let next = nextToken(); + return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword; + } + + return true; + } + + function nextTokenIsIdentifier() { + nextToken(); + return isIdentifier(); + } + + function isHeritageClauseExtendsOrImplementsKeyword(): boolean { + if (token === SyntaxKind.ImplementsKeyword || + token === SyntaxKind.ExtendsKeyword) { + + return lookAhead(nextTokenIsStartOfExpression); + } + + return false; + } + + function nextTokenIsStartOfExpression() { + nextToken(); + return isStartOfExpression(); + } + + // True if positioned at a list terminator + function isListTerminator(kind: ParsingContext): boolean { + if (token === SyntaxKind.EndOfFileToken) { + // Being at the end of the file ends all lists. + return true; + } + + switch (kind) { + case ParsingContext.ModuleElements: + case ParsingContext.BlockStatements: + case ParsingContext.SwitchClauses: + case ParsingContext.TypeMembers: + case ParsingContext.ClassMembers: + case ParsingContext.EnumMembers: + case ParsingContext.ObjectLiteralMembers: + case ParsingContext.ObjectBindingElements: + case ParsingContext.ImportOrExportSpecifiers: + return token === SyntaxKind.CloseBraceToken; + case ParsingContext.SwitchClauseStatements: + return token === SyntaxKind.CloseBraceToken || token === SyntaxKind.CaseKeyword || token === SyntaxKind.DefaultKeyword; + case ParsingContext.HeritageClauseElement: + return token === SyntaxKind.OpenBraceToken || token === SyntaxKind.ExtendsKeyword || token === SyntaxKind.ImplementsKeyword; + case ParsingContext.VariableDeclarations: + return isVariableDeclaratorListTerminator(); + case ParsingContext.TypeParameters: + // Tokens other than '>' are here for better error recovery + return token === SyntaxKind.GreaterThanToken || token === SyntaxKind.OpenParenToken || token === SyntaxKind.OpenBraceToken || token === SyntaxKind.ExtendsKeyword || token === SyntaxKind.ImplementsKeyword; + case ParsingContext.ArgumentExpressions: + // Tokens other than ')' are here for better error recovery + return token === SyntaxKind.CloseParenToken || token === SyntaxKind.SemicolonToken; + case ParsingContext.ArrayLiteralMembers: + case ParsingContext.TupleElementTypes: + case ParsingContext.ArrayBindingElements: + return token === SyntaxKind.CloseBracketToken; + case ParsingContext.Parameters: + // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery + return token === SyntaxKind.CloseParenToken || token === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/; + case ParsingContext.TypeArguments: + // Tokens other than '>' are here for better error recovery + return token === SyntaxKind.GreaterThanToken || token === SyntaxKind.OpenParenToken; + case ParsingContext.HeritageClauses: + return token === SyntaxKind.OpenBraceToken || token === SyntaxKind.CloseBraceToken; + } + } + + function isVariableDeclaratorListTerminator(): boolean { + // If we can consume a semicolon (either explicitly, or with ASI), then consider us done + // with parsing the list of variable declarators. + if (canParseSemicolon()) { + return true; + } + + // in the case where we're parsing the variable declarator of a 'for-in' statement, we + // are done if we see an 'in' keyword in front of us. Same with for-of + if (isInOrOfKeyword(token)) { + return true; + } + + // ERROR RECOVERY TWEAK: + // For better error recovery, if we see an '=>' then we just stop immediately. We've got an + // arrow function here and it's going to be very unlikely that we'll resynchronize and get + // another variable declaration. + if (token === SyntaxKind.EqualsGreaterThanToken) { + return true; + } + + // Keep trying to parse out variable declarators. + return false; + } + + // True if positioned at element or terminator of the current list or any enclosing list + function isInSomeParsingContext(): boolean { + for (let kind = 0; kind < ParsingContext.Count; kind++) { + if (parsingContext & (1 << kind)) { + if (isListElement(kind, /* inErrorRecovery */ true) || isListTerminator(kind)) { + return true; + } + } + } + + return false; + } + + // Parses a list of elements + function parseList(kind: ParsingContext, checkForStrictMode: boolean, parseElement: () => T): NodeArray { + let saveParsingContext = parsingContext; + parsingContext |= 1 << kind; + let result = >[]; + result.pos = getNodePos(); + let savedStrictModeContext = inStrictModeContext(); + + while (!isListTerminator(kind)) { + if (isListElement(kind, /* inErrorRecovery */ false)) { + let element = parseListElement(kind, parseElement); + result.push(element); + + // test elements only if we are not already in strict mode + if (checkForStrictMode && !inStrictModeContext()) { + if (isPrologueDirective(element)) { + if (isUseStrictPrologueDirective(sourceFile, element)) { + setStrictModeContext(true); + checkForStrictMode = false; + } + } + else { + checkForStrictMode = false; + } + } + + continue; + } + + if (abortParsingListOrMoveToNextToken(kind)) { + break; + } + } + + setStrictModeContext(savedStrictModeContext); + result.end = getNodeEnd(); + parsingContext = saveParsingContext; + return result; + } + + /// Should be called only on prologue directives (isPrologueDirective(node) should be true) + function isUseStrictPrologueDirective(sourceFile: SourceFile, node: Node): boolean { + Debug.assert(isPrologueDirective(node)); + let nodeText = getSourceTextOfNodeFromSourceFile(sourceFile, (node).expression); + + // Note: the node text must be exactly "use strict" or 'use strict'. It is not ok for the + // string to contain unicode escapes (as per ES5). + return nodeText === '"use strict"' || nodeText === "'use strict'"; + } + + function parseListElement(parsingContext: ParsingContext, parseElement: () => T): T { + let node = currentNode(parsingContext); + if (node) { + return consumeNode(node); + } + + return parseElement(); + } + + function currentNode(parsingContext: ParsingContext): Node { + // If there is an outstanding parse error that we've encountered, but not attached to + // some node, then we cannot get a node from the old source tree. This is because we + // want to mark the next node we encounter as being unusable. + // + // Note: This may be too conservative. Perhaps we could reuse the node and set the bit + // on it (or its leftmost child) as having the error. For now though, being conservative + // is nice and likely won't ever affect perf. + if (parseErrorBeforeNextFinishedNode) { + return undefined; + } + + if (!syntaxCursor) { + // if we don't have a cursor, we could never return a node from the old tree. + return undefined; + } + + let node = syntaxCursor.currentNode(scanner.getStartPos()); + + // Can't reuse a missing node. + if (nodeIsMissing(node)) { + return undefined; + } + + // Can't reuse a node that intersected the change range. + if (node.intersectsChange) { + return undefined; + } + + // Can't reuse a node that contains a parse error. This is necessary so that we + // produce the same set of errors again. + if (containsParseError(node)) { + return undefined; + } + + // We can only reuse a node if it was parsed under the same strict mode that we're + // currently in. i.e. if we originally parsed a node in non-strict mode, but then + // the user added 'using strict' at the top of the file, then we can't use that node + // again as the presense of strict mode may cause us to parse the tokens in the file + // differetly. + // + // Note: we *can* reuse tokens when the strict mode changes. That's because tokens + // are unaffected by strict mode. It's just the parser will decide what to do with it + // differently depending on what mode it is in. + // + // This also applies to all our other context flags as well. + let nodeContextFlags = node.parserContextFlags & ParserContextFlags.ParserGeneratedFlags; + if (nodeContextFlags !== contextFlags) { + return undefined; + } + + // Ok, we have a node that looks like it could be reused. Now verify that it is valid + // in the currest list parsing context that we're currently at. + if (!canReuseNode(node, parsingContext)) { + return undefined; + } + + return node; + } + + function consumeNode(node: Node) { + // Move the scanner so it is after the node we just consumed. + scanner.setTextPos(node.end); + nextToken(); + return node; + } + + function canReuseNode(node: Node, parsingContext: ParsingContext): boolean { + switch (parsingContext) { + case ParsingContext.ModuleElements: + return isReusableModuleElement(node); + + case ParsingContext.ClassMembers: + return isReusableClassMember(node); + + case ParsingContext.SwitchClauses: + return isReusableSwitchClause(node); + + case ParsingContext.BlockStatements: + case ParsingContext.SwitchClauseStatements: + return isReusableStatement(node); + + case ParsingContext.EnumMembers: + return isReusableEnumMember(node); + + case ParsingContext.TypeMembers: + return isReusableTypeMember(node); + + case ParsingContext.VariableDeclarations: + return isReusableVariableDeclaration(node); + + case ParsingContext.Parameters: + return isReusableParameter(node); + + // Any other lists we do not care about reusing nodes in. But feel free to add if + // you can do so safely. Danger areas involve nodes that may involve speculative + // parsing. If speculative parsing is involved with the node, then the range the + // parser reached while looking ahead might be in the edited range (see the example + // in canReuseVariableDeclaratorNode for a good case of this). + case ParsingContext.HeritageClauses: + // This would probably be safe to reuse. There is no speculative parsing with + // heritage clauses. + + case ParsingContext.TypeParameters: + // This would probably be safe to reuse. There is no speculative parsing with + // type parameters. Note that that's because type *parameters* only occur in + // unambiguous *type* contexts. While type *arguments* occur in very ambiguous + // *expression* contexts. + + case ParsingContext.TupleElementTypes: + // This would probably be safe to reuse. There is no speculative parsing with + // tuple types. + + // Technically, type argument list types are probably safe to reuse. While + // speculative parsing is involved with them (since type argument lists are only + // produced from speculative parsing a < as a type argument list), we only have + // the types because speculative parsing succeeded. Thus, the lookahead never + // went past the end of the list and rewound. + case ParsingContext.TypeArguments: + + // Note: these are almost certainly not safe to ever reuse. Expressions commonly + // need a large amount of lookahead, and we should not reuse them as they may + // have actually intersected the edit. + case ParsingContext.ArgumentExpressions: + + // This is not safe to reuse for the same reason as the 'AssignmentExpression' + // cases. i.e. a property assignment may end with an expression, and thus might + // have lookahead far beyond it's old node. + case ParsingContext.ObjectLiteralMembers: + + // This is probably not safe to reuse. There can be speculative parsing with + // type names in a heritage clause. There can be generic names in the type + // name list, and there can be left hand side expressions (which can have type + // arguments.) + case ParsingContext.HeritageClauseElement: + } + + return false; + } + + function isReusableModuleElement(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ExportDeclaration: + case SyntaxKind.ExportAssignment: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + return true; + } + + return isReusableStatement(node); + } + + return false; + } + + function isReusableClassMember(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.Constructor: + case SyntaxKind.IndexSignature: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.SemicolonClassElement: + return true; + } + } + + return false; + } + + function isReusableSwitchClause(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + return true; + } + } + + return false; + } + + function isReusableStatement(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.VariableStatement: + case SyntaxKind.Block: + case SyntaxKind.IfStatement: + case SyntaxKind.ExpressionStatement: + case SyntaxKind.ThrowStatement: + case SyntaxKind.ReturnStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.BreakStatement: + case SyntaxKind.ContinueStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.EmptyStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.LabeledStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.DebuggerStatement: + return true; + } + } + + return false; + } + + function isReusableEnumMember(node: Node) { + return node.kind === SyntaxKind.EnumMember; + } + + function isReusableTypeMember(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.ConstructSignature: + case SyntaxKind.MethodSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.PropertySignature: + case SyntaxKind.CallSignature: + return true; + } + } + + return false; + } + + function isReusableVariableDeclaration(node: Node) { + if (node.kind !== SyntaxKind.VariableDeclaration) { + return false; + } + + // Very subtle incremental parsing bug. Consider the following code: + // + // let v = new List < A, B + // + // This is actually legal code. It's a list of variable declarators "v = new List() + // + // then we have a problem. "v = new Listnode; + return variableDeclarator.initializer === undefined; + } + + function isReusableParameter(node: Node) { + if (node.kind !== SyntaxKind.Parameter) { + return false; + } + + // See the comment in isReusableVariableDeclaration for why we do this. + let parameter = node; + return parameter.initializer === undefined; + } + + // Returns true if we should abort parsing. + function abortParsingListOrMoveToNextToken(kind: ParsingContext) { + parseErrorAtCurrentToken(parsingContextErrors(kind)); + if (isInSomeParsingContext()) { + return true; + } + + nextToken(); + return false; + } + + function parsingContextErrors(context: ParsingContext): DiagnosticMessage { + switch (context) { + case ParsingContext.SourceElements: return Diagnostics.Declaration_or_statement_expected; + case ParsingContext.ModuleElements: return Diagnostics.Declaration_or_statement_expected; + case ParsingContext.BlockStatements: return Diagnostics.Statement_expected; + case ParsingContext.SwitchClauses: return Diagnostics.case_or_default_expected; + case ParsingContext.SwitchClauseStatements: return Diagnostics.Statement_expected; + case ParsingContext.TypeMembers: return Diagnostics.Property_or_signature_expected; + case ParsingContext.ClassMembers: return Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected; + case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected; + case ParsingContext.HeritageClauseElement: return Diagnostics.Expression_expected; + case ParsingContext.VariableDeclarations: return Diagnostics.Variable_declaration_expected; + case ParsingContext.ObjectBindingElements: return Diagnostics.Property_destructuring_pattern_expected; + case ParsingContext.ArrayBindingElements: return Diagnostics.Array_element_destructuring_pattern_expected; + case ParsingContext.ArgumentExpressions: return Diagnostics.Argument_expression_expected; + case ParsingContext.ObjectLiteralMembers: return Diagnostics.Property_assignment_expected; + case ParsingContext.ArrayLiteralMembers: return Diagnostics.Expression_or_comma_expected; + case ParsingContext.Parameters: return Diagnostics.Parameter_declaration_expected; + case ParsingContext.TypeParameters: return Diagnostics.Type_parameter_declaration_expected; + case ParsingContext.TypeArguments: return Diagnostics.Type_argument_expected; + case ParsingContext.TupleElementTypes: return Diagnostics.Type_expected; + case ParsingContext.HeritageClauses: return Diagnostics.Unexpected_token_expected; + case ParsingContext.ImportOrExportSpecifiers: return Diagnostics.Identifier_expected; + } + }; + + // Parses a comma-delimited list of elements + function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimeter?: boolean): NodeArray { + let saveParsingContext = parsingContext; + parsingContext |= 1 << kind; + let result = >[]; + result.pos = getNodePos(); + + let commaStart = -1; // Meaning the previous token was not a comma + while (true) { + if (isListElement(kind, /* inErrorRecovery */ false)) { + result.push(parseListElement(kind, parseElement)); + commaStart = scanner.getTokenPos(); + if (parseOptional(SyntaxKind.CommaToken)) { + continue; + } + + commaStart = -1; // Back to the state where the last token was not a comma + if (isListTerminator(kind)) { + break; + } + + // We didn't get a comma, and the list wasn't terminated, explicitly parse + // out a comma so we give a good error message. + parseExpected(SyntaxKind.CommaToken); + + // If the token was a semicolon, and the caller allows that, then skip it and + // continue. This ensures we get back on track and don't result in tons of + // parse errors. For example, this can happen when people do things like use + // a semicolon to delimit object literal members. Note: we'll have already + // reported an error when we called parseExpected above. + if (considerSemicolonAsDelimeter && token === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) { + nextToken(); + } + continue; + } + + if (isListTerminator(kind)) { + break; + } + + if (abortParsingListOrMoveToNextToken(kind)) { + break; + } + } + + // Recording the trailing comma is deliberately done after the previous + // loop, and not just if we see a list terminator. This is because the list + // may have ended incorrectly, but it is still important to know if there + // was a trailing comma. + // Check if the last token was a comma. + if (commaStart >= 0) { + // Always preserve a trailing comma by marking it on the NodeArray + result.hasTrailingComma = true; + } + + result.end = getNodeEnd(); + parsingContext = saveParsingContext; + return result; + } + + function createMissingList(): NodeArray { + let pos = getNodePos(); + let result = >[]; + result.pos = pos; + result.end = pos; + return result; + } + + function parseBracketedList(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray { + if (parseExpected(open)) { + let result = parseDelimitedList(kind, parseElement); + parseExpected(close); + return result; + } + + return createMissingList(); + } + + // The allowReservedWords parameter controls whether reserved words are permitted after the first dot + function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName { + let entity: EntityName = parseIdentifier(diagnosticMessage); + while (parseOptional(SyntaxKind.DotToken)) { + let node = createNode(SyntaxKind.QualifiedName, entity.pos); + node.left = entity; + node.right = parseRightSideOfDot(allowReservedWords); + entity = finishNode(node); + } + return entity; + } + + function parseRightSideOfDot(allowIdentifierNames: boolean): Identifier { + // Technically a keyword is valid here as all keywords are identifier names. + // However, often we'll encounter this in error situations when the keyword + // is actually starting another valid construct. + // + // So, we check for the following specific case: + // + // name. + // keyword identifierNameOrKeyword + // + // Note: the newlines are important here. For example, if that above code + // were rewritten into: + // + // name.keyword + // identifierNameOrKeyword + // + // Then we would consider it valid. That's because ASI would take effect and + // the code would be implicitly: "name.keyword; identifierNameOrKeyword". + // In the first case though, ASI will not take effect because there is not a + // line terminator after the keyword. + if (scanner.hasPrecedingLineBreak() && scanner.isReservedWord()) { + let matchesPattern = lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); + + if (matchesPattern) { + // Report that we need an identifier. However, report it right after the dot, + // and not on the next token. This is because the next token might actually + // be an identifier and the error woudl be quite confusing. + return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentToken:*/ true, Diagnostics.Identifier_expected); + } + } + + return allowIdentifierNames ? parseIdentifierName() : parseIdentifier(); + } + + function parseTemplateExpression(): TemplateExpression { + let template = createNode(SyntaxKind.TemplateExpression); + + template.head = parseLiteralNode(); + Debug.assert(template.head.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); + + let templateSpans = >[]; + templateSpans.pos = getNodePos(); + + do { + templateSpans.push(parseTemplateSpan()); + } + while (templateSpans[templateSpans.length - 1].literal.kind === SyntaxKind.TemplateMiddle) + + templateSpans.end = getNodeEnd(); + template.templateSpans = templateSpans; + + return finishNode(template); + } + + function parseTemplateSpan(): TemplateSpan { + let span = createNode(SyntaxKind.TemplateSpan); + span.expression = allowInAnd(parseExpression); + + let literal: LiteralExpression; + + if (token === SyntaxKind.CloseBraceToken) { + reScanTemplateToken() + literal = parseLiteralNode(); + } + else { + literal = parseExpectedToken(SyntaxKind.TemplateTail, /*reportAtCurrentPosition:*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)); + } + + span.literal = literal; + return finishNode(span); + } + + function parseLiteralNode(internName?: boolean): LiteralExpression { + let node = createNode(token); + let text = scanner.getTokenValue(); + node.text = internName ? internIdentifier(text) : text; + + if (scanner.hasExtendedUnicodeEscape()) { + node.hasExtendedUnicodeEscape = true; + } + + if (scanner.isUnterminated()) { + node.isUnterminated = true; + } + + let tokenPos = scanner.getTokenPos(); + nextToken(); + finishNode(node); + + // Octal literals are not allowed in strict mode or ES5 + // Note that theoretically the following condition would hold true literals like 009, + // which is not octal.But because of how the scanner separates the tokens, we would + // never get a token like this. Instead, we would get 00 and 9 as two separate tokens. + // We also do not need to check for negatives because any prefix operator would be part of a + // parent unary expression. + if (node.kind === SyntaxKind.NumericLiteral + && sourceText.charCodeAt(tokenPos) === CharacterCodes._0 + && isOctalDigit(sourceText.charCodeAt(tokenPos + 1))) { + + node.flags |= NodeFlags.OctalLiteral; + } + + return node; + } + + // TYPES + + function parseTypeReference(): TypeReferenceNode { + let node = createNode(SyntaxKind.TypeReference); + node.typeName = parseEntityName(/*allowReservedWords*/ false, Diagnostics.Type_expected); + if (!scanner.hasPrecedingLineBreak() && token === SyntaxKind.LessThanToken) { + node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); + } + return finishNode(node); + } + + function parseTypeQuery(): TypeQueryNode { + let node = createNode(SyntaxKind.TypeQuery); + parseExpected(SyntaxKind.TypeOfKeyword); + node.exprName = parseEntityName(/*allowReservedWords*/ true); + return finishNode(node); + } + + function parseTypeParameter(): TypeParameterDeclaration { + let node = createNode(SyntaxKind.TypeParameter); + node.name = parseIdentifier(); + if (parseOptional(SyntaxKind.ExtendsKeyword)) { + // It's not uncommon for people to write improper constraints to a generic. If the + // user writes a constraint that is an expression and not an actual type, then parse + // it out as an expression (so we can recover well), but report that a type is needed + // instead. + if (isStartOfType() || !isStartOfExpression()) { + node.constraint = parseType(); + } + else { + // It was not a type, and it looked like an expression. Parse out an expression + // here so we recover well. Note: it is important that we call parseUnaryExpression + // and not parseExpression here. If the user has: + // + // + // + // We do *not* want to consume the > as we're consuming the expression for "". + node.expression = parseUnaryExpressionOrHigher(); + } + } + + return finishNode(node); + } + + function parseTypeParameters(): NodeArray { + if (token === SyntaxKind.LessThanToken) { + return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); + } + } + + function parseParameterType(): TypeNode { + if (parseOptional(SyntaxKind.ColonToken)) { + return token === SyntaxKind.StringLiteral + ? parseLiteralNode(/*internName:*/ true) + : parseType(); + } + + return undefined; + } + + function isStartOfParameter(): boolean { + return token === SyntaxKind.DotDotDotToken || isIdentifierOrPattern() || isModifier(token) || token === SyntaxKind.AtToken; + } + + function setModifiers(node: Node, modifiers: ModifiersArray) { + if (modifiers) { + node.flags |= modifiers.flags; + node.modifiers = modifiers; + } + } + + function parseParameter(): ParameterDeclaration { + let node = createNode(SyntaxKind.Parameter); + node.decorators = parseDecorators(); + setModifiers(node, parseModifiers()); + node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); + + // SingleNameBinding[Yield,GeneratorParameter] : See 13.2.3 + // [+GeneratorParameter]BindingIdentifier[Yield]Initializer[In]opt + // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt + + node.name = inGeneratorParameterContext() ? doInYieldContext(parseIdentifierOrPattern) : parseIdentifierOrPattern(); + + if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifier(token)) { + // in cases like + // 'use strict' + // function foo(static) + // isParameter('static') === true, because of isModifier('static') + // however 'static' is not a legal identifier in a strict mode. + // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined) + // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM) + // to avoid this we'll advance cursor to the next token. + nextToken(); + } + + node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken); + node.type = parseParameterType(); + node.initializer = inGeneratorParameterContext() ? doOutsideOfYieldContext(parseParameterInitializer) : parseParameterInitializer(); + + // Do not check for initializers in an ambient context for parameters. This is not + // a grammar error because the grammar allows arbitrary call signatures in + // an ambient context. + // It is actually not necessary for this to be an error at all. The reason is that + // function/constructor implementations are syntactically disallowed in ambient + // contexts. In addition, parameter initializers are semantically disallowed in + // overload signatures. So parameter initializers are transitively disallowed in + // ambient contexts. + return finishNode(node); + } + + function parseParameterInitializer() { + return parseInitializer(/*inParameter*/ true); + } + + function fillSignature( + returnToken: SyntaxKind, + yieldAndGeneratorParameterContext: boolean, + requireCompleteParameterList: boolean, + signature: SignatureDeclaration): void { + let returnTokenRequired = returnToken === SyntaxKind.EqualsGreaterThanToken; + signature.typeParameters = parseTypeParameters(); + signature.parameters = parseParameterList(yieldAndGeneratorParameterContext, requireCompleteParameterList); + + if (returnTokenRequired) { + parseExpected(returnToken); + signature.type = parseType(); + } + else if (parseOptional(returnToken)) { + signature.type = parseType(); + } + } + + // Note: after careful analysis of the grammar, it does not appear to be possible to + // have 'Yield' And 'GeneratorParameter' not in sync. i.e. any production calling + // this FormalParameters production either always sets both to true, or always sets + // both to false. As such we only have a single parameter to represent both. + function parseParameterList(yieldAndGeneratorParameterContext: boolean, requireCompleteParameterList: boolean) { + // FormalParameters[Yield,GeneratorParameter] : + // ... + // + // FormalParameter[Yield,GeneratorParameter] : + // BindingElement[?Yield, ?GeneratorParameter] + // + // BindingElement[Yield, GeneratorParameter ] : See 13.2.3 + // SingleNameBinding[?Yield, ?GeneratorParameter] + // [+GeneratorParameter]BindingPattern[?Yield, GeneratorParameter]Initializer[In]opt + // [~GeneratorParameter]BindingPattern[?Yield]Initializer[In, ?Yield]opt + // + // SingleNameBinding[Yield, GeneratorParameter] : See 13.2.3 + // [+GeneratorParameter]BindingIdentifier[Yield]Initializer[In]opt + // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt + if (parseExpected(SyntaxKind.OpenParenToken)) { + let savedYieldContext = inYieldContext(); + let savedGeneratorParameterContext = inGeneratorParameterContext(); + + setYieldContext(yieldAndGeneratorParameterContext); + setGeneratorParameterContext(yieldAndGeneratorParameterContext); + + let result = parseDelimitedList(ParsingContext.Parameters, parseParameter); + + setYieldContext(savedYieldContext); + setGeneratorParameterContext(savedGeneratorParameterContext); + + if (!parseExpected(SyntaxKind.CloseParenToken) && requireCompleteParameterList) { + // Caller insisted that we had to end with a ) We didn't. So just return + // undefined here. + return undefined; + } + + return result; + } + + // We didn't even have an open paren. If the caller requires a complete parameter list, + // we definitely can't provide that. However, if they're ok with an incomplete one, + // then just return an empty set of parameters. + return requireCompleteParameterList ? undefined : createMissingList(); + } + + function parseTypeMemberSemicolon() { + // We allow type members to be separated by commas or (possibly ASI) semicolons. + // First check if it was a comma. If so, we're done with the member. + if (parseOptional(SyntaxKind.CommaToken)) { + return; + } + + // Didn't have a comma. We must have a (possible ASI) semicolon. + parseSemicolon(); + } + + function parseSignatureMember(kind: SyntaxKind): SignatureDeclaration { + let node = createNode(kind); + if (kind === SyntaxKind.ConstructSignature) { + parseExpected(SyntaxKind.NewKeyword); + } + fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ false, /*requireCompleteParameterList:*/ false, node); + parseTypeMemberSemicolon(); + return finishNode(node); + } + + function isIndexSignature(): boolean { + if (token !== SyntaxKind.OpenBracketToken) { + return false; + } + + return lookAhead(isUnambiguouslyIndexSignature); + } + + function isUnambiguouslyIndexSignature() { + // The only allowed sequence is: + // + // [id: + // + // However, for error recovery, we also check the following cases: + // + // [... + // [id, + // [id?, + // [id?: + // [id?] + // [public id + // [private id + // [protected id + // [] + // + nextToken(); + if (token === SyntaxKind.DotDotDotToken || token === SyntaxKind.CloseBracketToken) { + return true; + } + + if (isModifier(token)) { + nextToken(); + if (isIdentifier()) { + return true; + } + } + else if (!isIdentifier()) { + return false; + } + else { + // Skip the identifier + nextToken(); + } + + // A colon signifies a well formed indexer + // A comma should be a badly formed indexer because comma expressions are not allowed + // in computed properties. + if (token === SyntaxKind.ColonToken || token === SyntaxKind.CommaToken) { + return true; + } + + // Question mark could be an indexer with an optional property, + // or it could be a conditional expression in a computed property. + if (token !== SyntaxKind.QuestionToken) { + return false; + } + + // If any of the following tokens are after the question mark, it cannot + // be a conditional expression, so treat it as an indexer. + nextToken(); + return token === SyntaxKind.ColonToken || token === SyntaxKind.CommaToken || token === SyntaxKind.CloseBracketToken; + } + + function parseIndexSignatureDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): IndexSignatureDeclaration { + let node = createNode(SyntaxKind.IndexSignature, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + node.parameters = parseBracketedList(ParsingContext.Parameters, parseParameter, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); + node.type = parseTypeAnnotation(); + parseTypeMemberSemicolon(); + return finishNode(node) + } + + function parsePropertyOrMethodSignature(): Declaration { + let fullStart = scanner.getStartPos(); + let name = parsePropertyName(); + let questionToken = parseOptionalToken(SyntaxKind.QuestionToken); + + if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { + let method = createNode(SyntaxKind.MethodSignature, fullStart); + method.name = name; + method.questionToken = questionToken; + + // Method signatues don't exist in expression contexts. So they have neither + // [Yield] nor [GeneratorParameter] + fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ false, /*requireCompleteParameterList:*/ false, method); + parseTypeMemberSemicolon(); + return finishNode(method); + } + else { + let property = createNode(SyntaxKind.PropertySignature, fullStart); + property.name = name; + property.questionToken = questionToken; + property.type = parseTypeAnnotation(); + parseTypeMemberSemicolon(); + return finishNode(property); + } + } + + function isStartOfTypeMember(): boolean { + switch (token) { + case SyntaxKind.OpenParenToken: + case SyntaxKind.LessThanToken: + case SyntaxKind.OpenBracketToken: // Both for indexers and computed properties + return true; + default: + if (isModifier(token)) { + let result = lookAhead(isStartOfIndexSignatureDeclaration); + if (result) { + return result; + } + } + + return isLiteralPropertyName() && lookAhead(isTypeMemberWithLiteralPropertyName); + } + } + + function isStartOfIndexSignatureDeclaration() { + while (isModifier(token)) { + nextToken(); + } + + return isIndexSignature(); + } + + function isTypeMemberWithLiteralPropertyName() { + nextToken(); + return token === SyntaxKind.OpenParenToken || + token === SyntaxKind.LessThanToken || + token === SyntaxKind.QuestionToken || + token === SyntaxKind.ColonToken || + canParseSemicolon(); + } + + function parseTypeMember(): Declaration { + switch (token) { + case SyntaxKind.OpenParenToken: + case SyntaxKind.LessThanToken: + return parseSignatureMember(SyntaxKind.CallSignature); + case SyntaxKind.OpenBracketToken: + // Indexer or computed property + return isIndexSignature() + ? parseIndexSignatureDeclaration(scanner.getStartPos(), /*decorators*/ undefined, /*modifiers:*/ undefined) + : parsePropertyOrMethodSignature(); + case SyntaxKind.NewKeyword: + if (lookAhead(isStartOfConstructSignature)) { + return parseSignatureMember(SyntaxKind.ConstructSignature); + } + // fall through. + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + return parsePropertyOrMethodSignature(); + default: + // Index declaration as allowed as a type member. But as per the grammar, + // they also allow modifiers. So we have to check for an index declaration + // that might be following modifiers. This ensures that things work properly + // when incrementally parsing as the parser will produce the Index declaration + // if it has the same text regardless of whether it is inside a class or an + // object type. + if (isModifier(token)) { + let result = tryParse(parseIndexSignatureWithModifiers); + if (result) { + return result; + } + } + + if (isIdentifierOrKeyword()) { + return parsePropertyOrMethodSignature(); + } + } + } + + function parseIndexSignatureWithModifiers() { + let fullStart = scanner.getStartPos(); + let decorators = parseDecorators(); + let modifiers = parseModifiers(); + return isIndexSignature() + ? parseIndexSignatureDeclaration(fullStart, decorators, modifiers) + : undefined; + } + + function isStartOfConstructSignature() { + nextToken(); + return token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken; + } + + function parseTypeLiteral(): TypeLiteralNode { + let node = createNode(SyntaxKind.TypeLiteral); + node.members = parseObjectTypeMembers(); + return finishNode(node); + } + + function parseObjectTypeMembers(): NodeArray { + let members: NodeArray; + if (parseExpected(SyntaxKind.OpenBraceToken)) { + members = parseList(ParsingContext.TypeMembers, /*checkForStrictMode*/ false, parseTypeMember); + parseExpected(SyntaxKind.CloseBraceToken); + } + else { + members = createMissingList(); + } + + return members; + } + + function parseTupleType(): TupleTypeNode { + let node = createNode(SyntaxKind.TupleType); + node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); + return finishNode(node); + } + + function parseParenthesizedType(): ParenthesizedTypeNode { + let node = createNode(SyntaxKind.ParenthesizedType); + parseExpected(SyntaxKind.OpenParenToken); + node.type = parseType(); + parseExpected(SyntaxKind.CloseParenToken); + return finishNode(node); + } + + function parseFunctionOrConstructorType(kind: SyntaxKind): FunctionOrConstructorTypeNode { + let node = createNode(kind); + if (kind === SyntaxKind.ConstructorType) { + parseExpected(SyntaxKind.NewKeyword); + } + fillSignature(SyntaxKind.EqualsGreaterThanToken, /*yieldAndGeneratorParameterContext:*/ false, /*requireCompleteParameterList:*/ false, node); + return finishNode(node); + } + + function parseKeywordAndNoDot(): TypeNode { + let node = parseTokenNode(); + return token === SyntaxKind.DotToken ? undefined : node; + } + + function parseNonArrayType(): TypeNode { + switch (token) { + case SyntaxKind.AnyKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.SymbolKeyword: + // If these are followed by a dot, then parse these out as a dotted type reference instead. + let node = tryParse(parseKeywordAndNoDot); + return node || parseTypeReference(); + case SyntaxKind.VoidKeyword: + return parseTokenNode(); + case SyntaxKind.TypeOfKeyword: + return parseTypeQuery(); + case SyntaxKind.OpenBraceToken: + return parseTypeLiteral(); + case SyntaxKind.OpenBracketToken: + return parseTupleType(); + case SyntaxKind.OpenParenToken: + return parseParenthesizedType(); + default: + return parseTypeReference(); + } + } + + function isStartOfType(): boolean { + switch (token) { + case SyntaxKind.AnyKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.SymbolKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.TypeOfKeyword: + case SyntaxKind.OpenBraceToken: + case SyntaxKind.OpenBracketToken: + case SyntaxKind.LessThanToken: + case SyntaxKind.NewKeyword: + return true; + case SyntaxKind.OpenParenToken: + // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier, + // or something that starts a type. We don't want to consider things like '(1)' a type. + return lookAhead(isStartOfParenthesizedOrFunctionType); + default: + return isIdentifier(); + } + } + + function isStartOfParenthesizedOrFunctionType() { + nextToken(); + return token === SyntaxKind.CloseParenToken || isStartOfParameter() || isStartOfType(); + } + + function parseArrayTypeOrHigher(): TypeNode { + let type = parseNonArrayType(); + while (!scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.OpenBracketToken)) { + parseExpected(SyntaxKind.CloseBracketToken); + let node = createNode(SyntaxKind.ArrayType, type.pos); + node.elementType = type; + type = finishNode(node); + } + return type; + } + + function parseUnionTypeOrHigher(): TypeNode { + let type = parseArrayTypeOrHigher(); + if (token === SyntaxKind.BarToken) { + let types = >[type]; + types.pos = type.pos; + while (parseOptional(SyntaxKind.BarToken)) { + types.push(parseArrayTypeOrHigher()); + } + types.end = getNodeEnd(); + let node = createNode(SyntaxKind.UnionType, type.pos); + node.types = types; + type = finishNode(node); + } + return type; + } + + function isStartOfFunctionType(): boolean { + if (token === SyntaxKind.LessThanToken) { + return true; + } + + return token === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType); + } + + function isUnambiguouslyStartOfFunctionType() { + nextToken(); + if (token === SyntaxKind.CloseParenToken || token === SyntaxKind.DotDotDotToken) { + // ( ) + // ( ... + return true; + } + if (isIdentifier() || isModifier(token)) { + nextToken(); + if (token === SyntaxKind.ColonToken || token === SyntaxKind.CommaToken || + token === SyntaxKind.QuestionToken || token === SyntaxKind.EqualsToken || + isIdentifier() || isModifier(token)) { + // ( id : + // ( id , + // ( id ? + // ( id = + // ( modifier id + return true; + } + if (token === SyntaxKind.CloseParenToken) { + nextToken(); + if (token === SyntaxKind.EqualsGreaterThanToken) { + // ( id ) => + return true; + } + } + } + return false; + } + + function parseType(): TypeNode { + // The rules about 'yield' only apply to actual code/expression contexts. They don't + // apply to 'type' contexts. So we disable these parameters here before moving on. + let savedYieldContext = inYieldContext(); + let savedGeneratorParameterContext = inGeneratorParameterContext(); + + setYieldContext(false); + setGeneratorParameterContext(false); + + let result = parseTypeWorker(); + + setYieldContext(savedYieldContext); + setGeneratorParameterContext(savedGeneratorParameterContext); + + return result; + } + + function parseTypeWorker(): TypeNode { + if (isStartOfFunctionType()) { + return parseFunctionOrConstructorType(SyntaxKind.FunctionType); + } + if (token === SyntaxKind.NewKeyword) { + return parseFunctionOrConstructorType(SyntaxKind.ConstructorType); + } + return parseUnionTypeOrHigher(); + } + + function parseTypeAnnotation(): TypeNode { + return parseOptional(SyntaxKind.ColonToken) ? parseType() : undefined; + } + + // EXPRESSIONS + function isStartOfLeftHandSideExpression(): boolean { + switch (token) { + case SyntaxKind.ThisKeyword: + case SyntaxKind.SuperKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.TemplateHead: + case SyntaxKind.OpenParenToken: + case SyntaxKind.OpenBracketToken: + case SyntaxKind.OpenBraceToken: + case SyntaxKind.FunctionKeyword: + case SyntaxKind.ClassKeyword: + case SyntaxKind.NewKeyword: + case SyntaxKind.SlashToken: + case SyntaxKind.SlashEqualsToken: + case SyntaxKind.Identifier: + return true; + default: + return isIdentifier(); + } + } + + function isStartOfExpression(): boolean { + if (isStartOfLeftHandSideExpression()) { + return true; + } + + switch (token) { + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + case SyntaxKind.TildeToken: + case SyntaxKind.ExclamationToken: + case SyntaxKind.DeleteKeyword: + case SyntaxKind.TypeOfKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.PlusPlusToken: + case SyntaxKind.MinusMinusToken: + case SyntaxKind.LessThanToken: + case SyntaxKind.YieldKeyword: + // Yield always starts an expression. Either it is an identifier (in which case + // it is definitely an expression). Or it's a keyword (either because we're in + // a generator, or in strict mode (or both)) and it started a yield expression. + return true; + default: + // Error tolerance. If we see the start of some binary operator, we consider + // that the start of an expression. That way we'll parse out a missing identifier, + // give a good message about an identifier being missing, and then consume the + // rest of the binary expression. + if (isBinaryOperator()) { + return true; + } + + return isIdentifier(); + } + } + + function isStartOfExpressionStatement(): boolean { + // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement. + return token !== SyntaxKind.OpenBraceToken && + token !== SyntaxKind.FunctionKeyword && + token !== SyntaxKind.ClassKeyword && + token !== SyntaxKind.AtToken && + isStartOfExpression(); + } + + function parseExpression(): Expression { + // Expression[in]: + // AssignmentExpression[in] + // Expression[in] , AssignmentExpression[in] + + // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator + let saveDecoratorContext = inDecoratorContext(); + if (saveDecoratorContext) { + setDecoratorContext(false); + } + + let expr = parseAssignmentExpressionOrHigher(); + let operatorToken: Node; + while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) { + expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher()); + } + + if (saveDecoratorContext) { + setDecoratorContext(true); + } + return expr; + } + + function parseInitializer(inParameter: boolean): Expression { + if (token !== SyntaxKind.EqualsToken) { + // It's not uncommon during typing for the user to miss writing the '=' token. Check if + // there is no newline after the last token and if we're on an expression. If so, parse + // this as an equals-value clause with a missing equals. + // NOTE: There are two places where we allow equals-value clauses. The first is in a + // variable declarator. The second is with a parameter. For variable declarators + // it's more likely that a { would be a allowed (as an object literal). While this + // is also allowed for parameters, the risk is that we consume the { as an object + // literal when it really will be for the block following the parameter. + if (scanner.hasPrecedingLineBreak() || (inParameter && token === SyntaxKind.OpenBraceToken) || !isStartOfExpression()) { + // preceding line break, open brace in a parameter (likely a function body) or current token is not an expression - + // do not try to parse initializer + return undefined; + } + } + + // Initializer[In, Yield] : + // = AssignmentExpression[?In, ?Yield] + + parseExpected(SyntaxKind.EqualsToken); + return parseAssignmentExpressionOrHigher(); + } + + function parseAssignmentExpressionOrHigher(): Expression { + // AssignmentExpression[in,yield]: + // 1) ConditionalExpression[?in,?yield] + // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield] + // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield] + // 4) ArrowFunctionExpression[?in,?yield] + // 5) [+Yield] YieldExpression[?In] + // + // Note: for ease of implementation we treat productions '2' and '3' as the same thing. + // (i.e. they're both BinaryExpressions with an assignment operator in it). + + // First, do the simple check if we have a YieldExpression (production '5'). + if (isYieldExpression()) { + return parseYieldExpression(); + } + + // Then, check if we have an arrow function (production '4') that starts with a parenthesized + // parameter list. If we do, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is + // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done + // with AssignmentExpression if we see one. + let arrowExpression = tryParseParenthesizedArrowFunctionExpression(); + if (arrowExpression) { + return arrowExpression; + } + + // Now try to see if we're in production '1', '2' or '3'. A conditional expression can + // start with a LogicalOrExpression, while the assignment productions can only start with + // LeftHandSideExpressions. + // + // So, first, we try to just parse out a BinaryExpression. If we get something that is a + // LeftHandSide or higher, then we can try to parse out the assignment expression part. + // Otherwise, we try to parse out the conditional expression bit. We want to allow any + // binary expression here, so we pass in the 'lowest' precedence here so that it matches + // and consumes anything. + let expr = parseBinaryExpressionOrHigher(/*precedence:*/ 0); + + // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized + // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single + // identifier and the current token is an arrow. + if (expr.kind === SyntaxKind.Identifier && token === SyntaxKind.EqualsGreaterThanToken) { + return parseSimpleArrowFunctionExpression(expr); + } + + // Now see if we might be in cases '2' or '3'. + // If the expression was a LHS expression, and we have an assignment operator, then + // we're in '2' or '3'. Consume the assignment and return. + // + // Note: we call reScanGreaterToken so that we get an appropriately merged token + // for cases like > > = becoming >>= + if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) { + return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher()); + } + + // It wasn't an assignment or a lambda. This is a conditional expression: + return parseConditionalExpressionRest(expr); + } + + function isYieldExpression(): boolean { + if (token === SyntaxKind.YieldKeyword) { + // If we have a 'yield' keyword, and htis is a context where yield expressions are + // allowed, then definitely parse out a yield expression. + if (inYieldContext()) { + return true; + } + + if (inStrictModeContext()) { + // If we're in strict mode, then 'yield' is a keyword, could only ever start + // a yield expression. + return true; + } + + // We're in a context where 'yield expr' is not allowed. However, if we can + // definitely tell that the user was trying to parse a 'yield expr' and not + // just a normal expr that start with a 'yield' identifier, then parse out + // a 'yield expr'. We can then report an error later that they are only + // allowed in generator expressions. + // + // for example, if we see 'yield(foo)', then we'll have to treat that as an + // invocation expression of something called 'yield'. However, if we have + // 'yield foo' then that is not legal as a normal expression, so we can + // definitely recognize this as a yield expression. + // + // for now we just check if the next token is an identifier. More heuristics + // can be added here later as necessary. We just need to make sure that we + // don't accidently consume something legal. + return lookAhead(nextTokenIsIdentifierOnSameLine); + } + + return false; + } + + function nextTokenIsIdentifierOnSameLine() { + nextToken(); + return !scanner.hasPrecedingLineBreak() && isIdentifier() + } + + function nextTokenIsIdentifierOrStartOfDestructuringOnTheSameLine() { + nextToken(); + return !scanner.hasPrecedingLineBreak() && + (isIdentifier() || token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken); + } + + function parseYieldExpression(): YieldExpression { + let node = createNode(SyntaxKind.YieldExpression); + + // YieldExpression[In] : + // yield + // yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] + // yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] + nextToken(); + + if (!scanner.hasPrecedingLineBreak() && + (token === SyntaxKind.AsteriskToken || isStartOfExpression())) { + node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); + node.expression = parseAssignmentExpressionOrHigher(); + return finishNode(node); + } + else { + // if the next token is not on the same line as yield. or we don't have an '*' or + // the start of an expressin, then this is just a simple "yield" expression. + return finishNode(node); + } + } + + function parseSimpleArrowFunctionExpression(identifier: Identifier): Expression { + Debug.assert(token === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); + + let node = createNode(SyntaxKind.ArrowFunction, identifier.pos); + + let parameter = createNode(SyntaxKind.Parameter, identifier.pos); + parameter.name = identifier; + finishNode(parameter); + + node.parameters = >[parameter]; + node.parameters.pos = parameter.pos; + node.parameters.end = parameter.end; + + node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>"); + node.body = parseArrowFunctionExpressionBody(); + + return finishNode(node); + } + + function tryParseParenthesizedArrowFunctionExpression(): Expression { + let triState = isParenthesizedArrowFunctionExpression(); + + if (triState === Tristate.False) { + // It's definitely not a parenthesized arrow function expression. + return undefined; + } + + // If we definitely have an arrow function, then we can just parse one, not requiring a + // following => or { token. Otherwise, we *might* have an arrow function. Try to parse + // it out, but don't allow any ambiguity, and return 'undefined' if this could be an + // expression instead. + let arrowFunction = triState === Tristate.True + ? parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity:*/ true) + : tryParse(parsePossibleParenthesizedArrowFunctionExpressionHead); + + if (!arrowFunction) { + // Didn't appear to actually be a parenthesized arrow function. Just bail out. + return undefined; + } + + // If we have an arrow, then try to parse the body. Even if not, try to parse if we + // have an opening brace, just in case we're in an error state. + var lastToken = token; + arrowFunction.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition:*/false, Diagnostics._0_expected, "=>"); + arrowFunction.body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken) + ? parseArrowFunctionExpressionBody() + : parseIdentifier(); + + return finishNode(arrowFunction); + } + + // True -> We definitely expect a parenthesized arrow function here. + // False -> There *cannot* be a parenthesized arrow function here. + // Unknown -> There *might* be a parenthesized arrow function here. + // Speculatively look ahead to be sure, and rollback if not. + function isParenthesizedArrowFunctionExpression(): Tristate { + if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { + return lookAhead(isParenthesizedArrowFunctionExpressionWorker); + } + + if (token === SyntaxKind.EqualsGreaterThanToken) { + // ERROR RECOVERY TWEAK: + // If we see a standalone => try to parse it as an arrow function expression as that's + // likely what the user intended to write. + return Tristate.True; + } + // Definitely not a parenthesized arrow function. + return Tristate.False; + } + + function isParenthesizedArrowFunctionExpressionWorker() { + let first = token; + let second = nextToken(); + + if (first === SyntaxKind.OpenParenToken) { + if (second === SyntaxKind.CloseParenToken) { + // Simple cases: "() =>", "(): ", and "() {". + // This is an arrow function with no parameters. + // The last one is not actually an arrow function, + // but this is probably what the user intended. + let third = nextToken(); + switch (third) { + case SyntaxKind.EqualsGreaterThanToken: + case SyntaxKind.ColonToken: + case SyntaxKind.OpenBraceToken: + return Tristate.True; + default: + return Tristate.False; + } + } + + // If encounter "([" or "({", this could be the start of a binding pattern. + // Examples: + // ([ x ]) => { } + // ({ x }) => { } + // ([ x ]) + // ({ x }) + if (second === SyntaxKind.OpenBracketToken || second === SyntaxKind.OpenBraceToken) { + return Tristate.Unknown; + } + + // Simple case: "(..." + // This is an arrow function with a rest parameter. + if (second === SyntaxKind.DotDotDotToken) { + return Tristate.True; + } + + // If we had "(" followed by something that's not an identifier, + // then this definitely doesn't look like a lambda. + // Note: we could be a little more lenient and allow + // "(public" or "(private". These would not ever actually be allowed, + // but we could provide a good error message instead of bailing out. + if (!isIdentifier()) { + return Tristate.False; + } + + // If we have something like "(a:", then we must have a + // type-annotated parameter in an arrow function expression. + if (nextToken() === SyntaxKind.ColonToken) { + return Tristate.True; + } + + // This *could* be a parenthesized arrow function. + // Return Unknown to let the caller know. + return Tristate.Unknown; + } + else { + Debug.assert(first === SyntaxKind.LessThanToken); + + // If we have "<" not followed by an identifier, + // then this definitely is not an arrow function. + if (!isIdentifier()) { + return Tristate.False; + } + + // This *could* be a parenthesized arrow function. + return Tristate.Unknown; + } + } + + function parsePossibleParenthesizedArrowFunctionExpressionHead(): ArrowFunction { + return parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity:*/ false); + } + + function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction { + let node = createNode(SyntaxKind.ArrowFunction); + // Arrow functions are never generators. + // + // If we're speculatively parsing a signature for a parenthesized arrow function, then + // we have to have a complete parameter list. Otherwise we might see something like + // a => (b => c) + // And think that "(b =>" was actually a parenthesized arrow function with a missing + // close paren. + fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ false, /*requireCompleteParameterList:*/ !allowAmbiguity, node); + + // If we couldn't get parameters, we definitely could not parse out an arrow function. + if (!node.parameters) { + return undefined; + } + + // Parsing a signature isn't enough. + // Parenthesized arrow signatures often look like other valid expressions. + // For instance: + // - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value. + // - "(x,y)" is a comma expression parsed as a signature with two parameters. + // - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation. + // + // So we need just a bit of lookahead to ensure that it can only be a signature. + if (!allowAmbiguity && token !== SyntaxKind.EqualsGreaterThanToken && token !== SyntaxKind.OpenBraceToken) { + // Returning undefined here will cause our caller to rewind to where we started from. + return undefined; + } + + return node; + } + + function parseArrowFunctionExpressionBody(): Block | Expression { + if (token === SyntaxKind.OpenBraceToken) { + return parseFunctionBlock(/*allowYield:*/ false, /* ignoreMissingOpenBrace */ false); + } + + if (isStartOfStatement(/*inErrorRecovery:*/ true) && + !isStartOfExpressionStatement() && + token !== SyntaxKind.FunctionKeyword && + token !== SyntaxKind.ClassKeyword) { + + // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations) + // + // Here we try to recover from a potential error situation in the case where the + // user meant to supply a block. For example, if the user wrote: + // + // a => + // let v = 0; + // } + // + // they may be missing an open brace. Check to see if that's the case so we can + // try to recover better. If we don't do this, then the next close curly we see may end + // up preemptively closing the containing construct. + // + // Note: even when 'ignoreMissingOpenBrace' is passed as true, parseBody will still error. + return parseFunctionBlock(/*allowYield:*/ false, /* ignoreMissingOpenBrace */ true); + } + + return parseAssignmentExpressionOrHigher(); + } + + function parseConditionalExpressionRest(leftOperand: Expression): Expression { + // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. + let questionToken = parseOptionalToken(SyntaxKind.QuestionToken); + if (!questionToken) { + return leftOperand; + } + + // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and + // we do not that for the 'whenFalse' part. + let node = createNode(SyntaxKind.ConditionalExpression, leftOperand.pos); + node.condition = leftOperand; + node.questionToken = questionToken; + node.whenTrue = doOutsideOfContext(disallowInAndDecoratorContext, parseAssignmentExpressionOrHigher); + node.colonToken = parseExpectedToken(SyntaxKind.ColonToken, /*reportAtCurrentPosition:*/ false, + Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)); + node.whenFalse = parseAssignmentExpressionOrHigher(); + return finishNode(node); + } + + function parseBinaryExpressionOrHigher(precedence: number): Expression { + let leftOperand = parseUnaryExpressionOrHigher(); + return parseBinaryExpressionRest(precedence, leftOperand); + } + + function isInOrOfKeyword(t: SyntaxKind) { + return t === SyntaxKind.InKeyword || t === SyntaxKind.OfKeyword; + } + + function parseBinaryExpressionRest(precedence: number, leftOperand: Expression): Expression { + while (true) { + // We either have a binary operator here, or we're finished. We call + // reScanGreaterToken so that we merge token sequences like > and = into >= + + reScanGreaterToken(); + let newPrecedence = getBinaryOperatorPrecedence(); + + // Check the precedence to see if we should "take" this operator + if (newPrecedence <= precedence) { + break; + } + + if (token === SyntaxKind.InKeyword && inDisallowInContext()) { + break; + } + + leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence)); + } + + return leftOperand; + } + + function isBinaryOperator() { + if (inDisallowInContext() && token === SyntaxKind.InKeyword) { + return false; + } + + return getBinaryOperatorPrecedence() > 0; + } + + function getBinaryOperatorPrecedence(): number { + switch (token) { + case SyntaxKind.BarBarToken: + return 1; + case SyntaxKind.AmpersandAmpersandToken: + return 2; + case SyntaxKind.BarToken: + return 3; + case SyntaxKind.CaretToken: + return 4; + case SyntaxKind.AmpersandToken: + return 5; + case SyntaxKind.EqualsEqualsToken: + case SyntaxKind.ExclamationEqualsToken: + case SyntaxKind.EqualsEqualsEqualsToken: + case SyntaxKind.ExclamationEqualsEqualsToken: + return 6; + case SyntaxKind.LessThanToken: + case SyntaxKind.GreaterThanToken: + case SyntaxKind.LessThanEqualsToken: + case SyntaxKind.GreaterThanEqualsToken: + case SyntaxKind.InstanceOfKeyword: + case SyntaxKind.InKeyword: + return 7; + case SyntaxKind.LessThanLessThanToken: + case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + return 8; + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + return 9; + case SyntaxKind.AsteriskToken: + case SyntaxKind.SlashToken: + case SyntaxKind.PercentToken: + return 10; + } + + // -1 is lower than all other precedences. Returning it will cause binary expression + // parsing to stop. + return -1; + } + + function makeBinaryExpression(left: Expression, operatorToken: Node, right: Expression): BinaryExpression { + let node = createNode(SyntaxKind.BinaryExpression, left.pos); + node.left = left; + node.operatorToken = operatorToken; + node.right = right; + return finishNode(node); + } + + function parsePrefixUnaryExpression() { + let node = createNode(SyntaxKind.PrefixUnaryExpression); + node.operator = token; + nextToken(); + node.operand = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + + function parseDeleteExpression() { + let node = createNode(SyntaxKind.DeleteExpression); + nextToken(); + node.expression = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + + function parseTypeOfExpression() { + let node = createNode(SyntaxKind.TypeOfExpression); + nextToken(); + node.expression = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + + function parseVoidExpression() { + let node = createNode(SyntaxKind.VoidExpression); + nextToken(); + node.expression = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + + function parseUnaryExpressionOrHigher(): UnaryExpression { + switch (token) { + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + case SyntaxKind.TildeToken: + case SyntaxKind.ExclamationToken: + case SyntaxKind.PlusPlusToken: + case SyntaxKind.MinusMinusToken: + return parsePrefixUnaryExpression(); + case SyntaxKind.DeleteKeyword: + return parseDeleteExpression(); + case SyntaxKind.TypeOfKeyword: + return parseTypeOfExpression(); + case SyntaxKind.VoidKeyword: + return parseVoidExpression(); + case SyntaxKind.LessThanToken: + return parseTypeAssertion(); + default: + return parsePostfixExpressionOrHigher(); + } + } + + function parsePostfixExpressionOrHigher(): PostfixExpression { + let expression = parseLeftHandSideExpressionOrHigher(); + + Debug.assert(isLeftHandSideExpression(expression)); + if ((token === SyntaxKind.PlusPlusToken || token === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) { + let node = createNode(SyntaxKind.PostfixUnaryExpression, expression.pos); + node.operand = expression; + node.operator = token; + nextToken(); + return finishNode(node); + } + + return expression; + } + + function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression { + // Original Ecma: + // LeftHandSideExpression: See 11.2 + // NewExpression + // CallExpression + // + // Our simplification: + // + // LeftHandSideExpression: See 11.2 + // MemberExpression + // CallExpression + // + // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with + // MemberExpression to make our lives easier. + // + // to best understand the below code, it's important to see how CallExpression expands + // out into its own productions: + // + // CallExpression: + // MemberExpression Arguments + // CallExpression Arguments + // CallExpression[Expression] + // CallExpression.IdentifierName + // super ( ArgumentListopt ) + // super.IdentifierName + // + // Because of the recursion in these calls, we need to bottom out first. There are two + // bottom out states we can run into. Either we see 'super' which must start either of + // the last two CallExpression productions. Or we have a MemberExpression which either + // completes the LeftHandSideExpression, or starts the beginning of the first four + // CallExpression productions. + let expression = token === SyntaxKind.SuperKeyword + ? parseSuperExpression() + : parseMemberExpressionOrHigher(); + + // Now, we *may* be complete. However, we might have consumed the start of a + // CallExpression. As such, we need to consume the rest of it here to be complete. + return parseCallExpressionRest(expression); + } + + function parseMemberExpressionOrHigher(): MemberExpression { + // Note: to make our lives simpler, we decompose the the NewExpression productions and + // place ObjectCreationExpression and FunctionExpression into PrimaryExpression. + // like so: + // + // PrimaryExpression : See 11.1 + // this + // Identifier + // Literal + // ArrayLiteral + // ObjectLiteral + // (Expression) + // FunctionExpression + // new MemberExpression Arguments? + // + // MemberExpression : See 11.2 + // PrimaryExpression + // MemberExpression[Expression] + // MemberExpression.IdentifierName + // + // CallExpression : See 11.2 + // MemberExpression + // CallExpression Arguments + // CallExpression[Expression] + // CallExpression.IdentifierName + // + // Technically this is ambiguous. i.e. CallExpression defines: + // + // CallExpression: + // CallExpression Arguments + // + // If you see: "new Foo()" + // + // Then that could be treated as a single ObjectCreationExpression, or it could be + // treated as the invocation of "new Foo". We disambiguate that in code (to match + // the original grammar) by making sure that if we see an ObjectCreationExpression + // we always consume arguments if they are there. So we treat "new Foo()" as an + // object creation only, and not at all as an invocation) Another way to think + // about this is that for every "new" that we see, we will consume an argument list if + // it is there as part of the *associated* object creation node. Any additional + // argument lists we see, will become invocation expressions. + // + // Because there are no other places in the grammar now that refer to FunctionExpression + // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression + // production. + // + // Because CallExpression and MemberExpression are left recursive, we need to bottom out + // of the recursion immediately. So we parse out a primary expression to start with. + let expression = parsePrimaryExpression(); + return parseMemberExpressionRest(expression); + } + + function parseSuperExpression(): MemberExpression { + let expression = parseTokenNode(); + if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.DotToken) { + return expression; + } + + // If we have seen "super" it must be followed by '(' or '.'. + // If it wasn't then just try to parse out a '.' and report an error. + let node = createNode(SyntaxKind.PropertyAccessExpression, expression.pos); + node.expression = expression; + node.dotToken = parseExpectedToken(SyntaxKind.DotToken, /*reportAtCurrentPosition:*/ false, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); + node.name = parseRightSideOfDot(/*allowIdentifierNames:*/ true); + return finishNode(node); + } + + function parseTypeAssertion(): TypeAssertion { + let node = createNode(SyntaxKind.TypeAssertionExpression); + parseExpected(SyntaxKind.LessThanToken); + node.type = parseType(); + parseExpected(SyntaxKind.GreaterThanToken); + node.expression = parseUnaryExpressionOrHigher(); + return finishNode(node); + } + + function parseMemberExpressionRest(expression: LeftHandSideExpression): MemberExpression { + while (true) { + let dotToken = parseOptionalToken(SyntaxKind.DotToken); + if (dotToken) { + let propertyAccess = createNode(SyntaxKind.PropertyAccessExpression, expression.pos); + propertyAccess.expression = expression; + propertyAccess.dotToken = dotToken; + propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames:*/ true); + expression = finishNode(propertyAccess); + continue; + } + + // when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName + if (!inDecoratorContext() && parseOptional(SyntaxKind.OpenBracketToken)) { + let indexedAccess = createNode(SyntaxKind.ElementAccessExpression, expression.pos); + indexedAccess.expression = expression; + + // It's not uncommon for a user to write: "new Type[]". + // Check for that common pattern and report a better error message. + if (token !== SyntaxKind.CloseBracketToken) { + indexedAccess.argumentExpression = allowInAnd(parseExpression); + if (indexedAccess.argumentExpression.kind === SyntaxKind.StringLiteral || indexedAccess.argumentExpression.kind === SyntaxKind.NumericLiteral) { + let literal = indexedAccess.argumentExpression; + literal.text = internIdentifier(literal.text); + } + } + + parseExpected(SyntaxKind.CloseBracketToken); + expression = finishNode(indexedAccess); + continue; + } + + if (token === SyntaxKind.NoSubstitutionTemplateLiteral || token === SyntaxKind.TemplateHead) { + let tagExpression = createNode(SyntaxKind.TaggedTemplateExpression, expression.pos); + tagExpression.tag = expression; + tagExpression.template = token === SyntaxKind.NoSubstitutionTemplateLiteral + ? parseLiteralNode() + : parseTemplateExpression(); + expression = finishNode(tagExpression); + continue; + } + + return expression; + } + } + + function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression { + while (true) { + expression = parseMemberExpressionRest(expression); + if (token === SyntaxKind.LessThanToken) { + // See if this is the start of a generic invocation. If so, consume it and + // keep checking for postfix expressions. Otherwise, it's just a '<' that's + // part of an arithmetic expression. Break out so we consume it higher in the + // stack. + let typeArguments = tryParse(parseTypeArgumentsInExpression); + if (!typeArguments) { + return expression; + } + + let callExpr = createNode(SyntaxKind.CallExpression, expression.pos); + callExpr.expression = expression; + callExpr.typeArguments = typeArguments; + callExpr.arguments = parseArgumentList(); + expression = finishNode(callExpr); + continue; + } + else if (token === SyntaxKind.OpenParenToken) { + let callExpr = createNode(SyntaxKind.CallExpression, expression.pos); + callExpr.expression = expression; + callExpr.arguments = parseArgumentList(); + expression = finishNode(callExpr); + continue; + } + + return expression; + } + } + + function parseArgumentList() { + parseExpected(SyntaxKind.OpenParenToken); + let result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression); + parseExpected(SyntaxKind.CloseParenToken); + return result; + } + + function parseTypeArgumentsInExpression() { + if (!parseOptional(SyntaxKind.LessThanToken)) { + return undefined; + } + + let typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType); + if (!parseExpected(SyntaxKind.GreaterThanToken)) { + // If it doesn't have the closing > then it's definitely not an type argument list. + return undefined; + } + + // If we have a '<', then only parse this as a arugment list if the type arguments + // are complete and we have an open paren. if we don't, rewind and return nothing. + return typeArguments && canFollowTypeArgumentsInExpression() + ? typeArguments + : undefined; + } + + function canFollowTypeArgumentsInExpression(): boolean { + switch (token) { + case SyntaxKind.OpenParenToken: // foo( + // this case are the only case where this token can legally follow a type argument + // list. So we definitely want to treat this as a type arg list. + + case SyntaxKind.DotToken: // foo. + case SyntaxKind.CloseParenToken: // foo) + case SyntaxKind.CloseBracketToken: // foo] + case SyntaxKind.ColonToken: // foo: + case SyntaxKind.SemicolonToken: // foo; + case SyntaxKind.QuestionToken: // foo? + case SyntaxKind.EqualsEqualsToken: // foo == + case SyntaxKind.EqualsEqualsEqualsToken: // foo === + case SyntaxKind.ExclamationEqualsToken: // foo != + case SyntaxKind.ExclamationEqualsEqualsToken: // foo !== + case SyntaxKind.AmpersandAmpersandToken: // foo && + case SyntaxKind.BarBarToken: // foo || + case SyntaxKind.CaretToken: // foo ^ + case SyntaxKind.AmpersandToken: // foo & + case SyntaxKind.BarToken: // foo | + case SyntaxKind.CloseBraceToken: // foo } + case SyntaxKind.EndOfFileToken: // foo + // these cases can't legally follow a type arg list. However, they're not legal + // expressions either. The user is probably in the middle of a generic type. So + // treat it as such. + return true; + + case SyntaxKind.CommaToken: // foo, + case SyntaxKind.OpenBraceToken: // foo { + // We don't want to treat these as type arguments. Otherwise we'll parse this + // as an invocation expression. Instead, we want to parse out the expression + // in isolation from the type arguments. + + default: + // Anything else treat as an expression. + return false; + } + } + + function parsePrimaryExpression(): PrimaryExpression { + switch (token) { + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + return parseLiteralNode(); + case SyntaxKind.ThisKeyword: + case SyntaxKind.SuperKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + return parseTokenNode(); + case SyntaxKind.OpenParenToken: + return parseParenthesizedExpression(); + case SyntaxKind.OpenBracketToken: + return parseArrayLiteralExpression(); + case SyntaxKind.OpenBraceToken: + return parseObjectLiteralExpression(); + case SyntaxKind.ClassKeyword: + return parseClassExpression(); + case SyntaxKind.FunctionKeyword: + return parseFunctionExpression(); + case SyntaxKind.NewKeyword: + return parseNewExpression(); + case SyntaxKind.SlashToken: + case SyntaxKind.SlashEqualsToken: + if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) { + return parseLiteralNode(); + } + break; + case SyntaxKind.TemplateHead: + return parseTemplateExpression(); + } + + return parseIdentifier(Diagnostics.Expression_expected); + } + + function parseParenthesizedExpression(): ParenthesizedExpression { + let node = createNode(SyntaxKind.ParenthesizedExpression); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + return finishNode(node); + } + + function parseSpreadElement(): Expression { + let node = createNode(SyntaxKind.SpreadElementExpression); + parseExpected(SyntaxKind.DotDotDotToken); + node.expression = parseAssignmentExpressionOrHigher(); + return finishNode(node); + } + + function parseArgumentOrArrayLiteralElement(): Expression { + return token === SyntaxKind.DotDotDotToken ? parseSpreadElement() : + token === SyntaxKind.CommaToken ? createNode(SyntaxKind.OmittedExpression) : + parseAssignmentExpressionOrHigher(); + } + + function parseArgumentExpression(): Expression { + return doOutsideOfContext(disallowInAndDecoratorContext, parseArgumentOrArrayLiteralElement); + } + + function parseArrayLiteralExpression(): ArrayLiteralExpression { + let node = createNode(SyntaxKind.ArrayLiteralExpression); + parseExpected(SyntaxKind.OpenBracketToken); + if (scanner.hasPrecedingLineBreak()) node.flags |= NodeFlags.MultiLine; + node.elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement); + parseExpected(SyntaxKind.CloseBracketToken); + return finishNode(node); + } + + function tryParseAccessorDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): AccessorDeclaration { + if (parseContextualModifier(SyntaxKind.GetKeyword)) { + return parseAccessorDeclaration(SyntaxKind.GetAccessor, fullStart, decorators, modifiers); + } + else if (parseContextualModifier(SyntaxKind.SetKeyword)) { + return parseAccessorDeclaration(SyntaxKind.SetAccessor, fullStart, decorators, modifiers); + } + + return undefined; + } + + function parseObjectLiteralElement(): ObjectLiteralElement { + let fullStart = scanner.getStartPos(); + let decorators = parseDecorators(); + let modifiers = parseModifiers(); + + let accessor = tryParseAccessorDeclaration(fullStart, decorators, modifiers); + if (accessor) { + return accessor; + } + + let asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); + let tokenIsIdentifier = isIdentifier(); + let nameToken = token; + let propertyName = parsePropertyName(); + + // Disallowing of optional property assignments happens in the grammar checker. + let questionToken = parseOptionalToken(SyntaxKind.QuestionToken); + if (asteriskToken || token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { + return parseMethodDeclaration(fullStart, decorators, modifiers, asteriskToken, propertyName, questionToken); + } + + // Parse to check if it is short-hand property assignment or normal property assignment + if ((token === SyntaxKind.CommaToken || token === SyntaxKind.CloseBraceToken) && tokenIsIdentifier) { + let shorthandDeclaration = createNode(SyntaxKind.ShorthandPropertyAssignment, fullStart); + shorthandDeclaration.name = propertyName; + shorthandDeclaration.questionToken = questionToken; + return finishNode(shorthandDeclaration); + } + else { + let propertyAssignment = createNode(SyntaxKind.PropertyAssignment, fullStart); + propertyAssignment.name = propertyName; + propertyAssignment.questionToken = questionToken; + parseExpected(SyntaxKind.ColonToken); + propertyAssignment.initializer = allowInAnd(parseAssignmentExpressionOrHigher); + return finishNode(propertyAssignment); + } + } + + function parseObjectLiteralExpression(): ObjectLiteralExpression { + let node = createNode(SyntaxKind.ObjectLiteralExpression); + parseExpected(SyntaxKind.OpenBraceToken); + if (scanner.hasPrecedingLineBreak()) { + node.flags |= NodeFlags.MultiLine; + } + + node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimeter:*/ true); + parseExpected(SyntaxKind.CloseBraceToken); + return finishNode(node); + } + + function parseFunctionExpression(): FunctionExpression { + // GeneratorExpression : + // function * BindingIdentifier[Yield]opt (FormalParameters[Yield, GeneratorParameter]) { GeneratorBody[Yield] } + // FunctionExpression: + // function BindingIdentifieropt(FormalParameters) { FunctionBody } + let saveDecoratorContext = inDecoratorContext(); + if (saveDecoratorContext) { + setDecoratorContext(false); + } + let node = createNode(SyntaxKind.FunctionExpression); + parseExpected(SyntaxKind.FunctionKeyword); + node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); + node.name = node.asteriskToken ? doInYieldContext(parseOptionalIdentifier) : parseOptionalIdentifier(); + fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ !!node.asteriskToken, /*requireCompleteParameterList:*/ false, node); + node.body = parseFunctionBlock(/*allowYield:*/ !!node.asteriskToken, /* ignoreMissingOpenBrace */ false); + if (saveDecoratorContext) { + setDecoratorContext(true); + } + return finishNode(node); + } + + function parseOptionalIdentifier() { + return isIdentifier() ? parseIdentifier() : undefined; + } + + function parseNewExpression(): NewExpression { + let node = createNode(SyntaxKind.NewExpression); + parseExpected(SyntaxKind.NewKeyword); + node.expression = parseMemberExpressionOrHigher(); + node.typeArguments = tryParse(parseTypeArgumentsInExpression); + if (node.typeArguments || token === SyntaxKind.OpenParenToken) { + node.arguments = parseArgumentList(); + } + + return finishNode(node); + } + + // STATEMENTS + function parseBlock(ignoreMissingOpenBrace: boolean, checkForStrictMode: boolean, diagnosticMessage?: DiagnosticMessage): Block { + let node = createNode(SyntaxKind.Block); + if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) { + node.statements = parseList(ParsingContext.BlockStatements, checkForStrictMode, parseStatement); + parseExpected(SyntaxKind.CloseBraceToken); + } + else { + node.statements = createMissingList(); + } + return finishNode(node); + } + + function parseFunctionBlock(allowYield: boolean, ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block { + let savedYieldContext = inYieldContext(); + setYieldContext(allowYield); + + // We may be in a [Decorator] context when parsing a function expression or + // arrow function. The body of the function is not in [Decorator] context. + let saveDecoratorContext = inDecoratorContext(); + if (saveDecoratorContext) { + setDecoratorContext(false); + } + + let block = parseBlock(ignoreMissingOpenBrace, /*checkForStrictMode*/ true, diagnosticMessage); + + if (saveDecoratorContext) { + setDecoratorContext(true); + } + + setYieldContext(savedYieldContext); + + return block; + } + + function parseEmptyStatement(): Statement { + let node = createNode(SyntaxKind.EmptyStatement); + parseExpected(SyntaxKind.SemicolonToken); + return finishNode(node); + } + + function parseIfStatement(): IfStatement { + let node = createNode(SyntaxKind.IfStatement); + parseExpected(SyntaxKind.IfKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + node.thenStatement = parseStatement(); + node.elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined; + return finishNode(node); + } + + function parseDoStatement(): DoStatement { + let node = createNode(SyntaxKind.DoStatement); + parseExpected(SyntaxKind.DoKeyword); + node.statement = parseStatement(); + parseExpected(SyntaxKind.WhileKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + + // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html + // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in + // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby + // do;while(0)x will have a semicolon inserted before x. + parseOptional(SyntaxKind.SemicolonToken); + return finishNode(node); + } + + function parseWhileStatement(): WhileStatement { + let node = createNode(SyntaxKind.WhileStatement); + parseExpected(SyntaxKind.WhileKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + node.statement = parseStatement(); + return finishNode(node); + } + + function parseForOrForInOrForOfStatement(): Statement { + let pos = getNodePos(); + parseExpected(SyntaxKind.ForKeyword); + parseExpected(SyntaxKind.OpenParenToken); + + let initializer: VariableDeclarationList | Expression = undefined; + if (token !== SyntaxKind.SemicolonToken) { + if (token === SyntaxKind.VarKeyword || token === SyntaxKind.LetKeyword || token === SyntaxKind.ConstKeyword) { + initializer = parseVariableDeclarationList(/*inForStatementInitializer:*/ true); + } + else { + initializer = disallowInAnd(parseExpression); + } + } + let forOrForInOrForOfStatement: IterationStatement; + if (parseOptional(SyntaxKind.InKeyword)) { + let forInStatement = createNode(SyntaxKind.ForInStatement, pos); + forInStatement.initializer = initializer; + forInStatement.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + forOrForInOrForOfStatement = forInStatement; + } + else if (parseOptional(SyntaxKind.OfKeyword)) { + let forOfStatement = createNode(SyntaxKind.ForOfStatement, pos); + forOfStatement.initializer = initializer; + forOfStatement.expression = allowInAnd(parseAssignmentExpressionOrHigher); + parseExpected(SyntaxKind.CloseParenToken); + forOrForInOrForOfStatement = forOfStatement; + } else { + let forStatement = createNode(SyntaxKind.ForStatement, pos); + forStatement.initializer = initializer; + parseExpected(SyntaxKind.SemicolonToken); + if (token !== SyntaxKind.SemicolonToken && token !== SyntaxKind.CloseParenToken) { + forStatement.condition = allowInAnd(parseExpression); + } + parseExpected(SyntaxKind.SemicolonToken); + if (token !== SyntaxKind.CloseParenToken) { + forStatement.incrementor = allowInAnd(parseExpression); + } + parseExpected(SyntaxKind.CloseParenToken); + forOrForInOrForOfStatement = forStatement; + } + + forOrForInOrForOfStatement.statement = parseStatement(); + + return finishNode(forOrForInOrForOfStatement); + } + + function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement { + let node = createNode(kind); + + parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword); + if (!canParseSemicolon()) { + node.label = parseIdentifier(); + } + + parseSemicolon(); + return finishNode(node); + } + + function parseReturnStatement(): ReturnStatement { + let node = createNode(SyntaxKind.ReturnStatement); + + parseExpected(SyntaxKind.ReturnKeyword); + if (!canParseSemicolon()) { + node.expression = allowInAnd(parseExpression); + } + + parseSemicolon(); + return finishNode(node); + } + + function parseWithStatement(): WithStatement { + let node = createNode(SyntaxKind.WithStatement); + parseExpected(SyntaxKind.WithKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + node.statement = parseStatement(); + return finishNode(node); + } + + function parseCaseClause(): CaseClause { + let node = createNode(SyntaxKind.CaseClause); + parseExpected(SyntaxKind.CaseKeyword); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.ColonToken); + node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement); + return finishNode(node); + } + + function parseDefaultClause(): DefaultClause { + let node = createNode(SyntaxKind.DefaultClause); + parseExpected(SyntaxKind.DefaultKeyword); + parseExpected(SyntaxKind.ColonToken); + node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement); + return finishNode(node); + } + + function parseCaseOrDefaultClause(): CaseOrDefaultClause { + return token === SyntaxKind.CaseKeyword ? parseCaseClause() : parseDefaultClause(); + } + + function parseSwitchStatement(): SwitchStatement { + let node = createNode(SyntaxKind.SwitchStatement); + parseExpected(SyntaxKind.SwitchKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + let caseBlock = createNode(SyntaxKind.CaseBlock, scanner.getStartPos()); + parseExpected(SyntaxKind.OpenBraceToken); + caseBlock.clauses = parseList(ParsingContext.SwitchClauses, /*checkForStrictMode*/ false, parseCaseOrDefaultClause); + parseExpected(SyntaxKind.CloseBraceToken); + node.caseBlock = finishNode(caseBlock); + return finishNode(node); + } + + function parseThrowStatement(): ThrowStatement { + // ThrowStatement[Yield] : + // throw [no LineTerminator here]Expression[In, ?Yield]; + + // Because of automatic semicolon insertion, we need to report error if this + // throw could be terminated with a semicolon. Note: we can't call 'parseExpression' + // directly as that might consume an expression on the following line. + // We just return 'undefined' in that case. The actual error will be reported in the + // grammar walker. + let node = createNode(SyntaxKind.ThrowStatement); + parseExpected(SyntaxKind.ThrowKeyword); + node.expression = scanner.hasPrecedingLineBreak() ? undefined : allowInAnd(parseExpression); + parseSemicolon(); + return finishNode(node); + } + + // TODO: Review for error recovery + function parseTryStatement(): TryStatement { + let node = createNode(SyntaxKind.TryStatement); + + parseExpected(SyntaxKind.TryKeyword); + node.tryBlock = parseBlock(/*ignoreMissingOpenBrace:*/ false, /*checkForStrictMode*/ false); + node.catchClause = token === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined; + + // If we don't have a catch clause, then we must have a finally clause. Try to parse + // one out no matter what. + if (!node.catchClause || token === SyntaxKind.FinallyKeyword) { + parseExpected(SyntaxKind.FinallyKeyword); + node.finallyBlock = parseBlock(/*ignoreMissingOpenBrace:*/ false, /*checkForStrictMode*/ false); + } + + return finishNode(node); + } + + function parseCatchClause(): CatchClause { + let result = createNode(SyntaxKind.CatchClause); + parseExpected(SyntaxKind.CatchKeyword); + if (parseExpected(SyntaxKind.OpenParenToken)) { + result.variableDeclaration = parseVariableDeclaration(); + } + + parseExpected(SyntaxKind.CloseParenToken); + result.block = parseBlock(/*ignoreMissingOpenBrace:*/ false, /*checkForStrictMode:*/ false); + return finishNode(result); + } + + function parseDebuggerStatement(): Statement { + let node = createNode(SyntaxKind.DebuggerStatement); + parseExpected(SyntaxKind.DebuggerKeyword); + parseSemicolon(); + return finishNode(node); + } + + function parseExpressionOrLabeledStatement(): ExpressionStatement | LabeledStatement { + // Avoiding having to do the lookahead for a labeled statement by just trying to parse + // out an expression, seeing if it is identifier and then seeing if it is followed by + // a colon. + let fullStart = scanner.getStartPos(); + let expression = allowInAnd(parseExpression); + + if (expression.kind === SyntaxKind.Identifier && parseOptional(SyntaxKind.ColonToken)) { + let labeledStatement = createNode(SyntaxKind.LabeledStatement, fullStart); + labeledStatement.label = expression; + labeledStatement.statement = parseStatement(); + return finishNode(labeledStatement); + } + else { + let expressionStatement = createNode(SyntaxKind.ExpressionStatement, fullStart); + expressionStatement.expression = expression; + parseSemicolon(); + return finishNode(expressionStatement); + } + } + + function isStartOfStatement(inErrorRecovery: boolean): boolean { + // Functions, variable statements and classes are allowed as a statement. But as per + // the grammar, they also allow modifiers. So we have to check for those statements + // that might be following modifiers.This ensures that things work properly when + // incrementally parsing as the parser will produce the same FunctionDeclaraiton, + // VariableStatement or ClassDeclaration, if it has the same text regardless of whether + // it is inside a block or not. + if (isModifier(token)) { + let result = lookAhead(parseVariableStatementOrFunctionDeclarationOrClassDeclarationWithDecoratorsOrModifiers); + if (result) { + return true; + } + } + + switch (token) { + case SyntaxKind.SemicolonToken: + // If we're in error recovery, then we don't want to treat ';' as an empty statement. + // The problem is that ';' can show up in far too many contexts, and if we see one + // and assume it's a statement, then we may bail out inappropriately from whatever + // we're parsing. For example, if we have a semicolon in the middle of a class, then + // we really don't want to assume the class is over and we're on a statement in the + // outer module. We just want to consume and move on. + return !inErrorRecovery; + case SyntaxKind.OpenBraceToken: + case SyntaxKind.VarKeyword: + case SyntaxKind.LetKeyword: + case SyntaxKind.FunctionKeyword: + case SyntaxKind.ClassKeyword: + case SyntaxKind.IfKeyword: + case SyntaxKind.DoKeyword: + case SyntaxKind.WhileKeyword: + case SyntaxKind.ForKeyword: + case SyntaxKind.ContinueKeyword: + case SyntaxKind.BreakKeyword: + case SyntaxKind.ReturnKeyword: + case SyntaxKind.WithKeyword: + case SyntaxKind.SwitchKeyword: + case SyntaxKind.ThrowKeyword: + case SyntaxKind.TryKeyword: + case SyntaxKind.DebuggerKeyword: + // 'catch' and 'finally' do not actually indicate that the code is part of a statement, + // however, we say they are here so that we may gracefully parse them and error later. + case SyntaxKind.CatchKeyword: + case SyntaxKind.FinallyKeyword: + return true; + case SyntaxKind.ConstKeyword: + // const keyword can precede enum keyword when defining constant enums + // 'const enum' do not start statement. + // In ES 6 'enum' is a future reserved keyword, so it should not be used as identifier + let isConstEnum = lookAhead(nextTokenIsEnumKeyword); + return !isConstEnum; + case SyntaxKind.InterfaceKeyword: + case SyntaxKind.ModuleKeyword: + case SyntaxKind.EnumKeyword: + case SyntaxKind.TypeKeyword: + // When followed by an identifier, these do not start a statement but might + // instead be following declarations + if (isDeclarationStart()) { + return false; + } + + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.StaticKeyword: + // When followed by an identifier or keyword, these do not start a statement but + // might instead be following type members + if (lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine)) { + return false; + } + default: + return isStartOfExpression(); + } + } + + function nextTokenIsEnumKeyword() { + nextToken(); + return token === SyntaxKind.EnumKeyword + } + + function nextTokenIsIdentifierOrKeywordOnSameLine() { + nextToken(); + return isIdentifierOrKeyword() && !scanner.hasPrecedingLineBreak(); + } + + function parseStatement(): Statement { + switch (token) { + case SyntaxKind.OpenBraceToken: + return parseBlock(/*ignoreMissingOpenBrace:*/ false, /*checkForStrictMode:*/ false); + case SyntaxKind.VarKeyword: + case SyntaxKind.ConstKeyword: + // const here should always be parsed as const declaration because of check in 'isStatement' + return parseVariableStatement(scanner.getStartPos(), /*decorators*/ undefined, /*modifiers:*/ undefined); + case SyntaxKind.FunctionKeyword: + return parseFunctionDeclaration(scanner.getStartPos(), /*decorators*/ undefined, /*modifiers:*/ undefined); + case SyntaxKind.ClassKeyword: + return parseClassDeclaration(scanner.getStartPos(), /*decorators*/ undefined, /*modifiers:*/ undefined); + case SyntaxKind.SemicolonToken: + return parseEmptyStatement(); + case SyntaxKind.IfKeyword: + return parseIfStatement(); + case SyntaxKind.DoKeyword: + return parseDoStatement(); + case SyntaxKind.WhileKeyword: + return parseWhileStatement(); + case SyntaxKind.ForKeyword: + return parseForOrForInOrForOfStatement(); + case SyntaxKind.ContinueKeyword: + return parseBreakOrContinueStatement(SyntaxKind.ContinueStatement); + case SyntaxKind.BreakKeyword: + return parseBreakOrContinueStatement(SyntaxKind.BreakStatement); + case SyntaxKind.ReturnKeyword: + return parseReturnStatement(); + case SyntaxKind.WithKeyword: + return parseWithStatement(); + case SyntaxKind.SwitchKeyword: + return parseSwitchStatement(); + case SyntaxKind.ThrowKeyword: + return parseThrowStatement(); + case SyntaxKind.TryKeyword: + // Include the next two for error recovery. + case SyntaxKind.CatchKeyword: + case SyntaxKind.FinallyKeyword: + return parseTryStatement(); + case SyntaxKind.DebuggerKeyword: + return parseDebuggerStatement(); + case SyntaxKind.LetKeyword: + // If let follows identifier on the same line, it is declaration parse it as variable statement + if (isLetDeclaration()) { + return parseVariableStatement(scanner.getStartPos(), /*decorators*/ undefined, /*modifiers:*/ undefined); + } + // Else parse it like identifier - fall through + default: + // Functions and variable statements are allowed as a statement. But as per + // the grammar, they also allow modifiers. So we have to check for those + // statements that might be following modifiers. This ensures that things + // work properly when incrementally parsing as the parser will produce the + // same FunctionDeclaraiton or VariableStatement if it has the same text + // regardless of whether it is inside a block or not. + // Even though variable statements and function declarations cannot have decorators, + // we parse them here to provide better error recovery. + if (isModifier(token) || token === SyntaxKind.AtToken) { + let result = tryParse(parseVariableStatementOrFunctionDeclarationOrClassDeclarationWithDecoratorsOrModifiers); + if (result) { + return result; + } + } + + return parseExpressionOrLabeledStatement(); + } + } + + function parseVariableStatementOrFunctionDeclarationOrClassDeclarationWithDecoratorsOrModifiers(): FunctionDeclaration | VariableStatement | ClassDeclaration { + let start = scanner.getStartPos(); + let decorators = parseDecorators(); + let modifiers = parseModifiers(); + switch (token) { + case SyntaxKind.ConstKeyword: + let nextTokenIsEnum = lookAhead(nextTokenIsEnumKeyword) + if (nextTokenIsEnum) { + return undefined; + } + return parseVariableStatement(start, decorators, modifiers); + + case SyntaxKind.LetKeyword: + if (!isLetDeclaration()) { + return undefined; + } + return parseVariableStatement(start, decorators, modifiers); + + case SyntaxKind.VarKeyword: + return parseVariableStatement(start, decorators, modifiers); + + case SyntaxKind.FunctionKeyword: + return parseFunctionDeclaration(start, decorators, modifiers); + + case SyntaxKind.ClassKeyword: + return parseClassDeclaration(start, decorators, modifiers); + } + + return undefined; + } + + function parseFunctionBlockOrSemicolon(isGenerator: boolean, diagnosticMessage?: DiagnosticMessage): Block { + if (token !== SyntaxKind.OpenBraceToken && canParseSemicolon()) { + parseSemicolon(); + return; + } + + return parseFunctionBlock(isGenerator, /*ignoreMissingOpenBrace:*/ false, diagnosticMessage); + } + + // DECLARATIONS + + function parseArrayBindingElement(): BindingElement { + if (token === SyntaxKind.CommaToken) { + return createNode(SyntaxKind.OmittedExpression); + } + let node = createNode(SyntaxKind.BindingElement); + node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); + node.name = parseIdentifierOrPattern(); + node.initializer = parseInitializer(/*inParameter*/ false); + return finishNode(node); + } + + function parseObjectBindingElement(): BindingElement { + let node = createNode(SyntaxKind.BindingElement); + // TODO(andersh): Handle computed properties + let tokenIsIdentifier = isIdentifier(); + let propertyName = parsePropertyName(); + if (tokenIsIdentifier && token !== SyntaxKind.ColonToken) { + node.name = propertyName; + } + else { + parseExpected(SyntaxKind.ColonToken); + node.propertyName = propertyName; + node.name = parseIdentifierOrPattern(); + } + node.initializer = parseInitializer(/*inParameter*/ false); + return finishNode(node); + } + + function parseObjectBindingPattern(): BindingPattern { + let node = createNode(SyntaxKind.ObjectBindingPattern); + parseExpected(SyntaxKind.OpenBraceToken); + node.elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement); + parseExpected(SyntaxKind.CloseBraceToken); + return finishNode(node); + } + + function parseArrayBindingPattern(): BindingPattern { + let node = createNode(SyntaxKind.ArrayBindingPattern); + parseExpected(SyntaxKind.OpenBracketToken); + node.elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement); + parseExpected(SyntaxKind.CloseBracketToken); + return finishNode(node); + } + + function isIdentifierOrPattern() { + return token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken || isIdentifier(); + } + + function parseIdentifierOrPattern(): Identifier | BindingPattern { + if (token === SyntaxKind.OpenBracketToken) { + return parseArrayBindingPattern(); + } + if (token === SyntaxKind.OpenBraceToken) { + return parseObjectBindingPattern(); + } + return parseIdentifier(); + } + + function parseVariableDeclaration(): VariableDeclaration { + let node = createNode(SyntaxKind.VariableDeclaration); + node.name = parseIdentifierOrPattern(); + node.type = parseTypeAnnotation(); + if (!isInOrOfKeyword(token)) { + node.initializer = parseInitializer(/*inParameter*/ false); + } + return finishNode(node); + } + + function parseVariableDeclarationList(inForStatementInitializer: boolean): VariableDeclarationList { + let node = createNode(SyntaxKind.VariableDeclarationList); + + switch (token) { + case SyntaxKind.VarKeyword: + break; + case SyntaxKind.LetKeyword: + node.flags |= NodeFlags.Let; + break; + case SyntaxKind.ConstKeyword: + node.flags |= NodeFlags.Const; + break; + default: + Debug.fail(); + } + + nextToken(); + + // The user may have written the following: + // + // for (let of X) { } + // + // In this case, we want to parse an empty declaration list, and then parse 'of' + // as a keyword. The reason this is not automatic is that 'of' is a valid identifier. + // So we need to look ahead to determine if 'of' should be treated as a keyword in + // this context. + // The checker will then give an error that there is an empty declaration list. + if (token === SyntaxKind.OfKeyword && lookAhead(canFollowContextualOfKeyword)) { + node.declarations = createMissingList(); + } + else { + let savedDisallowIn = inDisallowInContext(); + setDisallowInContext(inForStatementInitializer); + + node.declarations = parseDelimitedList(ParsingContext.VariableDeclarations, parseVariableDeclaration); + + setDisallowInContext(savedDisallowIn); + } + + return finishNode(node); + } + + function canFollowContextualOfKeyword(): boolean { + return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken; + } + + function parseVariableStatement(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): VariableStatement { + let node = createNode(SyntaxKind.VariableStatement, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + node.declarationList = parseVariableDeclarationList(/*inForStatementInitializer:*/ false); + parseSemicolon(); + return finishNode(node); + } + + function parseFunctionDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): FunctionDeclaration { + let node = createNode(SyntaxKind.FunctionDeclaration, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(SyntaxKind.FunctionKeyword); + node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); + node.name = node.flags & NodeFlags.Default ? parseOptionalIdentifier() : parseIdentifier(); + fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ !!node.asteriskToken, /*requireCompleteParameterList:*/ false, node); + node.body = parseFunctionBlockOrSemicolon(!!node.asteriskToken, Diagnostics.or_expected); + return finishNode(node); + } + + function parseConstructorDeclaration(pos: number, decorators: NodeArray, modifiers: ModifiersArray): ConstructorDeclaration { + let node = createNode(SyntaxKind.Constructor, pos); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(SyntaxKind.ConstructorKeyword); + fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ false, /*requireCompleteParameterList:*/ false, node); + node.body = parseFunctionBlockOrSemicolon(/*isGenerator:*/ false, Diagnostics.or_expected); + return finishNode(node); + } + + function parseMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, asteriskToken: Node, name: DeclarationName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { + let method = createNode(SyntaxKind.MethodDeclaration, fullStart); + method.decorators = decorators; + setModifiers(method, modifiers); + method.asteriskToken = asteriskToken; + method.name = name; + method.questionToken = questionToken; + fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ !!asteriskToken, /*requireCompleteParameterList:*/ false, method); + method.body = parseFunctionBlockOrSemicolon(!!asteriskToken, diagnosticMessage); + return finishNode(method); + } + + function parsePropertyDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, name: DeclarationName, questionToken: Node): ClassElement { + let property = createNode(SyntaxKind.PropertyDeclaration, fullStart); + property.decorators = decorators; + setModifiers(property, modifiers); + property.name = name; + property.questionToken = questionToken; + property.type = parseTypeAnnotation(); + property.initializer = allowInAnd(parseNonParameterInitializer); + parseSemicolon(); + return finishNode(property); + } + + function parsePropertyOrMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ClassElement { + let asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); + let name = parsePropertyName(); + + // Note: this is not legal as per the grammar. But we allow it in the parser and + // report an error in the grammar checker. + let questionToken = parseOptionalToken(SyntaxKind.QuestionToken); + if (asteriskToken || token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { + return parseMethodDeclaration(fullStart, decorators, modifiers, asteriskToken, name, questionToken, Diagnostics.or_expected); + } + else { + return parsePropertyDeclaration(fullStart, decorators, modifiers, name, questionToken); + } + } + + function parseNonParameterInitializer() { + return parseInitializer(/*inParameter*/ false); + } + + function parseAccessorDeclaration(kind: SyntaxKind, fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): AccessorDeclaration { + let node = createNode(kind, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + node.name = parsePropertyName(); + fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ false, /*requireCompleteParameterList:*/ false, node); + node.body = parseFunctionBlockOrSemicolon(/*isGenerator:*/ false); + return finishNode(node); + } + + function isClassMemberModifier(idToken: SyntaxKind) { + switch (idToken) { + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.StaticKeyword: + return true; + default: + return false; + } + } + + function isClassMemberStart(): boolean { + let idToken: SyntaxKind; + + if (token === SyntaxKind.AtToken) { + return true; + } + + // Eat up all modifiers, but hold on to the last one in case it is actually an identifier. + while (isModifier(token)) { + idToken = token; + // If the idToken is a class modifier (protected, private, public, and static), it is + // certain that we are starting to parse class member. This allows better error recovery + // Example: + // public foo() ... // true + // public @dec blah ... // true; we will then report an error later + // export public ... // true; we will then report an error later + if (isClassMemberModifier(idToken)) { + return true; + } + + nextToken(); + } + + if (token === SyntaxKind.AsteriskToken) { + return true; + } + + // Try to get the first property-like token following all modifiers. + // This can either be an identifier or the 'get' or 'set' keywords. + if (isLiteralPropertyName()) { + idToken = token; + nextToken(); + } + + // Index signatures and computed properties are class members; we can parse. + if (token === SyntaxKind.OpenBracketToken) { + return true; + } + + // If we were able to get any potential identifier... + if (idToken !== undefined) { + // If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse. + if (!isKeyword(idToken) || idToken === SyntaxKind.SetKeyword || idToken === SyntaxKind.GetKeyword) { + return true; + } + + // If it *is* a keyword, but not an accessor, check a little farther along + // to see if it should actually be parsed as a class member. + switch (token) { + case SyntaxKind.OpenParenToken: // Method declaration + case SyntaxKind.LessThanToken: // Generic Method declaration + case SyntaxKind.ColonToken: // Type Annotation for declaration + case SyntaxKind.EqualsToken: // Initializer for declaration + case SyntaxKind.QuestionToken: // Not valid, but permitted so that it gets caught later on. + return true; + default: + // Covers + // - Semicolons (declaration termination) + // - Closing braces (end-of-class, must be declaration) + // - End-of-files (not valid, but permitted so that it gets caught later on) + // - Line-breaks (enabling *automatic semicolon insertion*) + return canParseSemicolon(); + } + } + + return false; + } + + function parseDecorators(): NodeArray { + let decorators: NodeArray; + while (true) { + let decoratorStart = getNodePos(); + if (!parseOptional(SyntaxKind.AtToken)) { + break; + } + + if (!decorators) { + decorators = >[]; + decorators.pos = scanner.getStartPos(); + } + + let decorator = createNode(SyntaxKind.Decorator, decoratorStart); + decorator.expression = doInDecoratorContext(parseLeftHandSideExpressionOrHigher); + decorators.push(finishNode(decorator)); + } + if (decorators) { + decorators.end = getNodeEnd(); + } + return decorators; + } + + function parseModifiers(): ModifiersArray { + let flags = 0; + let modifiers: ModifiersArray; + while (true) { + let modifierStart = scanner.getStartPos(); + let modifierKind = token; + + if (!parseAnyContextualModifier()) { + break; + } + + if (!modifiers) { + modifiers = []; + modifiers.pos = modifierStart; + } + flags |= modifierToFlag(modifierKind); + modifiers.push(finishNode(createNode(modifierKind, modifierStart))); + } + if (modifiers) { + modifiers.flags = flags; + modifiers.end = scanner.getStartPos(); + } + return modifiers; + } + + function parseClassElement(): ClassElement { + if (token === SyntaxKind.SemicolonToken) { + let result = createNode(SyntaxKind.SemicolonClassElement); + nextToken(); + return finishNode(result); + } + + let fullStart = getNodePos(); + let decorators = parseDecorators(); + let modifiers = parseModifiers(); + + let accessor = tryParseAccessorDeclaration(fullStart, decorators, modifiers); + if (accessor) { + return accessor; + } + + if (token === SyntaxKind.ConstructorKeyword) { + return parseConstructorDeclaration(fullStart, decorators, modifiers); + } + + if (isIndexSignature()) { + return parseIndexSignatureDeclaration(fullStart, decorators, modifiers); + } + + // It is very important that we check this *after* checking indexers because + // the [ token can start an index signature or a computed property name + if (isIdentifierOrKeyword() || + token === SyntaxKind.StringLiteral || + token === SyntaxKind.NumericLiteral || + token === SyntaxKind.AsteriskToken || + token === SyntaxKind.OpenBracketToken) { + + return parsePropertyOrMethodDeclaration(fullStart, decorators, modifiers); + } + + if (decorators) { + // treat this as a property declaration with a missing name. + let name = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); + return parsePropertyDeclaration(fullStart, decorators, modifiers, name, /*questionToken*/ undefined); + } + + // 'isClassMemberStart' should have hinted not to attempt parsing. + Debug.fail("Should not have attempted to parse class member declaration."); + } + + function parseClassExpression(): ClassExpression { + return parseClassDeclarationOrExpression( + /*fullStart:*/ scanner.getStartPos(), + /*decorators:*/ undefined, + /*modifiers:*/ undefined, + SyntaxKind.ClassExpression); + } + + function parseClassDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ClassDeclaration { + return parseClassDeclarationOrExpression(fullStart, decorators, modifiers, SyntaxKind.ClassDeclaration); + } + + function parseClassDeclarationOrExpression(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, kind: SyntaxKind): ClassLikeDeclaration { + // In ES6 specification, All parts of a ClassDeclaration or a ClassExpression are strict mode code + let savedStrictModeContext = inStrictModeContext(); + setStrictModeContext(true); + + var node = createNode(kind, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(SyntaxKind.ClassKeyword); + node.name = parseOptionalIdentifier(); + node.typeParameters = parseTypeParameters(); + node.heritageClauses = parseHeritageClauses(/*isClassHeritageClause:*/ true); + + if (parseExpected(SyntaxKind.OpenBraceToken)) { + // ClassTail[Yield,GeneratorParameter] : See 14.5 + // [~GeneratorParameter]ClassHeritage[?Yield]opt { ClassBody[?Yield]opt } + // [+GeneratorParameter] ClassHeritageopt { ClassBodyopt } + + node.members = inGeneratorParameterContext() + ? doOutsideOfYieldContext(parseClassMembers) + : parseClassMembers(); + parseExpected(SyntaxKind.CloseBraceToken); + } + else { + node.members = createMissingList(); + } + + var finishedNode = finishNode(node); + setStrictModeContext(savedStrictModeContext); + return finishedNode; + } + + function parseHeritageClauses(isClassHeritageClause: boolean): NodeArray { + // ClassTail[Yield,GeneratorParameter] : See 14.5 + // [~GeneratorParameter]ClassHeritage[?Yield]opt { ClassBody[?Yield]opt } + // [+GeneratorParameter] ClassHeritageopt { ClassBodyopt } + + if (isHeritageClause()) { + return isClassHeritageClause && inGeneratorParameterContext() + ? doOutsideOfYieldContext(parseHeritageClausesWorker) + : parseHeritageClausesWorker(); + } + + return undefined; + } + + function parseHeritageClausesWorker() { + return parseList(ParsingContext.HeritageClauses, /*checkForStrictMode:*/ false, parseHeritageClause); + } + + function parseHeritageClause() { + if (token === SyntaxKind.ExtendsKeyword || token === SyntaxKind.ImplementsKeyword) { + let node = createNode(SyntaxKind.HeritageClause); + node.token = token; + nextToken(); + node.types = parseDelimitedList(ParsingContext.HeritageClauseElement, parseHeritageClauseElement); + return finishNode(node); + } + + return undefined; + } + + function parseHeritageClauseElement(): HeritageClauseElement { + let node = createNode(SyntaxKind.HeritageClauseElement); + node.expression = parseLeftHandSideExpressionOrHigher(); + if (token === SyntaxKind.LessThanToken) { + node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); + } + + return finishNode(node); + } + + function isHeritageClause(): boolean { + return token === SyntaxKind.ExtendsKeyword || token === SyntaxKind.ImplementsKeyword; + } + + function parseClassMembers() { + return parseList(ParsingContext.ClassMembers, /*checkForStrictMode*/ false, parseClassElement); + } + + function parseInterfaceDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): InterfaceDeclaration { + let node = createNode(SyntaxKind.InterfaceDeclaration, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(SyntaxKind.InterfaceKeyword); + node.name = parseIdentifier(); + node.typeParameters = parseTypeParameters(); + node.heritageClauses = parseHeritageClauses(/*isClassHeritageClause:*/ false); + node.members = parseObjectTypeMembers(); + return finishNode(node); + } + + function parseTypeAliasDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): TypeAliasDeclaration { + let node = createNode(SyntaxKind.TypeAliasDeclaration, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(SyntaxKind.TypeKeyword); + node.name = parseIdentifier(); + parseExpected(SyntaxKind.EqualsToken); + node.type = parseType(); + parseSemicolon(); + return finishNode(node); + } + + // In an ambient declaration, the grammar only allows integer literals as initializers. + // In a non-ambient declaration, the grammar allows uninitialized members only in a + // ConstantEnumMemberSection, which starts at the beginning of an enum declaration + // or any time an integer literal initializer is encountered. + function parseEnumMember(): EnumMember { + let node = createNode(SyntaxKind.EnumMember, scanner.getStartPos()); + node.name = parsePropertyName(); + node.initializer = allowInAnd(parseNonParameterInitializer); + return finishNode(node); + } + + function parseEnumDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): EnumDeclaration { + let node = createNode(SyntaxKind.EnumDeclaration, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + parseExpected(SyntaxKind.EnumKeyword); + node.name = parseIdentifier(); + if (parseExpected(SyntaxKind.OpenBraceToken)) { + node.members = parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember); + parseExpected(SyntaxKind.CloseBraceToken); + } + else { + node.members = createMissingList(); + } + return finishNode(node); + } + + function parseModuleBlock(): ModuleBlock { + let node = createNode(SyntaxKind.ModuleBlock, scanner.getStartPos()); + if (parseExpected(SyntaxKind.OpenBraceToken)) { + node.statements = parseList(ParsingContext.ModuleElements, /*checkForStrictMode*/false, parseModuleElement); + parseExpected(SyntaxKind.CloseBraceToken); + } + else { + node.statements = createMissingList(); + } + return finishNode(node); + } + + function parseInternalModuleTail(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, flags: NodeFlags): ModuleDeclaration { + let node = createNode(SyntaxKind.ModuleDeclaration, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + node.flags |= flags; + node.name = parseIdentifier(); + node.body = parseOptional(SyntaxKind.DotToken) + ? parseInternalModuleTail(getNodePos(), /*decorators*/ undefined, /*modifiers:*/undefined, NodeFlags.Export) + : parseModuleBlock(); + return finishNode(node); + } + + function parseAmbientExternalModuleDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ModuleDeclaration { + let node = createNode(SyntaxKind.ModuleDeclaration, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + node.name = parseLiteralNode(/*internName:*/ true); + node.body = parseModuleBlock(); + return finishNode(node); + } + + function parseModuleDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ModuleDeclaration { + parseExpected(SyntaxKind.ModuleKeyword); + return token === SyntaxKind.StringLiteral + ? parseAmbientExternalModuleDeclaration(fullStart, decorators, modifiers) + : parseInternalModuleTail(fullStart, decorators, modifiers, modifiers ? modifiers.flags : 0); + } + + function isExternalModuleReference() { + return token === SyntaxKind.RequireKeyword && + lookAhead(nextTokenIsOpenParen); + } + + function nextTokenIsOpenParen() { + return nextToken() === SyntaxKind.OpenParenToken; + } + + function nextTokenIsCommaOrFromKeyword() { + nextToken(); + return token === SyntaxKind.CommaToken || + token === SyntaxKind.FromKeyword; + } + + function parseImportDeclarationOrImportEqualsDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ImportEqualsDeclaration | ImportDeclaration { + parseExpected(SyntaxKind.ImportKeyword); + let afterImportPos = scanner.getStartPos(); + + let identifier: Identifier; + if (isIdentifier()) { + identifier = parseIdentifier(); + if (token !== SyntaxKind.CommaToken && token !== SyntaxKind.FromKeyword) { + // ImportEquals declaration of type: + // import x = require("mod"); or + // import x = M.x; + let importEqualsDeclaration = createNode(SyntaxKind.ImportEqualsDeclaration, fullStart); + importEqualsDeclaration.decorators = decorators; + setModifiers(importEqualsDeclaration, modifiers); + importEqualsDeclaration.name = identifier; + parseExpected(SyntaxKind.EqualsToken); + importEqualsDeclaration.moduleReference = parseModuleReference(); + parseSemicolon(); + return finishNode(importEqualsDeclaration); + } + } + + // Import statement + let importDeclaration = createNode(SyntaxKind.ImportDeclaration, fullStart); + importDeclaration.decorators = decorators; + setModifiers(importDeclaration, modifiers); + + // ImportDeclaration: + // import ImportClause from ModuleSpecifier ; + // import ModuleSpecifier; + if (identifier || // import id + token === SyntaxKind.AsteriskToken || // import * + token === SyntaxKind.OpenBraceToken) { // import { + importDeclaration.importClause = parseImportClause(identifier, afterImportPos); + parseExpected(SyntaxKind.FromKeyword); + } + + importDeclaration.moduleSpecifier = parseModuleSpecifier(); + parseSemicolon(); + return finishNode(importDeclaration); + } + + function parseImportClause(identifier: Identifier, fullStart: number) { + //ImportClause: + // ImportedDefaultBinding + // NameSpaceImport + // NamedImports + // ImportedDefaultBinding, NameSpaceImport + // ImportedDefaultBinding, NamedImports + + let importClause = createNode(SyntaxKind.ImportClause, fullStart); + if (identifier) { + // ImportedDefaultBinding: + // ImportedBinding + importClause.name = identifier; + } + + // If there was no default import or if there is comma token after default import + // parse namespace or named imports + if (!importClause.name || + parseOptional(SyntaxKind.CommaToken)) { + importClause.namedBindings = token === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports); + } + + return finishNode(importClause); + } + + function parseModuleReference() { + return isExternalModuleReference() + ? parseExternalModuleReference() + : parseEntityName(/*allowReservedWords*/ false); + } + + function parseExternalModuleReference() { + let node = createNode(SyntaxKind.ExternalModuleReference); + parseExpected(SyntaxKind.RequireKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = parseModuleSpecifier(); + parseExpected(SyntaxKind.CloseParenToken); + return finishNode(node); + } + + function parseModuleSpecifier(): Expression { + // We allow arbitrary expressions here, even though the grammar only allows string + // literals. We check to ensure that it is only a string literal later in the grammar + // walker. + let result = parseExpression(); + // Ensure the string being required is in our 'identifier' table. This will ensure + // that features like 'find refs' will look inside this file when search for its name. + if (result.kind === SyntaxKind.StringLiteral) { + internIdentifier((result).text); + } + return result; + } + + function parseNamespaceImport(): NamespaceImport { + // NameSpaceImport: + // * as ImportedBinding + let namespaceImport = createNode(SyntaxKind.NamespaceImport); + parseExpected(SyntaxKind.AsteriskToken); + parseExpected(SyntaxKind.AsKeyword); + namespaceImport.name = parseIdentifier(); + return finishNode(namespaceImport); + } + + function parseNamedImportsOrExports(kind: SyntaxKind): NamedImportsOrExports { + let node = createNode(kind); + + // NamedImports: + // { } + // { ImportsList } + // { ImportsList, } + + // ImportsList: + // ImportSpecifier + // ImportsList, ImportSpecifier + node.elements = parseBracketedList(ParsingContext.ImportOrExportSpecifiers, + kind === SyntaxKind.NamedImports ? parseImportSpecifier : parseExportSpecifier, + SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken); + return finishNode(node); + } + + function parseExportSpecifier() { + return parseImportOrExportSpecifier(SyntaxKind.ExportSpecifier); + } + + function parseImportSpecifier() { + return parseImportOrExportSpecifier(SyntaxKind.ImportSpecifier); + } + + function parseImportOrExportSpecifier(kind: SyntaxKind): ImportOrExportSpecifier { + let node = createNode(kind); + // ImportSpecifier: + // BindingIdentifier + // IdentifierName as BindingIdentifier + // ExportSpecififer: + // IdentifierName + // IdentifierName as IdentifierName + let checkIdentifierIsKeyword = isKeyword(token) && !isIdentifier(); + let checkIdentifierStart = scanner.getTokenPos(); + let checkIdentifierEnd = scanner.getTextPos(); + let identifierName = parseIdentifierName(); + if (token === SyntaxKind.AsKeyword) { + node.propertyName = identifierName; + parseExpected(SyntaxKind.AsKeyword); + checkIdentifierIsKeyword = isKeyword(token) && !isIdentifier(); + checkIdentifierStart = scanner.getTokenPos(); + checkIdentifierEnd = scanner.getTextPos(); + node.name = parseIdentifierName(); + } + else { + node.name = identifierName; + } + if (kind === SyntaxKind.ImportSpecifier && checkIdentifierIsKeyword) { + // Report error identifier expected + parseErrorAtPosition(checkIdentifierStart, checkIdentifierEnd - checkIdentifierStart, Diagnostics.Identifier_expected); + } + return finishNode(node); + } + + function parseExportDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ExportDeclaration { + let node = createNode(SyntaxKind.ExportDeclaration, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + if (parseOptional(SyntaxKind.AsteriskToken)) { + parseExpected(SyntaxKind.FromKeyword); + node.moduleSpecifier = parseModuleSpecifier(); + } + else { + node.exportClause = parseNamedImportsOrExports(SyntaxKind.NamedExports); + if (parseOptional(SyntaxKind.FromKeyword)) { + node.moduleSpecifier = parseModuleSpecifier(); + } + } + parseSemicolon(); + return finishNode(node); + } + + function parseExportAssignment(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ExportAssignment { + let node = createNode(SyntaxKind.ExportAssignment, fullStart); + node.decorators = decorators; + setModifiers(node, modifiers); + if (parseOptional(SyntaxKind.EqualsToken)) { + node.isExportEquals = true; + } + else { + parseExpected(SyntaxKind.DefaultKeyword); + } + node.expression = parseAssignmentExpressionOrHigher(); + parseSemicolon(); + return finishNode(node); + } + + function isLetDeclaration() { + // It is let declaration if in strict mode or next token is identifier\open bracket\open curly on same line. + // otherwise it needs to be treated like identifier + return inStrictModeContext() || lookAhead(nextTokenIsIdentifierOrStartOfDestructuringOnTheSameLine); + } + + function isDeclarationStart(followsModifier?: boolean): boolean { + switch (token) { + case SyntaxKind.VarKeyword: + case SyntaxKind.ConstKeyword: + case SyntaxKind.FunctionKeyword: + return true; + case SyntaxKind.LetKeyword: + return isLetDeclaration(); + case SyntaxKind.ClassKeyword: + case SyntaxKind.InterfaceKeyword: + case SyntaxKind.EnumKeyword: + case SyntaxKind.TypeKeyword: + // Not true keywords so ensure an identifier follows + return lookAhead(nextTokenIsIdentifierOrKeyword); + case SyntaxKind.ImportKeyword: + // Not true keywords so ensure an identifier follows or is string literal or asterisk or open brace + return lookAhead(nextTokenCanFollowImportKeyword); + case SyntaxKind.ModuleKeyword: + // Not a true keyword so ensure an identifier or string literal follows + return lookAhead(nextTokenIsIdentifierOrKeywordOrStringLiteral); + case SyntaxKind.ExportKeyword: + // Check for export assignment or modifier on source element + return lookAhead(nextTokenCanFollowExportKeyword); + case SyntaxKind.DeclareKeyword: + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.StaticKeyword: + // Check for modifier on source element + return lookAhead(nextTokenIsDeclarationStart); + case SyntaxKind.AtToken: + // a lookahead here is too costly, and decorators are only valid on a declaration. + // We will assume we are parsing a declaration here and report an error later + return !followsModifier; + } + } + + function isIdentifierOrKeyword() { + return token >= SyntaxKind.Identifier; + } + + function nextTokenIsIdentifierOrKeyword() { + nextToken(); + return isIdentifierOrKeyword(); + } + + function nextTokenIsIdentifierOrKeywordOrStringLiteral() { + nextToken(); + return isIdentifierOrKeyword() || token === SyntaxKind.StringLiteral; + } + + function nextTokenCanFollowImportKeyword() { + nextToken(); + return isIdentifierOrKeyword() || token === SyntaxKind.StringLiteral || + token === SyntaxKind.AsteriskToken || token === SyntaxKind.OpenBraceToken; + } + + function nextTokenCanFollowExportKeyword() { + nextToken(); + return token === SyntaxKind.EqualsToken || token === SyntaxKind.AsteriskToken || + token === SyntaxKind.OpenBraceToken || token === SyntaxKind.DefaultKeyword || isDeclarationStart(/*followsModifier*/ true); + } + + function nextTokenIsDeclarationStart() { + nextToken(); + return isDeclarationStart(/*followsModifier*/ true); + } + + function nextTokenIsAsKeyword() { + return nextToken() === SyntaxKind.AsKeyword; + } + + function parseDeclaration(): ModuleElement { + let fullStart = getNodePos(); + let decorators = parseDecorators(); + let modifiers = parseModifiers(); + if (token === SyntaxKind.ExportKeyword) { + nextToken(); + if (token === SyntaxKind.DefaultKeyword || token === SyntaxKind.EqualsToken) { + return parseExportAssignment(fullStart, decorators, modifiers); + } + if (token === SyntaxKind.AsteriskToken || token === SyntaxKind.OpenBraceToken) { + return parseExportDeclaration(fullStart, decorators, modifiers); + } + } + + switch (token) { + case SyntaxKind.VarKeyword: + case SyntaxKind.LetKeyword: + case SyntaxKind.ConstKeyword: + return parseVariableStatement(fullStart, decorators, modifiers); + case SyntaxKind.FunctionKeyword: + return parseFunctionDeclaration(fullStart, decorators, modifiers); + case SyntaxKind.ClassKeyword: + return parseClassDeclaration(fullStart, decorators, modifiers); + case SyntaxKind.InterfaceKeyword: + return parseInterfaceDeclaration(fullStart, decorators, modifiers); + case SyntaxKind.TypeKeyword: + return parseTypeAliasDeclaration(fullStart, decorators, modifiers); + case SyntaxKind.EnumKeyword: + return parseEnumDeclaration(fullStart, decorators, modifiers); + case SyntaxKind.ModuleKeyword: + return parseModuleDeclaration(fullStart, decorators, modifiers); + case SyntaxKind.ImportKeyword: + return parseImportDeclarationOrImportEqualsDeclaration(fullStart, decorators, modifiers); + default: + if (decorators) { + // We reached this point because we encountered an AtToken and assumed a declaration would + // follow. For recovery and error reporting purposes, return an incomplete declaration. + let node = createMissingNode(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); + node.pos = fullStart; + node.decorators = decorators; + setModifiers(node, modifiers); + return finishNode(node); + } + Debug.fail("Mismatch between isDeclarationStart and parseDeclaration"); + } + } + + function isSourceElement(inErrorRecovery: boolean): boolean { + return isDeclarationStart() || isStartOfStatement(inErrorRecovery); + } + + function parseSourceElement() { + return parseSourceElementOrModuleElement(); + } + + function parseModuleElement() { + return parseSourceElementOrModuleElement(); + } + + function parseSourceElementOrModuleElement(): ModuleElement { + return isDeclarationStart() + ? parseDeclaration() + : parseStatement(); + } + + function processReferenceComments(sourceFile: SourceFile): void { + let triviaScanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/false, sourceText); + let referencedFiles: FileReference[] = []; + let amdDependencies: { path: string; name: string }[] = []; + let amdModuleName: string; + + // Keep scanning all the leading trivia in the file until we get to something that + // isn't trivia. Any single line comment will be analyzed to see if it is a + // reference comment. + while (true) { + let kind = triviaScanner.scan(); + if (kind === SyntaxKind.WhitespaceTrivia || kind === SyntaxKind.NewLineTrivia || kind === SyntaxKind.MultiLineCommentTrivia) { + continue; + } + if (kind !== SyntaxKind.SingleLineCommentTrivia) { + break; + } + + let range = { pos: triviaScanner.getTokenPos(), end: triviaScanner.getTextPos(), kind: triviaScanner.getToken() }; + + let comment = sourceText.substring(range.pos, range.end); + let referencePathMatchResult = getFileReferenceFromReferencePath(comment, range); + if (referencePathMatchResult) { + let fileReference = referencePathMatchResult.fileReference; + sourceFile.hasNoDefaultLib = referencePathMatchResult.isNoDefaultLib; + let diagnosticMessage = referencePathMatchResult.diagnosticMessage; + if (fileReference) { + referencedFiles.push(fileReference); + } + if (diagnosticMessage) { + sourceFile.parseDiagnostics.push(createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, diagnosticMessage)); + } + } + else { + let amdModuleNameRegEx = /^\/\/\/\s* + node.flags & NodeFlags.Export + || node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind === SyntaxKind.ExternalModuleReference + || node.kind === SyntaxKind.ImportDeclaration + || node.kind === SyntaxKind.ExportAssignment + || node.kind === SyntaxKind.ExportDeclaration + ? node + : undefined); + } + + const enum ParsingContext { + SourceElements, // Elements in source file + ModuleElements, // Elements in module declaration + BlockStatements, // Statements in block + SwitchClauses, // Clauses in switch statement + SwitchClauseStatements, // Statements in switch clause + TypeMembers, // Members in interface or type literal + ClassMembers, // Members in class declaration + EnumMembers, // Members in enum declaration + HeritageClauseElement, // Elements in a heritage clause + VariableDeclarations, // Variable declarations in variable statement + ObjectBindingElements, // Binding elements in object binding list + ArrayBindingElements, // Binding elements in array binding list + ArgumentExpressions, // Expressions in argument list + ObjectLiteralMembers, // Members in object literal + ArrayLiteralMembers, // Members in array literal + Parameters, // Parameters in parameter list + TypeParameters, // Type parameters in type parameter list + TypeArguments, // Type arguments in type argument list + TupleElementTypes, // Element types in tuple element type list + HeritageClauses, // Heritage clauses for a class or interface declaration. + ImportOrExportSpecifiers, // Named import clause's import specifier list + Count // Number of parsing contexts + } + + const enum Tristate { + False, + True, + Unknown + } + } + + module IncrementalParser { + export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile { + aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive); + + checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks); + if (textChangeRangeIsUnchanged(textChangeRange)) { + // if the text didn't change, then we can just return our current source file as-is. + return sourceFile; + } + + if (sourceFile.statements.length === 0) { + // If we don't have any statements in the current source file, then there's no real + // way to incrementally parse. So just do a full parse instead. + return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setNodeParents*/ true) + } + + // Make sure we're not trying to incrementally update a source file more than once. Once + // we do an update the original source file is considered unusbale from that point onwards. + // + // This is because we do incremental parsing in-place. i.e. we take nodes from the old + // tree and give them new positions and parents. From that point on, trusting the old + // tree at all is not possible as far too much of it may violate invariants. + let incrementalSourceFile = sourceFile; + Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed); + incrementalSourceFile.hasBeenIncrementallyParsed = true; + + let oldText = sourceFile.text; + let syntaxCursor = createSyntaxCursor(sourceFile); + + // Make the actual change larger so that we know to reparse anything whose lookahead + // might have intersected the change. + let changeRange = extendToAffectedRange(sourceFile, textChangeRange); + checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks); + + // Ensure that extending the affected range only moved the start of the change range + // earlier in the file. + Debug.assert(changeRange.span.start <= textChangeRange.span.start); + Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span)); + Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange))); + + // The is the amount the nodes after the edit range need to be adjusted. It can be + // positive (if the edit added characters), negative (if the edit deleted characters) + // or zero (if this was a pure overwrite with nothing added/removed). + let delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length; + + // If we added or removed characters during the edit, then we need to go and adjust all + // the nodes after the edit. Those nodes may move forward (if we inserted chars) or they + // may move backward (if we deleted chars). + // + // Doing this helps us out in two ways. First, it means that any nodes/tokens we want + // to reuse are already at the appropriate position in the new text. That way when we + // reuse them, we don't have to figure out if they need to be adjusted. Second, it makes + // it very easy to determine if we can reuse a node. If the node's position is at where + // we are in the text, then we can reuse it. Otherwise we can't. If the node's position + // is ahead of us, then we'll need to rescan tokens. If the node's position is behind + // us, then we'll need to skip it or crumble it as appropriate + // + // We will also adjust the positions of nodes that intersect the change range as well. + // By doing this, we ensure that all the positions in the old tree are consistent, not + // just the positions of nodes entirely before/after the change range. By being + // consistent, we can then easily map from positions to nodes in the old tree easily. + // + // Also, mark any syntax elements that intersect the changed span. We know, up front, + // that we cannot reuse these elements. + updateTokenPositionsAndMarkElements(incrementalSourceFile, + changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks); + + // Now that we've set up our internal incremental state just proceed and parse the + // source file in the normal fashion. When possible the parser will retrieve and + // reuse nodes from the old tree. + // + // Note: passing in 'true' for setNodeParents is very important. When incrementally + // parsing, we will be reusing nodes from the old tree, and placing it into new + // parents. If we don't set the parents now, we'll end up with an observably + // inconsistent tree. Setting the parents on the new tree should be very fast. We + // will immediately bail out of walking any subtrees when we can see that their parents + // are already correct. + let result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /* setParentNode */ true) + + return result; + } + + function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { + if (isArray) { + visitArray(element); + } + else { + visitNode(element); + } + return; + + function visitNode(node: IncrementalNode) { + if (aggressiveChecks && shouldCheckNode(node)) { + var text = oldText.substring(node.pos, node.end); + } + + // Ditch any existing LS children we may have created. This way we can avoid + // moving them forward. + node._children = undefined; + node.pos += delta; + node.end += delta; + + if (aggressiveChecks && shouldCheckNode(node)) { + Debug.assert(text === newText.substring(node.pos, node.end)); + } + + forEachChild(node, visitNode, visitArray); + checkNodePositions(node, aggressiveChecks); + } + + function visitArray(array: IncrementalNodeArray) { + array._children = undefined; + array.pos += delta; + array.end += delta; + + for (let node of array) { + visitNode(node); + } + } + } + + function shouldCheckNode(node: Node) { + switch (node.kind) { + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + case SyntaxKind.Identifier: + return true; + } + + return false; + } + + function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { + Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); + Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); + Debug.assert(element.pos <= element.end); + + // We have an element that intersects the change range in some way. It may have its + // start, or its end (or both) in the changed range. We want to adjust any part + // that intersects such that the final tree is in a consistent state. i.e. all + // chlidren have spans within the span of their parent, and all siblings are ordered + // properly. + + // We may need to update both the 'pos' and the 'end' of the element. + + // If the 'pos' is before the start of the change, then we don't need to touch it. + // If it isn't, then the 'pos' must be inside the change. How we update it will + // depend if delta is positive or negative. If delta is positive then we have + // something like: + // + // -------------------AAA----------------- + // -------------------BBBCCCCCCC----------------- + // + // In this case, we consider any node that started in the change range to still be + // starting at the same position. + // + // however, if the delta is negative, then we instead have something like this: + // + // -------------------XXXYYYYYYY----------------- + // -------------------ZZZ----------------- + // + // In this case, any element that started in the 'X' range will keep its position. + // However any element htat started after that will have their pos adjusted to be + // at the end of the new range. i.e. any node that started in the 'Y' range will + // be adjusted to have their start at the end of the 'Z' range. + // + // The element will keep its position if possible. Or Move backward to the new-end + // if it's in the 'Y' range. + element.pos = Math.min(element.pos, changeRangeNewEnd); + + // If the 'end' is after the change range, then we always adjust it by the delta + // amount. However, if the end is in the change range, then how we adjust it + // will depend on if delta is positive or negative. If delta is positive then we + // have something like: + // + // -------------------AAA----------------- + // -------------------BBBCCCCCCC----------------- + // + // In this case, we consider any node that ended inside the change range to keep its + // end position. + // + // however, if the delta is negative, then we instead have something like this: + // + // -------------------XXXYYYYYYY----------------- + // -------------------ZZZ----------------- + // + // In this case, any element that ended in the 'X' range will keep its position. + // However any element htat ended after that will have their pos adjusted to be + // at the end of the new range. i.e. any node that ended in the 'Y' range will + // be adjusted to have their end at the end of the 'Z' range. + if (element.end >= changeRangeOldEnd) { + // Element ends after the change range. Always adjust the end pos. + element.end += delta; + } + else { + // Element ends in the change range. The element will keep its position if + // possible. Or Move backward to the new-end if it's in the 'Y' range. + element.end = Math.min(element.end, changeRangeNewEnd); + } + + Debug.assert(element.pos <= element.end); + if (element.parent) { + Debug.assert(element.pos >= element.parent.pos); + Debug.assert(element.end <= element.parent.end); + } + } + + function checkNodePositions(node: Node, aggressiveChecks: boolean) { + if (aggressiveChecks) { + let pos = node.pos; + forEachChild(node, child => { + Debug.assert(child.pos >= pos); + pos = child.end; + }); + Debug.assert(pos <= node.end); + } + } + + function updateTokenPositionsAndMarkElements( + sourceFile: IncrementalNode, + changeStart: number, + changeRangeOldEnd: number, + changeRangeNewEnd: number, + delta: number, + oldText: string, + newText: string, + aggressiveChecks: boolean): void { + + visitNode(sourceFile); + return; + + function visitNode(child: IncrementalNode) { + Debug.assert(child.pos <= child.end); + if (child.pos > changeRangeOldEnd) { + // Node is entirely past the change range. We need to move both its pos and + // end, forward or backward appropriately. + moveElementEntirelyPastChangeRange(child, /*isArray:*/ false, delta, oldText, newText, aggressiveChecks); + return; + } + + // Check if the element intersects the change range. If it does, then it is not + // reusable. Also, we'll need to recurse to see what constituent portions we may + // be able to use. + let fullEnd = child.end; + if (fullEnd >= changeStart) { + child.intersectsChange = true; + child._children = undefined; + + // Adjust the pos or end (or both) of the intersecting element accordingly. + adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); + forEachChild(child, visitNode, visitArray); + + checkNodePositions(child, aggressiveChecks); + return; + } + + // Otherwise, the node is entirely before the change range. No need to do anything with it. + Debug.assert(fullEnd < changeStart); + } + + function visitArray(array: IncrementalNodeArray) { + Debug.assert(array.pos <= array.end); + if (array.pos > changeRangeOldEnd) { + // Array is entirely after the change range. We need to move it, and move any of + // its children. + moveElementEntirelyPastChangeRange(array, /*isArray:*/ true, delta, oldText, newText, aggressiveChecks); + return; + } + + // Check if the element intersects the change range. If it does, then it is not + // reusable. Also, we'll need to recurse to see what constituent portions we may + // be able to use. + let fullEnd = array.end; + if (fullEnd >= changeStart) { + array.intersectsChange = true; + array._children = undefined; + + // Adjust the pos or end (or both) of the intersecting array accordingly. + adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); + for (let node of array) { + visitNode(node); + } + return; + } + + // Otherwise, the array is entirely before the change range. No need to do anything with it. + Debug.assert(fullEnd < changeStart); + } + } + + function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange { + // Consider the following code: + // void foo() { /; } + // + // If the text changes with an insertion of / just before the semicolon then we end up with: + // void foo() { //; } + // + // If we were to just use the changeRange a is, then we would not rescan the { token + // (as it does not intersect the actual original change range). Because an edit may + // change the token touching it, we actually need to look back *at least* one token so + // that the prior token sees that change. + let maxLookahead = 1; + + let start = changeRange.span.start; + + // the first iteration aligns us with the change start. subsequent iteration move us to + // the left by maxLookahead tokens. We only need to do this as long as we're not at the + // start of the tree. + for (let i = 0; start > 0 && i <= maxLookahead; i++) { + let nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start); + Debug.assert(nearestNode.pos <= start); + let position = nearestNode.pos; + + start = Math.max(0, position - 1); + } + + let finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span)); + let finalLength = changeRange.newLength + (changeRange.span.start - start); + + return createTextChangeRange(finalSpan, finalLength); + } + + function findNearestNodeStartingBeforeOrAtPosition(sourceFile: SourceFile, position: number): Node { + let bestResult: Node = sourceFile; + let lastNodeEntirelyBeforePosition: Node; + + forEachChild(sourceFile, visit); + + if (lastNodeEntirelyBeforePosition) { + let lastChildOfLastEntireNodeBeforePosition = getLastChild(lastNodeEntirelyBeforePosition); + if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) { + bestResult = lastChildOfLastEntireNodeBeforePosition; + } + } + + return bestResult; + + function getLastChild(node: Node): Node { + while (true) { + let lastChild = getLastChildWorker(node); + if (lastChild) { + node = lastChild; + } + else { + return node; + } + } + } + + function getLastChildWorker(node: Node): Node { + let last: Node = undefined; + forEachChild(node, child => { + if (nodeIsPresent(child)) { + last = child; + } + }); + return last; + } + + function visit(child: Node) { + if (nodeIsMissing(child)) { + // Missing nodes are effectively invisible to us. We never even consider them + // When trying to find the nearest node before us. + return; + } + + // If the child intersects this position, then this node is currently the nearest + // node that starts before the position. + if (child.pos <= position) { + if (child.pos >= bestResult.pos) { + // This node starts before the position, and is closer to the position than + // the previous best node we found. It is now the new best node. + bestResult = child; + } + + // Now, the node may overlap the position, or it may end entirely before the + // position. If it overlaps with the position, then either it, or one of its + // children must be the nearest node before the position. So we can just + // recurse into this child to see if we can find something better. + if (position < child.end) { + // The nearest node is either this child, or one of the children inside + // of it. We've already marked this child as the best so far. Recurse + // in case one of the children is better. + forEachChild(child, visit); + + // Once we look at the children of this node, then there's no need to + // continue any further. + return true; + } + else { + Debug.assert(child.end <= position); + // The child ends entirely before this position. Say you have the following + // (where $ is the position) + // + // ? $ : <...> <...> + // + // We would want to find the nearest preceding node in "complex expr 2". + // To support that, we keep track of this node, and once we're done searching + // for a best node, we recurse down this node to see if we can find a good + // result in it. + // + // This approach allows us to quickly skip over nodes that are entirely + // before the position, while still allowing us to find any nodes in the + // last one that might be what we want. + lastNodeEntirelyBeforePosition = child; + } + } + else { + Debug.assert(child.pos > position); + // We're now at a node that is entirely past the position we're searching for. + // This node (and all following nodes) could never contribute to the result, + // so just skip them by returning 'true' here. + return true; + } + } + } + + function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) { + let oldText = sourceFile.text; + if (textChangeRange) { + Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length); + + if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) { + let oldTextPrefix = oldText.substr(0, textChangeRange.span.start); + let newTextPrefix = newText.substr(0, textChangeRange.span.start); + Debug.assert(oldTextPrefix === newTextPrefix); + + let oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length); + let newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length); + Debug.assert(oldTextSuffix === newTextSuffix); + } + } + } + + interface IncrementalElement extends TextRange { + parent?: Node; + intersectsChange: boolean + length?: number; + _children: Node[]; + } + + export interface IncrementalNode extends Node, IncrementalElement { + hasBeenIncrementallyParsed: boolean + } + + interface IncrementalNodeArray extends NodeArray, IncrementalElement { + length: number + } + + // Allows finding nodes in the source file at a certain position in an efficient manner. + // The implementation takes advantage of the calling pattern it knows the parser will + // make in order to optimize finding nodes as quickly as possible. + export interface SyntaxCursor { + currentNode(position: number): IncrementalNode; + } + + function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor { + let currentArray: NodeArray = sourceFile.statements; + let currentArrayIndex = 0; + + Debug.assert(currentArrayIndex < currentArray.length); + let current = currentArray[currentArrayIndex]; + let lastQueriedPosition = InvalidPosition.Value; + + return { + currentNode(position: number) { + // Only compute the current node if the position is different than the last time + // we were asked. The parser commonly asks for the node at the same position + // twice. Once to know if can read an appropriate list element at a certain point, + // and then to actually read and consume the node. + if (position !== lastQueriedPosition) { + // Much of the time the parser will need the very next node in the array that + // we just returned a node from.So just simply check for that case and move + // forward in the array instead of searching for the node again. + if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) { + currentArrayIndex++; + current = currentArray[currentArrayIndex]; + } + + // If we don't have a node, or the node we have isn't in the right position, + // then try to find a viable node at the position requested. + if (!current || current.pos !== position) { + findHighestListElementThatStartsAtPosition(position); + } + } + + // Cache this query so that we don't do any extra work if the parser calls back + // into us. Note: this is very common as the parser will make pairs of calls like + // 'isListElement -> parseListElement'. If we were unable to find a node when + // called with 'isListElement', we don't want to redo the work when parseListElement + // is called immediately after. + lastQueriedPosition = position; + + // Either we don'd have a node, or we have a node at the position being asked for. + Debug.assert(!current || current.pos === position); + return current; + } + }; + + // Finds the highest element in the tree we can find that starts at the provided position. + // The element must be a direct child of some node list in the tree. This way after we + // return it, we can easily return its next sibling in the list. + function findHighestListElementThatStartsAtPosition(position: number) { + // Clear out any cached state about the last node we found. + currentArray = undefined; + currentArrayIndex = InvalidPosition.Value; + current = undefined; + + // Recurse into the source file to find the highest node at this position. + forEachChild(sourceFile, visitNode, visitArray); + return; + + function visitNode(node: Node) { + if (position >= node.pos && position < node.end) { + // Position was within this node. Keep searching deeper to find the node. + forEachChild(node, visitNode, visitArray); + + // don't procede any futher in the search. + return true; + } + + // position wasn't in this node, have to keep searching. + return false; + } + + function visitArray(array: NodeArray) { + if (position >= array.pos && position < array.end) { + // position was in this array. Search through this array to see if we find a + // viable element. + for (let i = 0, n = array.length; i < n; i++) { + let child = array[i]; + if (child) { + if (child.pos === position) { + // Found the right node. We're done. + currentArray = array; + currentArrayIndex = i; + current = child; + return true; + } + else { + if (child.pos < position && position < child.end) { + // Position in somewhere within this child. Search in it and + // stop searching in this array. + forEachChild(child, visitNode, visitArray); + return true; + } + } + } + } + } + + // position wasn't in this array, have to keep searching. + return false; + } + } + } + + const enum InvalidPosition { + Value = -1 + } + } +} diff --git a/lib/typescript/compiler/program.ts b/lib/typescript/compiler/program.ts new file mode 100644 index 000000000..29baecb7e --- /dev/null +++ b/lib/typescript/compiler/program.ts @@ -0,0 +1,608 @@ +/// +/// + +module ts { + /* @internal */ export let programTime = 0; + /* @internal */ export let emitTime = 0; + /* @internal */ export let ioReadTime = 0; + /* @internal */ export let ioWriteTime = 0; + + /** The version of the TypeScript compiler release */ + export const version = "1.5.0"; + + export function findConfigFile(searchPath: string): string { + var fileName = "tsconfig.json"; + while (true) { + if (sys.fileExists(fileName)) { + return fileName; + } + var parentPath = getDirectoryPath(searchPath); + if (parentPath === searchPath) { + break; + } + searchPath = parentPath; + fileName = "../" + fileName; + } + return undefined; + } + + export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost { + let currentDirectory: string; + let existingDirectories: Map = {}; + + function getCanonicalFileName(fileName: string): string { + // if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form. + // otherwise use toLowerCase as a canonical form. + return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(); + } + + // returned by CScript sys environment + let unsupportedFileEncodingErrorCode = -2147024809; + + function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile { + let text: string; + try { + let start = new Date().getTime(); + text = sys.readFile(fileName, options.charset); + ioReadTime += new Date().getTime() - start; + } + catch (e) { + if (onError) { + onError(e.number === unsupportedFileEncodingErrorCode + ? createCompilerDiagnostic(Diagnostics.Unsupported_file_encoding).messageText + : e.message); + } + text = ""; + } + + return text !== undefined ? createSourceFile(fileName, text, languageVersion, setParentNodes) : undefined; + } + + function directoryExists(directoryPath: string): boolean { + if (hasProperty(existingDirectories, directoryPath)) { + return true; + } + if (sys.directoryExists(directoryPath)) { + existingDirectories[directoryPath] = true; + return true; + } + return false; + } + + function ensureDirectoriesExist(directoryPath: string) { + if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) { + let parentDirectory = getDirectoryPath(directoryPath); + ensureDirectoriesExist(parentDirectory); + sys.createDirectory(directoryPath); + } + } + + function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) { + try { + var start = new Date().getTime(); + ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName))); + sys.writeFile(fileName, data, writeByteOrderMark); + ioWriteTime += new Date().getTime() - start; + } + catch (e) { + if (onError) { + onError(e.message); + } + } + } + + return { + getSourceFile, + getDefaultLibFileName: options => combinePaths(getDirectoryPath(normalizePath(sys.getExecutingFilePath())), getDefaultLibFileName(options)), + writeFile, + getCurrentDirectory: () => currentDirectory || (currentDirectory = sys.getCurrentDirectory()), + useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames, + getCanonicalFileName, + getNewLine: () => sys.newLine + }; + } + + export function getPreEmitDiagnostics(program: Program): Diagnostic[] { + let diagnostics = program.getSyntacticDiagnostics().concat(program.getGlobalDiagnostics()).concat(program.getSemanticDiagnostics()); + + if (program.getCompilerOptions().declaration) { + diagnostics.concat(program.getDeclarationDiagnostics()); + } + + return sortAndDeduplicateDiagnostics(diagnostics); + } + + export function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain, newLine: string): string { + if (typeof messageText === "string") { + return messageText; + } + else { + let diagnosticChain = messageText; + let result = ""; + + let indent = 0; + while (diagnosticChain) { + if (indent) { + result += newLine; + + for (let i = 0; i < indent; i++) { + result += " "; + } + } + result += diagnosticChain.messageText; + indent++; + diagnosticChain = diagnosticChain.next; + } + + return result; + } + } + + export function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost): Program { + let program: Program; + let files: SourceFile[] = []; + let filesByName: Map = {}; + let diagnostics = createDiagnosticCollection(); + let seenNoDefaultLib = options.noLib; + let commonSourceDirectory: string; + let diagnosticsProducingTypeChecker: TypeChecker; + let noDiagnosticsTypeChecker: TypeChecker; + + let start = new Date().getTime(); + + host = host || createCompilerHost(options); + forEach(rootNames, name => processRootFile(name, false)); + if (!seenNoDefaultLib) { + processRootFile(host.getDefaultLibFileName(options), true); + } + verifyCompilerOptions(); + + programTime += new Date().getTime() - start; + + program = { + getSourceFile: getSourceFile, + getSourceFiles: () => files, + getCompilerOptions: () => options, + getSyntacticDiagnostics, + getGlobalDiagnostics, + getSemanticDiagnostics, + getDeclarationDiagnostics, + getTypeChecker, + getDiagnosticsProducingTypeChecker, + getCommonSourceDirectory: () => commonSourceDirectory, + emit, + getCurrentDirectory: () => host.getCurrentDirectory(), + getNodeCount: () => getDiagnosticsProducingTypeChecker().getNodeCount(), + getIdentifierCount: () => getDiagnosticsProducingTypeChecker().getIdentifierCount(), + getSymbolCount: () => getDiagnosticsProducingTypeChecker().getSymbolCount(), + getTypeCount: () => getDiagnosticsProducingTypeChecker().getTypeCount(), + }; + return program; + + function getEmitHost(writeFileCallback?: WriteFileCallback): EmitHost { + return { + getCanonicalFileName: fileName => host.getCanonicalFileName(fileName), + getCommonSourceDirectory: program.getCommonSourceDirectory, + getCompilerOptions: program.getCompilerOptions, + getCurrentDirectory: () => host.getCurrentDirectory(), + getNewLine: () => host.getNewLine(), + getSourceFile: program.getSourceFile, + getSourceFiles: program.getSourceFiles, + writeFile: writeFileCallback || ( + (fileName, data, writeByteOrderMark, onError) => host.writeFile(fileName, data, writeByteOrderMark, onError)), + }; + } + + function getDiagnosticsProducingTypeChecker() { + return diagnosticsProducingTypeChecker || (diagnosticsProducingTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ true)); + } + + function getTypeChecker() { + return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ false)); + } + + function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback): EmitResult { + // If the noEmitOnError flag is set, then check if we have any errors so far. If so, + // immediately bail out. + if (options.noEmitOnError && getPreEmitDiagnostics(this).length > 0) { + return { diagnostics: [], sourceMaps: undefined, emitSkipped: true }; + } + + // Create the emit resolver outside of the "emitTime" tracking code below. That way + // any cost associated with it (like type checking) are appropriate associated with + // the type-checking counter. + let emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile); + + let start = new Date().getTime(); + + let emitResult = emitFiles( + emitResolver, + getEmitHost(writeFileCallback), + sourceFile); + + emitTime += new Date().getTime() - start; + return emitResult; + } + + function getSourceFile(fileName: string) { + fileName = host.getCanonicalFileName(fileName); + return hasProperty(filesByName, fileName) ? filesByName[fileName] : undefined; + } + + function getDiagnosticsHelper(sourceFile: SourceFile, getDiagnostics: (sourceFile: SourceFile) => Diagnostic[]): Diagnostic[] { + if (sourceFile) { + return getDiagnostics(sourceFile); + } + + let allDiagnostics: Diagnostic[] = []; + forEach(program.getSourceFiles(), sourceFile => { + addRange(allDiagnostics, getDiagnostics(sourceFile)); + }); + + return sortAndDeduplicateDiagnostics(allDiagnostics); + } + + function getSyntacticDiagnostics(sourceFile?: SourceFile): Diagnostic[] { + return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile); + } + + function getSemanticDiagnostics(sourceFile?: SourceFile): Diagnostic[] { + return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile); + } + + function getDeclarationDiagnostics(sourceFile?: SourceFile): Diagnostic[] { + return getDiagnosticsHelper(sourceFile, getDeclarationDiagnosticsForFile); + } + + function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] { + return sourceFile.parseDiagnostics; + } + + function getSemanticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] { + let typeChecker = getDiagnosticsProducingTypeChecker(); + + Debug.assert(!!sourceFile.bindDiagnostics); + let bindDiagnostics = sourceFile.bindDiagnostics; + let checkDiagnostics = typeChecker.getDiagnostics(sourceFile); + let programDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName); + + return bindDiagnostics.concat(checkDiagnostics).concat(programDiagnostics); + } + + function getDeclarationDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] { + if (!isDeclarationFile(sourceFile)) { + let resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile); + // Don't actually write any files since we're just getting diagnostics. + var writeFile: WriteFileCallback = () => { }; + return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile); + } + } + + function getGlobalDiagnostics(): Diagnostic[] { + let typeChecker = getDiagnosticsProducingTypeChecker(); + + let allDiagnostics: Diagnostic[] = []; + addRange(allDiagnostics, typeChecker.getGlobalDiagnostics()); + addRange(allDiagnostics, diagnostics.getGlobalDiagnostics()); + + return sortAndDeduplicateDiagnostics(allDiagnostics); + } + + function hasExtension(fileName: string): boolean { + return getBaseFileName(fileName).indexOf(".") >= 0; + } + + function processRootFile(fileName: string, isDefaultLib: boolean) { + processSourceFile(normalizePath(fileName), isDefaultLib); + } + + function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number) { + let start: number; + let length: number; + if (refEnd !== undefined && refPos !== undefined) { + start = refPos; + length = refEnd - refPos; + } + let diagnostic: DiagnosticMessage; + if (hasExtension(fileName)) { + if (!options.allowNonTsExtensions && !fileExtensionIs(host.getCanonicalFileName(fileName), ".ts")) { + diagnostic = Diagnostics.File_0_must_have_extension_ts_or_d_ts; + } + else if (!findSourceFile(fileName, isDefaultLib, refFile, refPos, refEnd)) { + diagnostic = Diagnostics.File_0_not_found; + } + else if (refFile && host.getCanonicalFileName(fileName) === host.getCanonicalFileName(refFile.fileName)) { + diagnostic = Diagnostics.A_file_cannot_have_a_reference_to_itself; + } + } + else { + if (options.allowNonTsExtensions && !findSourceFile(fileName, isDefaultLib, refFile, refPos, refEnd)) { + diagnostic = Diagnostics.File_0_not_found; + } + else if (!findSourceFile(fileName + ".ts", isDefaultLib, refFile, refPos, refEnd) && !findSourceFile(fileName + ".d.ts", isDefaultLib, refFile, refPos, refEnd)) { + diagnostic = Diagnostics.File_0_not_found; + fileName += ".ts"; + } + } + + if (diagnostic) { + if (refFile) { + diagnostics.add(createFileDiagnostic(refFile, start, length, diagnostic, fileName)); + } + else { + diagnostics.add(createCompilerDiagnostic(diagnostic, fileName)); + } + } + } + + // Get source file from normalized fileName + function findSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refStart?: number, refLength?: number): SourceFile { + let canonicalName = host.getCanonicalFileName(fileName); + if (hasProperty(filesByName, canonicalName)) { + // We've already looked for this file, use cached result + return getSourceFileFromCache(fileName, canonicalName, /*useAbsolutePath*/ false); + } + else { + let normalizedAbsolutePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory()); + let canonicalAbsolutePath = host.getCanonicalFileName(normalizedAbsolutePath); + if (hasProperty(filesByName, canonicalAbsolutePath)) { + return getSourceFileFromCache(normalizedAbsolutePath, canonicalAbsolutePath, /*useAbsolutePath*/ true); + } + + // We haven't looked for this file, do so now and cache result + let file = filesByName[canonicalName] = host.getSourceFile(fileName, options.target, hostErrorMessage => { + if (refFile) { + diagnostics.add(createFileDiagnostic(refFile, refStart, refLength, + Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage)); + } + else { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage)); + } + }); + if (file) { + seenNoDefaultLib = seenNoDefaultLib || file.hasNoDefaultLib; + + // Set the source file for normalized absolute path + filesByName[canonicalAbsolutePath] = file; + + if (!options.noResolve) { + let basePath = getDirectoryPath(fileName); + processReferencedFiles(file, basePath); + processImportedModules(file, basePath); + } + if (isDefaultLib) { + files.unshift(file); + } + else { + files.push(file); + } + } + + return file; + } + + function getSourceFileFromCache(fileName: string, canonicalName: string, useAbsolutePath: boolean): SourceFile { + let file = filesByName[canonicalName]; + if (file && host.useCaseSensitiveFileNames()) { + let sourceFileName = useAbsolutePath ? getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory()) : file.fileName; + if (canonicalName !== sourceFileName) { + diagnostics.add(createFileDiagnostic(refFile, refStart, refLength, + Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, fileName, sourceFileName)); + } + } + return file; + } + } + + function processReferencedFiles(file: SourceFile, basePath: string) { + forEach(file.referencedFiles, ref => { + let referencedFileName = isRootedDiskPath(ref.fileName) ? ref.fileName : combinePaths(basePath, ref.fileName); + processSourceFile(normalizePath(referencedFileName), /* isDefaultLib */ false, file, ref.pos, ref.end); + }); + } + + function processImportedModules(file: SourceFile, basePath: string) { + forEach(file.statements, node => { + if (node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration || node.kind === SyntaxKind.ExportDeclaration) { + let moduleNameExpr = getExternalModuleName(node); + if (moduleNameExpr && moduleNameExpr.kind === SyntaxKind.StringLiteral) { + let moduleNameText = (moduleNameExpr).text; + if (moduleNameText) { + let searchPath = basePath; + while (true) { + let searchName = normalizePath(combinePaths(searchPath, moduleNameText)); + if (findModuleSourceFile(searchName + ".ts", moduleNameExpr) || findModuleSourceFile(searchName + ".d.ts", moduleNameExpr)) { + break; + } + let parentPath = getDirectoryPath(searchPath); + if (parentPath === searchPath) { + break; + } + searchPath = parentPath; + } + } + } + } + else if (node.kind === SyntaxKind.ModuleDeclaration && (node).name.kind === SyntaxKind.StringLiteral && (node.flags & NodeFlags.Ambient || isDeclarationFile(file))) { + // TypeScript 1.0 spec (April 2014): 12.1.6 + // An AmbientExternalModuleDeclaration declares an external module. + // This type of declaration is permitted only in the global module. + // The StringLiteral must specify a top - level external module name. + // Relative external module names are not permitted + forEachChild((node).body, node => { + if (isExternalModuleImportEqualsDeclaration(node) && + getExternalModuleImportEqualsDeclarationExpression(node).kind === SyntaxKind.StringLiteral) { + + let nameLiteral = getExternalModuleImportEqualsDeclarationExpression(node); + let moduleName = nameLiteral.text; + if (moduleName) { + // TypeScript 1.0 spec (April 2014): 12.1.6 + // An ExternalImportDeclaration in anAmbientExternalModuleDeclaration may reference other external modules + // only through top - level external module names. Relative external module names are not permitted. + let searchName = normalizePath(combinePaths(basePath, moduleName)); + let tsFile = findModuleSourceFile(searchName + ".ts", nameLiteral); + if (!tsFile) { + findModuleSourceFile(searchName + ".d.ts", nameLiteral); + } + } + } + }); + } + }); + + function findModuleSourceFile(fileName: string, nameLiteral: Expression) { + return findSourceFile(fileName, /* isDefaultLib */ false, file, nameLiteral.pos, nameLiteral.end - nameLiteral.pos); + } + } + + function computeCommonSourceDirectory(sourceFiles: SourceFile[]): string { + let commonPathComponents: string[]; + let currentDirectory = host.getCurrentDirectory(); + forEach(files, sourceFile => { + // Each file contributes into common source file path + if (isDeclarationFile(sourceFile)) { + return; + } + + let sourcePathComponents = getNormalizedPathComponents(sourceFile.fileName, currentDirectory); + sourcePathComponents.pop(); // The base file name is not part of the common directory path + + if (!commonPathComponents) { + // first file + commonPathComponents = sourcePathComponents; + return; + } + + for (let i = 0, n = Math.min(commonPathComponents.length, sourcePathComponents.length); i < n; i++) { + if (commonPathComponents[i] !== sourcePathComponents[i]) { + if (i === 0) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files)); + return; + } + + // New common path found that is 0 -> i-1 + commonPathComponents.length = i; + break; + } + } + + // If the sourcePathComponents was shorter than the commonPathComponents, truncate to the sourcePathComponents + if (sourcePathComponents.length < commonPathComponents.length) { + commonPathComponents.length = sourcePathComponents.length; + } + }); + + return getNormalizedPathFromPathComponents(commonPathComponents); + } + + function checkSourceFilesBelongToPath(sourceFiles: SourceFile[], rootDirectory: string): boolean { + let allFilesBelongToPath = true; + if (sourceFiles) { + let currentDirectory = host.getCurrentDirectory(); + let absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory)); + + for (var sourceFile of sourceFiles) { + if (!isDeclarationFile(sourceFile)) { + let absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory)); + if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, options.rootDir)); + allFilesBelongToPath = false; + } + } + } + } + + return allFilesBelongToPath; + } + + function verifyCompilerOptions() { + if (options.separateCompilation) { + if (options.sourceMap) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_sourceMap_cannot_be_specified_with_option_separateCompilation)); + } + + if (options.declaration) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_declaration_cannot_be_specified_with_option_separateCompilation)); + } + + if (options.noEmitOnError) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_noEmitOnError_cannot_be_specified_with_option_separateCompilation)); + } + + if (options.out) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_out_cannot_be_specified_with_option_separateCompilation)); + } + } + + if (!options.sourceMap && (options.mapRoot || options.sourceRoot)) { + // Error to specify --mapRoot or --sourceRoot without mapSourceFiles + if (options.mapRoot) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option)); + } + if (options.sourceRoot) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option)); + } + return; + } + + let languageVersion = options.target || ScriptTarget.ES3; + + let firstExternalModuleSourceFile = forEach(files, f => isExternalModule(f) ? f : undefined); + if (options.separateCompilation) { + if (!options.module && languageVersion < ScriptTarget.ES6) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_separateCompilation_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES6_or_higher)); + } + + let firstNonExternalModuleSourceFile = forEach(files, f => !isExternalModule(f) && !isDeclarationFile(f) ? f : undefined); + if (firstNonExternalModuleSourceFile) { + let span = getErrorSpanForNode(firstNonExternalModuleSourceFile, firstNonExternalModuleSourceFile); + diagnostics.add(createFileDiagnostic(firstNonExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_non_external_modules_when_the_separateCompilation_flag_is_provided)); + } + } + else if (firstExternalModuleSourceFile && languageVersion < ScriptTarget.ES6 && !options.module) { + // We cannot use createDiagnosticFromNode because nodes do not have parents yet + let span = getErrorSpanForNode(firstExternalModuleSourceFile, firstExternalModuleSourceFile.externalModuleIndicator); + diagnostics.add(createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_external_modules_unless_the_module_flag_is_provided)); + } + + // Cannot specify module gen target when in es6 or above + if (options.module && languageVersion >= ScriptTarget.ES6) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_compile_external_modules_into_amd_commonjs_or_umd_when_targeting_ES6_or_higher)); + } + + // there has to be common source directory if user specified --outdir || --sourceRoot + // if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted + if (options.outDir || // there is --outDir specified + options.sourceRoot || // there is --sourceRoot specified + (options.mapRoot && // there is --mapRoot specified and there would be multiple js files generated + (!options.out || firstExternalModuleSourceFile !== undefined))) { + + if (options.rootDir && checkSourceFilesBelongToPath(files, options.rootDir)) { + // If a rootDir is specified and is valid use it as the commonSourceDirectory + commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, host.getCurrentDirectory()); + } + else { + // Compute the commonSourceDirectory from the input files + commonSourceDirectory = computeCommonSourceDirectory(files); + } + + if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== directorySeparator) { + // Make sure directory path ends with directory separator so this string can directly + // used to replace with "" to get the relative path of the source file and the relative path doesn't + // start with / making it rooted path + commonSourceDirectory += directorySeparator; + } + } + + if (options.noEmit) { + if (options.out || options.outDir) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_noEmit_cannot_be_specified_with_option_out_or_outDir)); + } + + if (options.declaration) { + diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_noEmit_cannot_be_specified_with_option_declaration)); + } + } + } + } +} \ No newline at end of file diff --git a/lib/typescript/compiler/scanner.ts b/lib/typescript/compiler/scanner.ts new file mode 100644 index 000000000..f7a51cd8e --- /dev/null +++ b/lib/typescript/compiler/scanner.ts @@ -0,0 +1,1505 @@ +/// +/// + +module ts { + /* @internal */ + export interface ErrorCallback { + (message: DiagnosticMessage, length: number): void; + } + + /* @internal */ + export interface Scanner { + getStartPos(): number; + getToken(): SyntaxKind; + getTextPos(): number; + getTokenPos(): number; + getTokenText(): string; + getTokenValue(): string; + hasExtendedUnicodeEscape(): boolean; + hasPrecedingLineBreak(): boolean; + isIdentifier(): boolean; + isReservedWord(): boolean; + isUnterminated(): boolean; + reScanGreaterToken(): SyntaxKind; + reScanSlashToken(): SyntaxKind; + reScanTemplateToken(): SyntaxKind; + scan(): SyntaxKind; + // Sets the text for the scanner to scan. An optional subrange starting point and length + // can be provided to have the scanner only scan a portion of the text. + setText(text: string, start?: number, length?: number): void; + setOnError(onError: ErrorCallback): void; + setScriptTarget(scriptTarget: ScriptTarget): void; + setTextPos(textPos: number): void; + // Invokes the provided callback then unconditionally restores the scanner to the state it + // was in immediately prior to invoking the callback. The result of invoking the callback + // is returned from this function. + lookAhead(callback: () => T): T; + + // Invokes the provided callback. If the callback returns something falsy, then it restores + // the scanner to the state it was in immediately prior to invoking the callback. If the + // callback returns something truthy, then the scanner state is not rolled back. The result + // of invoking the callback is returned from this function. + tryScan(callback: () => T): T; + } + + let textToToken: Map = { + "any": SyntaxKind.AnyKeyword, + "as": SyntaxKind.AsKeyword, + "boolean": SyntaxKind.BooleanKeyword, + "break": SyntaxKind.BreakKeyword, + "case": SyntaxKind.CaseKeyword, + "catch": SyntaxKind.CatchKeyword, + "class": SyntaxKind.ClassKeyword, + "continue": SyntaxKind.ContinueKeyword, + "const": SyntaxKind.ConstKeyword, + "constructor": SyntaxKind.ConstructorKeyword, + "debugger": SyntaxKind.DebuggerKeyword, + "declare": SyntaxKind.DeclareKeyword, + "default": SyntaxKind.DefaultKeyword, + "delete": SyntaxKind.DeleteKeyword, + "do": SyntaxKind.DoKeyword, + "else": SyntaxKind.ElseKeyword, + "enum": SyntaxKind.EnumKeyword, + "export": SyntaxKind.ExportKeyword, + "extends": SyntaxKind.ExtendsKeyword, + "false": SyntaxKind.FalseKeyword, + "finally": SyntaxKind.FinallyKeyword, + "for": SyntaxKind.ForKeyword, + "from": SyntaxKind.FromKeyword, + "function": SyntaxKind.FunctionKeyword, + "get": SyntaxKind.GetKeyword, + "if": SyntaxKind.IfKeyword, + "implements": SyntaxKind.ImplementsKeyword, + "import": SyntaxKind.ImportKeyword, + "in": SyntaxKind.InKeyword, + "instanceof": SyntaxKind.InstanceOfKeyword, + "interface": SyntaxKind.InterfaceKeyword, + "let": SyntaxKind.LetKeyword, + "module": SyntaxKind.ModuleKeyword, + "new": SyntaxKind.NewKeyword, + "null": SyntaxKind.NullKeyword, + "number": SyntaxKind.NumberKeyword, + "package": SyntaxKind.PackageKeyword, + "private": SyntaxKind.PrivateKeyword, + "protected": SyntaxKind.ProtectedKeyword, + "public": SyntaxKind.PublicKeyword, + "require": SyntaxKind.RequireKeyword, + "return": SyntaxKind.ReturnKeyword, + "set": SyntaxKind.SetKeyword, + "static": SyntaxKind.StaticKeyword, + "string": SyntaxKind.StringKeyword, + "super": SyntaxKind.SuperKeyword, + "switch": SyntaxKind.SwitchKeyword, + "symbol": SyntaxKind.SymbolKeyword, + "this": SyntaxKind.ThisKeyword, + "throw": SyntaxKind.ThrowKeyword, + "true": SyntaxKind.TrueKeyword, + "try": SyntaxKind.TryKeyword, + "type": SyntaxKind.TypeKeyword, + "typeof": SyntaxKind.TypeOfKeyword, + "var": SyntaxKind.VarKeyword, + "void": SyntaxKind.VoidKeyword, + "while": SyntaxKind.WhileKeyword, + "with": SyntaxKind.WithKeyword, + "yield": SyntaxKind.YieldKeyword, + "of": SyntaxKind.OfKeyword, + "{": SyntaxKind.OpenBraceToken, + "}": SyntaxKind.CloseBraceToken, + "(": SyntaxKind.OpenParenToken, + ")": SyntaxKind.CloseParenToken, + "[": SyntaxKind.OpenBracketToken, + "]": SyntaxKind.CloseBracketToken, + ".": SyntaxKind.DotToken, + "...": SyntaxKind.DotDotDotToken, + ";": SyntaxKind.SemicolonToken, + ",": SyntaxKind.CommaToken, + "<": SyntaxKind.LessThanToken, + ">": SyntaxKind.GreaterThanToken, + "<=": SyntaxKind.LessThanEqualsToken, + ">=": SyntaxKind.GreaterThanEqualsToken, + "==": SyntaxKind.EqualsEqualsToken, + "!=": SyntaxKind.ExclamationEqualsToken, + "===": SyntaxKind.EqualsEqualsEqualsToken, + "!==": SyntaxKind.ExclamationEqualsEqualsToken, + "=>": SyntaxKind.EqualsGreaterThanToken, + "+": SyntaxKind.PlusToken, + "-": SyntaxKind.MinusToken, + "*": SyntaxKind.AsteriskToken, + "/": SyntaxKind.SlashToken, + "%": SyntaxKind.PercentToken, + "++": SyntaxKind.PlusPlusToken, + "--": SyntaxKind.MinusMinusToken, + "<<": SyntaxKind.LessThanLessThanToken, + ">>": SyntaxKind.GreaterThanGreaterThanToken, + ">>>": SyntaxKind.GreaterThanGreaterThanGreaterThanToken, + "&": SyntaxKind.AmpersandToken, + "|": SyntaxKind.BarToken, + "^": SyntaxKind.CaretToken, + "!": SyntaxKind.ExclamationToken, + "~": SyntaxKind.TildeToken, + "&&": SyntaxKind.AmpersandAmpersandToken, + "||": SyntaxKind.BarBarToken, + "?": SyntaxKind.QuestionToken, + ":": SyntaxKind.ColonToken, + "=": SyntaxKind.EqualsToken, + "+=": SyntaxKind.PlusEqualsToken, + "-=": SyntaxKind.MinusEqualsToken, + "*=": SyntaxKind.AsteriskEqualsToken, + "/=": SyntaxKind.SlashEqualsToken, + "%=": SyntaxKind.PercentEqualsToken, + "<<=": SyntaxKind.LessThanLessThanEqualsToken, + ">>=": SyntaxKind.GreaterThanGreaterThanEqualsToken, + ">>>=": SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken, + "&=": SyntaxKind.AmpersandEqualsToken, + "|=": SyntaxKind.BarEqualsToken, + "^=": SyntaxKind.CaretEqualsToken, + "@": SyntaxKind.AtToken, + }; + + /* + As per ECMAScript Language Specification 3th Edition, Section 7.6: Identifiers + IdentifierStart :: + Can contain Unicode 3.0.0 categories: + Uppercase letter (Lu), + Lowercase letter (Ll), + Titlecase letter (Lt), + Modifier letter (Lm), + Other letter (Lo), or + Letter number (Nl). + IdentifierPart :: = + Can contain IdentifierStart + Unicode 3.0.0 categories: + Non-spacing mark (Mn), + Combining spacing mark (Mc), + Decimal number (Nd), or + Connector punctuation (Pc). + + Codepoint ranges for ES3 Identifiers are extracted from the Unicode 3.0.0 specification at: + http://www.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.txt + */ + let unicodeES3IdentifierStart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1569, 1594, 1600, 1610, 1649, 1747, 1749, 1749, 1765, 1766, 1786, 1788, 1808, 1808, 1810, 1836, 1920, 1957, 2309, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2784, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3294, 3294, 3296, 3297, 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3424, 3425, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, 3840, 3840, 3904, 3911, 3913, 3946, 3976, 3979, 4096, 4129, 4131, 4135, 4137, 4138, 4176, 4181, 4256, 4293, 4304, 4342, 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6067, 6176, 6263, 6272, 6312, 7680, 7835, 7840, 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8319, 8319, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12346, 12353, 12436, 12445, 12446, 12449, 12538, 12540, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65138, 65140, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; + let unicodeES3IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 768, 846, 864, 866, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, 1155, 1158, 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1441, 1443, 1465, 1467, 1469, 1471, 1471, 1473, 1474, 1476, 1476, 1488, 1514, 1520, 1522, 1569, 1594, 1600, 1621, 1632, 1641, 1648, 1747, 1749, 1756, 1759, 1768, 1770, 1773, 1776, 1788, 1808, 1836, 1840, 1866, 1920, 1968, 2305, 2307, 2309, 2361, 2364, 2381, 2384, 2388, 2392, 2403, 2406, 2415, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2492, 2494, 2500, 2503, 2504, 2507, 2509, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2562, 2562, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2649, 2652, 2654, 2654, 2662, 2676, 2689, 2691, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2784, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, 2873, 2876, 2883, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2913, 2918, 2927, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3031, 3031, 3047, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3134, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3168, 3169, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3262, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3297, 3302, 3311, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3390, 3395, 3398, 3400, 3402, 3405, 3415, 3415, 3424, 3425, 3430, 3439, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3805, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3946, 3953, 3972, 3974, 3979, 3984, 3991, 3993, 4028, 4038, 4038, 4096, 4129, 4131, 4135, 4137, 4138, 4140, 4146, 4150, 4153, 4160, 4169, 4176, 4185, 4256, 4293, 4304, 4342, 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 4969, 4977, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6099, 6112, 6121, 6160, 6169, 6176, 6263, 6272, 6313, 7680, 7835, 7840, 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8255, 8256, 8319, 8319, 8400, 8412, 8417, 8417, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12346, 12353, 12436, 12441, 12442, 12445, 12446, 12449, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65056, 65059, 65075, 65076, 65101, 65103, 65136, 65138, 65140, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65381, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; + + /* + As per ECMAScript Language Specification 5th Edition, Section 7.6: ISyntaxToken Names and Identifiers + IdentifierStart :: + Can contain Unicode 6.2 categories: + Uppercase letter (Lu), + Lowercase letter (Ll), + Titlecase letter (Lt), + Modifier letter (Lm), + Other letter (Lo), or + Letter number (Nl). + IdentifierPart :: + Can contain IdentifierStart + Unicode 6.2 categories: + Non-spacing mark (Mn), + Combining spacing mark (Mc), + Decimal number (Nd), + Connector punctuation (Pc), + , or + . + + Codepoint ranges for ES5 Identifiers are extracted from the Unicode 6.2 specification at: + http://www.unicode.org/Public/6.2.0/ucd/UnicodeData.txt + */ + let unicodeES5IdentifierStart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2208, 2208, 2210, 2220, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, 7413, 7414, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; + let unicodeES5IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1520, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2048, 2093, 2112, 2139, 2208, 2208, 2210, 2220, 2276, 2302, 2304, 2403, 2406, 2415, 2417, 2423, 2425, 2431, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3161, 3168, 3171, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3299, 3302, 3311, 3313, 3314, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3396, 3398, 3400, 3402, 3406, 3415, 3415, 3424, 3427, 3430, 3439, 3450, 3455, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5908, 5920, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6160, 6169, 6176, 6263, 6272, 6314, 6320, 6389, 6400, 6428, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6617, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6912, 6987, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7376, 7378, 7380, 7414, 7424, 7654, 7676, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8204, 8205, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 11823, 11823, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12442, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42647, 42655, 42737, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43047, 43072, 43123, 43136, 43204, 43216, 43225, 43232, 43255, 43259, 43259, 43264, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43643, 43648, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65062, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; + + function lookupInUnicodeMap(code: number, map: number[]): boolean { + // Bail out quickly if it couldn't possibly be in the map. + if (code < map[0]) { + return false; + } + + // Perform binary search in one of the Unicode range maps + let lo: number = 0; + let hi: number = map.length; + let mid: number; + + while (lo + 1 < hi) { + mid = lo + (hi - lo) / 2; + // mid has to be even to catch a range's beginning + mid -= mid % 2; + if (map[mid] <= code && code <= map[mid + 1]) { + return true; + } + + if (code < map[mid]) { + hi = mid; + } + else { + lo = mid + 2; + } + } + + return false; + } + + /* @internal */ export function isUnicodeIdentifierStart(code: number, languageVersion: ScriptTarget) { + return languageVersion >= ScriptTarget.ES5 ? + lookupInUnicodeMap(code, unicodeES5IdentifierStart) : + lookupInUnicodeMap(code, unicodeES3IdentifierStart); + } + + function isUnicodeIdentifierPart(code: number, languageVersion: ScriptTarget) { + return languageVersion >= ScriptTarget.ES5 ? + lookupInUnicodeMap(code, unicodeES5IdentifierPart) : + lookupInUnicodeMap(code, unicodeES3IdentifierPart); + } + + function makeReverseMap(source: Map): string[] { + let result: string[] = []; + for (let name in source) { + if (source.hasOwnProperty(name)) { + result[source[name]] = name; + } + } + return result; + } + + let tokenStrings = makeReverseMap(textToToken); + + export function tokenToString(t: SyntaxKind): string { + return tokenStrings[t]; + } + + /* @internal */ + export function stringToToken(s: string): SyntaxKind { + return textToToken[s]; + } + + /* @internal */ + export function computeLineStarts(text: string): number[] { + let result: number[] = new Array(); + let pos = 0; + let lineStart = 0; + while (pos < text.length) { + let ch = text.charCodeAt(pos++); + switch (ch) { + case CharacterCodes.carriageReturn: + if (text.charCodeAt(pos) === CharacterCodes.lineFeed) { + pos++; + } + case CharacterCodes.lineFeed: + result.push(lineStart); + lineStart = pos; + break; + default: + if (ch > CharacterCodes.maxAsciiCharacter && isLineBreak(ch)) { + result.push(lineStart); + lineStart = pos; + } + break; + } + } + result.push(lineStart); + return result; + } + + export function getPositionOfLineAndCharacter(sourceFile: SourceFile, line: number, character: number): number { + return computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character); + } + + /* @internal */ + export function computePositionOfLineAndCharacter(lineStarts: number[], line: number, character: number): number { + Debug.assert(line >= 0 && line < lineStarts.length); + return lineStarts[line] + character; + } + + /* @internal */ + export function getLineStarts(sourceFile: SourceFile): number[] { + return sourceFile.lineMap || (sourceFile.lineMap = computeLineStarts(sourceFile.text)); + } + + /* @internal */ + export function computeLineAndCharacterOfPosition(lineStarts: number[], position: number) { + let lineNumber = binarySearch(lineStarts, position); + if (lineNumber < 0) { + // If the actual position was not found, + // the binary search returns the negative value of the next line start + // e.g. if the line starts at [5, 10, 23, 80] and the position requested was 20 + // then the search will return -2 + lineNumber = ~lineNumber - 1; + } + return { + line: lineNumber, + character: position - lineStarts[lineNumber] + }; + } + + export function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter { + return computeLineAndCharacterOfPosition(getLineStarts(sourceFile), position); + } + + let hasOwnProperty = Object.prototype.hasOwnProperty; + + export function isWhiteSpace(ch: number): boolean { + // Note: nextLine is in the Zs space, and should be considered to be a whitespace. + // It is explicitly not a line-break as it isn't in the exact set specified by EcmaScript. + return ch === CharacterCodes.space || + ch === CharacterCodes.tab || + ch === CharacterCodes.verticalTab || + ch === CharacterCodes.formFeed || + ch === CharacterCodes.nonBreakingSpace || + ch === CharacterCodes.nextLine || + ch === CharacterCodes.ogham || + ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace || + ch === CharacterCodes.narrowNoBreakSpace || + ch === CharacterCodes.mathematicalSpace || + ch === CharacterCodes.ideographicSpace || + ch === CharacterCodes.byteOrderMark; + } + + export function isLineBreak(ch: number): boolean { + // ES5 7.3: + // The ECMAScript line terminator characters are listed in Table 3. + // Table 3: Line Terminator Characters + // Code Unit Value Name Formal Name + // \u000A Line Feed + // \u000D Carriage Return + // \u2028 Line separator + // \u2029 Paragraph separator + // Only the characters in Table 3 are treated as line terminators. Other new line or line + // breaking characters are treated as white space but not as line terminators. + + return ch === CharacterCodes.lineFeed || + ch === CharacterCodes.carriageReturn || + ch === CharacterCodes.lineSeparator || + ch === CharacterCodes.paragraphSeparator; + } + + function isDigit(ch: number): boolean { + return ch >= CharacterCodes._0 && ch <= CharacterCodes._9; + } + + /* @internal */ + export function isOctalDigit(ch: number): boolean { + return ch >= CharacterCodes._0 && ch <= CharacterCodes._7; + } + + /* @internal */ + export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean): number { + while (true) { + let ch = text.charCodeAt(pos); + switch (ch) { + case CharacterCodes.carriageReturn: + if (text.charCodeAt(pos + 1) === CharacterCodes.lineFeed) { + pos++; + } + case CharacterCodes.lineFeed: + pos++; + if (stopAfterLineBreak) { + return pos; + } + continue; + case CharacterCodes.tab: + case CharacterCodes.verticalTab: + case CharacterCodes.formFeed: + case CharacterCodes.space: + pos++; + continue; + case CharacterCodes.slash: + if (text.charCodeAt(pos + 1) === CharacterCodes.slash) { + pos += 2; + while (pos < text.length) { + if (isLineBreak(text.charCodeAt(pos))) { + break; + } + pos++; + } + continue; + } + if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) { + pos += 2; + while (pos < text.length) { + if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) { + pos += 2; + break; + } + pos++; + } + continue; + } + break; + + case CharacterCodes.lessThan: + case CharacterCodes.equals: + case CharacterCodes.greaterThan: + if (isConflictMarkerTrivia(text, pos)) { + pos = scanConflictMarkerTrivia(text, pos); + continue; + } + break; + + default: + if (ch > CharacterCodes.maxAsciiCharacter && (isWhiteSpace(ch) || isLineBreak(ch))) { + pos++; + continue; + } + break; + } + return pos; + } + } + + // All conflict markers consist of the same character repeated seven times. If it is + // a <<<<<<< or >>>>>>> marker then it is also followd by a space. + let mergeConflictMarkerLength = "<<<<<<<".length; + + function isConflictMarkerTrivia(text: string, pos: number) { + Debug.assert(pos >= 0); + + // Conflict markers must be at the start of a line. + if (pos === 0 || isLineBreak(text.charCodeAt(pos - 1))) { + let ch = text.charCodeAt(pos); + + if ((pos + mergeConflictMarkerLength) < text.length) { + for (let i = 0, n = mergeConflictMarkerLength; i < n; i++) { + if (text.charCodeAt(pos + i) !== ch) { + return false; + } + } + + return ch === CharacterCodes.equals || + text.charCodeAt(pos + mergeConflictMarkerLength) === CharacterCodes.space; + } + } + + return false; + } + + function scanConflictMarkerTrivia(text: string, pos: number, error?: ErrorCallback) { + if (error) { + error(Diagnostics.Merge_conflict_marker_encountered, mergeConflictMarkerLength); + } + + let ch = text.charCodeAt(pos); + let len = text.length; + + if (ch === CharacterCodes.lessThan || ch === CharacterCodes.greaterThan) { + while (pos < len && !isLineBreak(text.charCodeAt(pos))) { + pos++; + } + } + else { + Debug.assert(ch === CharacterCodes.equals); + // Consume everything from the start of the mid-conlict marker to the start of the next + // end-conflict marker. + while (pos < len) { + let ch = text.charCodeAt(pos); + if (ch === CharacterCodes.greaterThan && isConflictMarkerTrivia(text, pos)) { + break; + } + + pos++; + } + } + + return pos; + } + + // Extract comments from the given source text starting at the given position. If trailing is + // false, whitespace is skipped until the first line break and comments between that location + // and the next token are returned.If trailing is true, comments occurring between the given + // position and the next line break are returned.The return value is an array containing a + // TextRange for each comment. Single-line comment ranges include the beginning '//' characters + // but not the ending line break. Multi - line comment ranges include the beginning '/* and + // ending '*/' characters.The return value is undefined if no comments were found. + function getCommentRanges(text: string, pos: number, trailing: boolean): CommentRange[] { + let result: CommentRange[]; + let collecting = trailing || pos === 0; + while (true) { + let ch = text.charCodeAt(pos); + switch (ch) { + case CharacterCodes.carriageReturn: + if (text.charCodeAt(pos + 1) === CharacterCodes.lineFeed) { + pos++; + } + case CharacterCodes.lineFeed: + pos++; + if (trailing) { + return result; + } + collecting = true; + if (result && result.length) { + result[result.length - 1].hasTrailingNewLine = true; + } + continue; + case CharacterCodes.tab: + case CharacterCodes.verticalTab: + case CharacterCodes.formFeed: + case CharacterCodes.space: + pos++; + continue; + case CharacterCodes.slash: + let nextChar = text.charCodeAt(pos + 1); + let hasTrailingNewLine = false; + if (nextChar === CharacterCodes.slash || nextChar === CharacterCodes.asterisk) { + let kind = nextChar === CharacterCodes.slash ? SyntaxKind.SingleLineCommentTrivia : SyntaxKind.MultiLineCommentTrivia; + let startPos = pos; + pos += 2; + if (nextChar === CharacterCodes.slash) { + while (pos < text.length) { + if (isLineBreak(text.charCodeAt(pos))) { + hasTrailingNewLine = true; + break; + } + pos++; + } + } + else { + while (pos < text.length) { + if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) { + pos += 2; + break; + } + pos++; + } + } + if (collecting) { + if (!result) { + result = []; + } + + result.push({ pos: startPos, end: pos, hasTrailingNewLine, kind }); + } + continue; + } + break; + default: + if (ch > CharacterCodes.maxAsciiCharacter && (isWhiteSpace(ch) || isLineBreak(ch))) { + if (result && result.length && isLineBreak(ch)) { + result[result.length - 1].hasTrailingNewLine = true; + } + pos++; + continue; + } + break; + } + return result; + } + } + + export function getLeadingCommentRanges(text: string, pos: number): CommentRange[] { + return getCommentRanges(text, pos, /*trailing*/ false); + } + + export function getTrailingCommentRanges(text: string, pos: number): CommentRange[] { + return getCommentRanges(text, pos, /*trailing*/ true); + } + + export function isIdentifierStart(ch: number, languageVersion: ScriptTarget): boolean { + return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z || + ch === CharacterCodes.$ || ch === CharacterCodes._ || + ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierStart(ch, languageVersion); + } + + export function isIdentifierPart(ch: number, languageVersion: ScriptTarget): boolean { + return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z || + ch >= CharacterCodes._0 && ch <= CharacterCodes._9 || ch === CharacterCodes.$ || ch === CharacterCodes._ || + ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierPart(ch, languageVersion); + } + + // Creates a scanner over a (possibly unspecified) range of a piece of text. + /* @internal */ + export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean, text?: string, onError?: ErrorCallback, start?: number, length?: number): Scanner { + let pos: number; // Current position (end position of text of current token) + let end: number; // end of text + let startPos: number; // Start position of whitespace before current token + let tokenPos: number; // Start position of text of current token + let token: SyntaxKind; + let tokenValue: string; + let precedingLineBreak: boolean; + let hasExtendedUnicodeEscape: boolean; + let tokenIsUnterminated: boolean; + + setText(text, start, length); + + return { + getStartPos: () => startPos, + getTextPos: () => pos, + getToken: () => token, + getTokenPos: () => tokenPos, + getTokenText: () => text.substring(tokenPos, pos), + getTokenValue: () => tokenValue, + hasExtendedUnicodeEscape: () => hasExtendedUnicodeEscape, + hasPrecedingLineBreak: () => precedingLineBreak, + isIdentifier: () => token === SyntaxKind.Identifier || token > SyntaxKind.LastReservedWord, + isReservedWord: () => token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord, + isUnterminated: () => tokenIsUnterminated, + reScanGreaterToken, + reScanSlashToken, + reScanTemplateToken, + scan, + setText, + setScriptTarget, + setOnError, + setTextPos, + tryScan, + lookAhead, + }; + + function error(message: DiagnosticMessage, length?: number): void { + if (onError) { + onError(message, length || 0); + } + } + + function isIdentifierStart(ch: number): boolean { + return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z || + ch === CharacterCodes.$ || ch === CharacterCodes._ || + ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierStart(ch, languageVersion); + } + + function isIdentifierPart(ch: number): boolean { + return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z || + ch >= CharacterCodes._0 && ch <= CharacterCodes._9 || ch === CharacterCodes.$ || ch === CharacterCodes._ || + ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierPart(ch, languageVersion); + } + + function scanNumber(): number { + let start = pos; + while (isDigit(text.charCodeAt(pos))) pos++; + if (text.charCodeAt(pos) === CharacterCodes.dot) { + pos++; + while (isDigit(text.charCodeAt(pos))) pos++; + } + let end = pos; + if (text.charCodeAt(pos) === CharacterCodes.E || text.charCodeAt(pos) === CharacterCodes.e) { + pos++; + if (text.charCodeAt(pos) === CharacterCodes.plus || text.charCodeAt(pos) === CharacterCodes.minus) pos++; + if (isDigit(text.charCodeAt(pos))) { + pos++; + while (isDigit(text.charCodeAt(pos))) pos++; + end = pos; + } + else { + error(Diagnostics.Digit_expected); + } + } + return +(text.substring(start, end)); + } + + function scanOctalDigits(): number { + let start = pos; + while (isOctalDigit(text.charCodeAt(pos))) { + pos++; + } + return +(text.substring(start, pos)); + } + + /** + * Scans the given number of hexadecimal digits in the text, + * returning -1 if the given number is unavailable. + */ + function scanExactNumberOfHexDigits(count: number): number { + return scanHexDigits(/*minCount*/ count, /*scanAsManyAsPossible*/ false); + } + + /** + * Scans as many hexadecimal digits as are available in the text, + * returning -1 if the given number of digits was unavailable. + */ + function scanMinimumNumberOfHexDigits(count: number): number { + return scanHexDigits(/*minCount*/ count, /*scanAsManyAsPossible*/ true); + } + + function scanHexDigits(minCount: number, scanAsManyAsPossible: boolean): number { + let digits = 0; + let value = 0; + while (digits < minCount || scanAsManyAsPossible) { + let ch = text.charCodeAt(pos); + if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) { + value = value * 16 + ch - CharacterCodes._0; + } + else if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) { + value = value * 16 + ch - CharacterCodes.A + 10; + } + else if (ch >= CharacterCodes.a && ch <= CharacterCodes.f) { + value = value * 16 + ch - CharacterCodes.a + 10; + } + else { + break; + } + pos++; + digits++; + } + if (digits < minCount) { + value = -1; + } + return value; + } + + function scanString(): string { + let quote = text.charCodeAt(pos++); + let result = ""; + let start = pos; + while (true) { + if (pos >= end) { + result += text.substring(start, pos); + tokenIsUnterminated = true; + error(Diagnostics.Unterminated_string_literal); + break; + } + let ch = text.charCodeAt(pos); + if (ch === quote) { + result += text.substring(start, pos); + pos++; + break; + } + if (ch === CharacterCodes.backslash) { + result += text.substring(start, pos); + result += scanEscapeSequence(); + start = pos; + continue; + } + if (isLineBreak(ch)) { + result += text.substring(start, pos); + tokenIsUnterminated = true; + error(Diagnostics.Unterminated_string_literal); + break; + } + pos++; + } + return result; + } + + /** + * Sets the current 'tokenValue' and returns a NoSubstitutionTemplateLiteral or + * a literal component of a TemplateExpression. + */ + function scanTemplateAndSetTokenValue(): SyntaxKind { + let startedWithBacktick = text.charCodeAt(pos) === CharacterCodes.backtick; + + pos++; + let start = pos; + let contents = "" + let resultingToken: SyntaxKind; + + while (true) { + if (pos >= end) { + contents += text.substring(start, pos); + tokenIsUnterminated = true; + error(Diagnostics.Unterminated_template_literal); + resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail; + break; + } + + let currChar = text.charCodeAt(pos); + + // '`' + if (currChar === CharacterCodes.backtick) { + contents += text.substring(start, pos); + pos++; + resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail; + break; + } + + // '${' + if (currChar === CharacterCodes.$ && pos + 1 < end && text.charCodeAt(pos + 1) === CharacterCodes.openBrace) { + contents += text.substring(start, pos); + pos += 2; + resultingToken = startedWithBacktick ? SyntaxKind.TemplateHead : SyntaxKind.TemplateMiddle; + break; + } + + // Escape character + if (currChar === CharacterCodes.backslash) { + contents += text.substring(start, pos); + contents += scanEscapeSequence(); + start = pos; + continue; + } + + // Speculated ECMAScript 6 Spec 11.8.6.1: + // and LineTerminatorSequences are normalized to for Template Values + if (currChar === CharacterCodes.carriageReturn) { + contents += text.substring(start, pos); + pos++; + + if (pos < end && text.charCodeAt(pos) === CharacterCodes.lineFeed) { + pos++; + } + + contents += "\n"; + start = pos; + continue; + } + + pos++; + } + + Debug.assert(resultingToken !== undefined); + + tokenValue = contents; + return resultingToken; + } + + function scanEscapeSequence(): string { + pos++; + if (pos >= end) { + error(Diagnostics.Unexpected_end_of_text); + return ""; + } + let ch = text.charCodeAt(pos++); + switch (ch) { + case CharacterCodes._0: + return "\0"; + case CharacterCodes.b: + return "\b"; + case CharacterCodes.t: + return "\t"; + case CharacterCodes.n: + return "\n"; + case CharacterCodes.v: + return "\v"; + case CharacterCodes.f: + return "\f"; + case CharacterCodes.r: + return "\r"; + case CharacterCodes.singleQuote: + return "\'"; + case CharacterCodes.doubleQuote: + return "\""; + case CharacterCodes.u: + // '\u{DDDDDDDD}' + if (pos < end && text.charCodeAt(pos) === CharacterCodes.openBrace) { + hasExtendedUnicodeEscape = true; + pos++; + return scanExtendedUnicodeEscape(); + } + + // '\uDDDD' + return scanHexadecimalEscape(/*numDigits*/ 4) + + case CharacterCodes.x: + // '\xDD' + return scanHexadecimalEscape(/*numDigits*/ 2) + + // when encountering a LineContinuation (i.e. a backslash and a line terminator sequence), + // the line terminator is interpreted to be "the empty code unit sequence". + case CharacterCodes.carriageReturn: + if (pos < end && text.charCodeAt(pos) === CharacterCodes.lineFeed) { + pos++; + } + // fall through + case CharacterCodes.lineFeed: + case CharacterCodes.lineSeparator: + case CharacterCodes.paragraphSeparator: + return "" + default: + return String.fromCharCode(ch); + } + } + + function scanHexadecimalEscape(numDigits: number): string { + let escapedValue = scanExactNumberOfHexDigits(numDigits); + + if (escapedValue >= 0) { + return String.fromCharCode(escapedValue); + } + else { + error(Diagnostics.Hexadecimal_digit_expected); + return "" + } + } + + function scanExtendedUnicodeEscape(): string { + let escapedValue = scanMinimumNumberOfHexDigits(1); + let isInvalidExtendedEscape = false; + + // Validate the value of the digit + if (escapedValue < 0) { + error(Diagnostics.Hexadecimal_digit_expected) + isInvalidExtendedEscape = true; + } + else if (escapedValue > 0x10FFFF) { + error(Diagnostics.An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive); + isInvalidExtendedEscape = true; + } + + if (pos >= end) { + error(Diagnostics.Unexpected_end_of_text); + isInvalidExtendedEscape = true; + } + else if (text.charCodeAt(pos) == CharacterCodes.closeBrace) { + // Only swallow the following character up if it's a '}'. + pos++; + } + else { + error(Diagnostics.Unterminated_Unicode_escape_sequence); + isInvalidExtendedEscape = true; + } + + if (isInvalidExtendedEscape) { + return ""; + } + + return utf16EncodeAsString(escapedValue); + } + + // Derived from the 10.1.1 UTF16Encoding of the ES6 Spec. + function utf16EncodeAsString(codePoint: number): string { + Debug.assert(0x0 <= codePoint && codePoint <= 0x10FFFF); + + if (codePoint <= 65535) { + return String.fromCharCode(codePoint); + } + + let codeUnit1 = Math.floor((codePoint - 65536) / 1024) + 0xD800; + let codeUnit2 = ((codePoint - 65536) % 1024) + 0xDC00; + + return String.fromCharCode(codeUnit1, codeUnit2); + } + + // Current character is known to be a backslash. Check for Unicode escape of the form '\uXXXX' + // and return code point value if valid Unicode escape is found. Otherwise return -1. + function peekUnicodeEscape(): number { + if (pos + 5 < end && text.charCodeAt(pos + 1) === CharacterCodes.u) { + let start = pos; + pos += 2; + let value = scanExactNumberOfHexDigits(4); + pos = start; + return value; + } + return -1; + } + + function scanIdentifierParts(): string { + let result = ""; + let start = pos; + while (pos < end) { + let ch = text.charCodeAt(pos); + if (isIdentifierPart(ch)) { + pos++; + } + else if (ch === CharacterCodes.backslash) { + ch = peekUnicodeEscape(); + if (!(ch >= 0 && isIdentifierPart(ch))) { + break; + } + result += text.substring(start, pos); + result += String.fromCharCode(ch); + // Valid Unicode escape is always six characters + pos += 6; + start = pos; + } + else { + break; + } + } + result += text.substring(start, pos); + return result; + } + + function getIdentifierToken(): SyntaxKind { + // Reserved words are between 2 and 11 characters long and start with a lowercase letter + let len = tokenValue.length; + if (len >= 2 && len <= 11) { + let ch = tokenValue.charCodeAt(0); + if (ch >= CharacterCodes.a && ch <= CharacterCodes.z && hasOwnProperty.call(textToToken, tokenValue)) { + return token = textToToken[tokenValue]; + } + } + return token = SyntaxKind.Identifier; + } + + function scanBinaryOrOctalDigits(base: number): number { + Debug.assert(base !== 2 || base !== 8, "Expected either base 2 or base 8"); + + let value = 0; + // For counting number of digits; Valid binaryIntegerLiteral must have at least one binary digit following B or b. + // Similarly valid octalIntegerLiteral must have at least one octal digit following o or O. + let numberOfDigits = 0; + while (true) { + let ch = text.charCodeAt(pos); + let valueOfCh = ch - CharacterCodes._0; + if (!isDigit(ch) || valueOfCh >= base) { + break; + } + value = value * base + valueOfCh; + pos++; + numberOfDigits++; + } + // Invalid binaryIntegerLiteral or octalIntegerLiteral + if (numberOfDigits === 0) { + return -1; + } + return value; + } + + function scan(): SyntaxKind { + startPos = pos; + hasExtendedUnicodeEscape = false; + precedingLineBreak = false; + tokenIsUnterminated = false; + while (true) { + tokenPos = pos; + if (pos >= end) { + return token = SyntaxKind.EndOfFileToken; + } + let ch = text.charCodeAt(pos); + switch (ch) { + case CharacterCodes.lineFeed: + case CharacterCodes.carriageReturn: + precedingLineBreak = true; + if (skipTrivia) { + pos++; + continue; + } + else { + if (ch === CharacterCodes.carriageReturn && pos + 1 < end && text.charCodeAt(pos + 1) === CharacterCodes.lineFeed) { + // consume both CR and LF + pos += 2; + } + else { + pos++; + } + return token = SyntaxKind.NewLineTrivia; + } + case CharacterCodes.tab: + case CharacterCodes.verticalTab: + case CharacterCodes.formFeed: + case CharacterCodes.space: + if (skipTrivia) { + pos++; + continue; + } + else { + while (pos < end && isWhiteSpace(text.charCodeAt(pos))) { + pos++; + } + return token = SyntaxKind.WhitespaceTrivia; + } + case CharacterCodes.exclamation: + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + if (text.charCodeAt(pos + 2) === CharacterCodes.equals) { + return pos += 3, token = SyntaxKind.ExclamationEqualsEqualsToken; + } + return pos += 2, token = SyntaxKind.ExclamationEqualsToken; + } + return pos++, token = SyntaxKind.ExclamationToken; + case CharacterCodes.doubleQuote: + case CharacterCodes.singleQuote: + tokenValue = scanString(); + return token = SyntaxKind.StringLiteral; + case CharacterCodes.backtick: + return token = scanTemplateAndSetTokenValue() + case CharacterCodes.percent: + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + return pos += 2, token = SyntaxKind.PercentEqualsToken; + } + return pos++, token = SyntaxKind.PercentToken; + case CharacterCodes.ampersand: + if (text.charCodeAt(pos + 1) === CharacterCodes.ampersand) { + return pos += 2, token = SyntaxKind.AmpersandAmpersandToken; + } + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + return pos += 2, token = SyntaxKind.AmpersandEqualsToken; + } + return pos++, token = SyntaxKind.AmpersandToken; + case CharacterCodes.openParen: + return pos++, token = SyntaxKind.OpenParenToken; + case CharacterCodes.closeParen: + return pos++, token = SyntaxKind.CloseParenToken; + case CharacterCodes.asterisk: + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + return pos += 2, token = SyntaxKind.AsteriskEqualsToken; + } + return pos++, token = SyntaxKind.AsteriskToken; + case CharacterCodes.plus: + if (text.charCodeAt(pos + 1) === CharacterCodes.plus) { + return pos += 2, token = SyntaxKind.PlusPlusToken; + } + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + return pos += 2, token = SyntaxKind.PlusEqualsToken; + } + return pos++, token = SyntaxKind.PlusToken; + case CharacterCodes.comma: + return pos++, token = SyntaxKind.CommaToken; + case CharacterCodes.minus: + if (text.charCodeAt(pos + 1) === CharacterCodes.minus) { + return pos += 2, token = SyntaxKind.MinusMinusToken; + } + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + return pos += 2, token = SyntaxKind.MinusEqualsToken; + } + return pos++, token = SyntaxKind.MinusToken; + case CharacterCodes.dot: + if (isDigit(text.charCodeAt(pos + 1))) { + tokenValue = "" + scanNumber(); + return token = SyntaxKind.NumericLiteral; + } + if (text.charCodeAt(pos + 1) === CharacterCodes.dot && text.charCodeAt(pos + 2) === CharacterCodes.dot) { + return pos += 3, token = SyntaxKind.DotDotDotToken; + } + return pos++, token = SyntaxKind.DotToken; + case CharacterCodes.slash: + // Single-line comment + if (text.charCodeAt(pos + 1) === CharacterCodes.slash) { + pos += 2; + + while (pos < end) { + if (isLineBreak(text.charCodeAt(pos))) { + break; + } + pos++; + + } + + if (skipTrivia) { + continue; + } + else { + return token = SyntaxKind.SingleLineCommentTrivia; + } + } + // Multi-line comment + if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) { + pos += 2; + + let commentClosed = false; + while (pos < end) { + let ch = text.charCodeAt(pos); + + if (ch === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) { + pos += 2; + commentClosed = true; + break; + } + + if (isLineBreak(ch)) { + precedingLineBreak = true; + } + pos++; + } + + if (!commentClosed) { + error(Diagnostics.Asterisk_Slash_expected); + } + + if (skipTrivia) { + continue; + } + else { + tokenIsUnterminated = !commentClosed; + return token = SyntaxKind.MultiLineCommentTrivia; + } + } + + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + return pos += 2, token = SyntaxKind.SlashEqualsToken; + } + + return pos++, token = SyntaxKind.SlashToken; + + case CharacterCodes._0: + if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.X || text.charCodeAt(pos + 1) === CharacterCodes.x)) { + pos += 2; + let value = scanMinimumNumberOfHexDigits(1); + if (value < 0) { + error(Diagnostics.Hexadecimal_digit_expected); + value = 0; + } + tokenValue = "" + value; + return token = SyntaxKind.NumericLiteral; + } + else if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.B || text.charCodeAt(pos + 1) === CharacterCodes.b)) { + pos += 2; + let value = scanBinaryOrOctalDigits(/* base */ 2); + if (value < 0) { + error(Diagnostics.Binary_digit_expected); + value = 0; + } + tokenValue = "" + value; + return token = SyntaxKind.NumericLiteral; + } + else if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.O || text.charCodeAt(pos + 1) === CharacterCodes.o)) { + pos += 2; + let value = scanBinaryOrOctalDigits(/* base */ 8); + if (value < 0) { + error(Diagnostics.Octal_digit_expected); + value = 0; + } + tokenValue = "" + value; + return token = SyntaxKind.NumericLiteral; + } + // Try to parse as an octal + if (pos + 1 < end && isOctalDigit(text.charCodeAt(pos + 1))) { + tokenValue = "" + scanOctalDigits(); + return token = SyntaxKind.NumericLiteral; + } + // This fall-through is a deviation from the EcmaScript grammar. The grammar says that a leading zero + // can only be followed by an octal digit, a dot, or the end of the number literal. However, we are being + // permissive and allowing decimal digits of the form 08* and 09* (which many browsers also do). + case CharacterCodes._1: + case CharacterCodes._2: + case CharacterCodes._3: + case CharacterCodes._4: + case CharacterCodes._5: + case CharacterCodes._6: + case CharacterCodes._7: + case CharacterCodes._8: + case CharacterCodes._9: + tokenValue = "" + scanNumber(); + return token = SyntaxKind.NumericLiteral; + case CharacterCodes.colon: + return pos++, token = SyntaxKind.ColonToken; + case CharacterCodes.semicolon: + return pos++, token = SyntaxKind.SemicolonToken; + case CharacterCodes.lessThan: + if (isConflictMarkerTrivia(text, pos)) { + pos = scanConflictMarkerTrivia(text, pos, error); + if (skipTrivia) { + continue; + } + else { + return token = SyntaxKind.ConflictMarkerTrivia; + } + } + + if (text.charCodeAt(pos + 1) === CharacterCodes.lessThan) { + if (text.charCodeAt(pos + 2) === CharacterCodes.equals) { + return pos += 3, token = SyntaxKind.LessThanLessThanEqualsToken; + } + return pos += 2, token = SyntaxKind.LessThanLessThanToken; + } + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + return pos += 2, token = SyntaxKind.LessThanEqualsToken; + } + return pos++, token = SyntaxKind.LessThanToken; + case CharacterCodes.equals: + if (isConflictMarkerTrivia(text, pos)) { + pos = scanConflictMarkerTrivia(text, pos, error); + if (skipTrivia) { + continue; + } + else { + return token = SyntaxKind.ConflictMarkerTrivia; + } + } + + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + if (text.charCodeAt(pos + 2) === CharacterCodes.equals) { + return pos += 3, token = SyntaxKind.EqualsEqualsEqualsToken; + } + return pos += 2, token = SyntaxKind.EqualsEqualsToken; + } + if (text.charCodeAt(pos + 1) === CharacterCodes.greaterThan) { + return pos += 2, token = SyntaxKind.EqualsGreaterThanToken; + } + return pos++, token = SyntaxKind.EqualsToken; + case CharacterCodes.greaterThan: + if (isConflictMarkerTrivia(text, pos)) { + pos = scanConflictMarkerTrivia(text, pos, error); + if (skipTrivia) { + continue; + } + else { + return token = SyntaxKind.ConflictMarkerTrivia; + } + } + + return pos++, token = SyntaxKind.GreaterThanToken; + case CharacterCodes.question: + return pos++, token = SyntaxKind.QuestionToken; + case CharacterCodes.openBracket: + return pos++, token = SyntaxKind.OpenBracketToken; + case CharacterCodes.closeBracket: + return pos++, token = SyntaxKind.CloseBracketToken; + case CharacterCodes.caret: + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + return pos += 2, token = SyntaxKind.CaretEqualsToken; + } + return pos++, token = SyntaxKind.CaretToken; + case CharacterCodes.openBrace: + return pos++, token = SyntaxKind.OpenBraceToken; + case CharacterCodes.bar: + if (text.charCodeAt(pos + 1) === CharacterCodes.bar) { + return pos += 2, token = SyntaxKind.BarBarToken; + } + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + return pos += 2, token = SyntaxKind.BarEqualsToken; + } + return pos++, token = SyntaxKind.BarToken; + case CharacterCodes.closeBrace: + return pos++, token = SyntaxKind.CloseBraceToken; + case CharacterCodes.tilde: + return pos++, token = SyntaxKind.TildeToken; + case CharacterCodes.at: + return pos++, token = SyntaxKind.AtToken; + case CharacterCodes.backslash: + let cookedChar = peekUnicodeEscape(); + if (cookedChar >= 0 && isIdentifierStart(cookedChar)) { + pos += 6; + tokenValue = String.fromCharCode(cookedChar) + scanIdentifierParts(); + return token = getIdentifierToken(); + } + error(Diagnostics.Invalid_character); + return pos++, token = SyntaxKind.Unknown; + default: + if (isIdentifierStart(ch)) { + pos++; + while (pos < end && isIdentifierPart(ch = text.charCodeAt(pos))) pos++; + tokenValue = text.substring(tokenPos, pos); + if (ch === CharacterCodes.backslash) { + tokenValue += scanIdentifierParts(); + } + return token = getIdentifierToken(); + } + else if (isWhiteSpace(ch)) { + pos++; + continue; + } + else if (isLineBreak(ch)) { + precedingLineBreak = true; + pos++; + continue; + } + error(Diagnostics.Invalid_character); + return pos++, token = SyntaxKind.Unknown; + } + } + } + + function reScanGreaterToken(): SyntaxKind { + if (token === SyntaxKind.GreaterThanToken) { + if (text.charCodeAt(pos) === CharacterCodes.greaterThan) { + if (text.charCodeAt(pos + 1) === CharacterCodes.greaterThan) { + if (text.charCodeAt(pos + 2) === CharacterCodes.equals) { + return pos += 3, token = SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken; + } + return pos += 2, token = SyntaxKind.GreaterThanGreaterThanGreaterThanToken; + } + if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { + return pos += 2, token = SyntaxKind.GreaterThanGreaterThanEqualsToken; + } + return pos++, token = SyntaxKind.GreaterThanGreaterThanToken; + } + if (text.charCodeAt(pos) === CharacterCodes.equals) { + return pos++, token = SyntaxKind.GreaterThanEqualsToken; + } + } + return token; + } + + function reScanSlashToken(): SyntaxKind { + if (token === SyntaxKind.SlashToken || token === SyntaxKind.SlashEqualsToken) { + let p = tokenPos + 1; + let inEscape = false; + let inCharacterClass = false; + while (true) { + // If we reach the end of a file, or hit a newline, then this is an unterminated + // regex. Report error and return what we have so far. + if (p >= end) { + tokenIsUnterminated = true; + error(Diagnostics.Unterminated_regular_expression_literal) + break; + } + + let ch = text.charCodeAt(p); + if (isLineBreak(ch)) { + tokenIsUnterminated = true; + error(Diagnostics.Unterminated_regular_expression_literal) + break; + } + + if (inEscape) { + // Parsing an escape character; + // reset the flag and just advance to the next char. + inEscape = false; + } + else if (ch === CharacterCodes.slash && !inCharacterClass) { + // A slash within a character class is permissible, + // but in general it signals the end of the regexp literal. + p++; + break; + } + else if (ch === CharacterCodes.openBracket) { + inCharacterClass = true; + } + else if (ch === CharacterCodes.backslash) { + inEscape = true; + } + else if (ch === CharacterCodes.closeBracket) { + inCharacterClass = false; + } + p++; + } + + while (p < end && isIdentifierPart(text.charCodeAt(p))) { + p++; + } + pos = p; + tokenValue = text.substring(tokenPos, pos); + token = SyntaxKind.RegularExpressionLiteral; + } + return token; + } + + /** + * Unconditionally back up and scan a template expression portion. + */ + function reScanTemplateToken(): SyntaxKind { + Debug.assert(token === SyntaxKind.CloseBraceToken, "'reScanTemplateToken' should only be called on a '}'"); + pos = tokenPos; + return token = scanTemplateAndSetTokenValue(); + } + + function speculationHelper(callback: () => T, isLookahead: boolean): T { + let savePos = pos; + let saveStartPos = startPos; + let saveTokenPos = tokenPos; + let saveToken = token; + let saveTokenValue = tokenValue; + let savePrecedingLineBreak = precedingLineBreak; + let result = callback(); + + // If our callback returned something 'falsy' or we're just looking ahead, + // then unconditionally restore us to where we were. + if (!result || isLookahead) { + pos = savePos; + startPos = saveStartPos; + tokenPos = saveTokenPos; + token = saveToken; + tokenValue = saveTokenValue; + precedingLineBreak = savePrecedingLineBreak; + } + return result; + } + + function lookAhead(callback: () => T): T { + return speculationHelper(callback, /*isLookahead:*/ true); + } + + function tryScan(callback: () => T): T { + return speculationHelper(callback, /*isLookahead:*/ false); + } + + function setText(newText: string, start: number, length: number) { + text = newText || ""; + end = length === undefined ? text.length : start + length; + setTextPos(start || 0); + } + + function setOnError(errorCallback: ErrorCallback) { + onError = errorCallback; + } + + function setScriptTarget(scriptTarget: ScriptTarget) { + languageVersion = scriptTarget; + } + + function setTextPos(textPos: number) { + Debug.assert(textPos >= 0); + pos = textPos; + startPos = textPos; + tokenPos = textPos; + token = SyntaxKind.Unknown; + precedingLineBreak = false; + + tokenValue = undefined; + hasExtendedUnicodeEscape = false; + tokenIsUnterminated = false; + } + } +} diff --git a/lib/typescript/compiler/sys.ts b/lib/typescript/compiler/sys.ts new file mode 100644 index 000000000..92c26bf01 --- /dev/null +++ b/lib/typescript/compiler/sys.ts @@ -0,0 +1,318 @@ +/// + +module ts { + export interface System { + args: string[]; + newLine: string; + useCaseSensitiveFileNames: boolean; + write(s: string): void; + readFile(path: string, encoding?: string): string; + writeFile(path: string, data: string, writeByteOrderMark?: boolean): void; + watchFile?(path: string, callback: (path: string) => void): FileWatcher; + resolvePath(path: string): string; + fileExists(path: string): boolean; + directoryExists(path: string): boolean; + createDirectory(path: string): void; + getExecutingFilePath(): string; + getCurrentDirectory(): string; + readDirectory(path: string, extension?: string): string[]; + getMemoryUsage?(): number; + exit(exitCode?: number): void; + } + + export interface FileWatcher { + close(): void; + } + + declare var require: any; + declare var module: any; + declare var process: any; + declare var global: any; + declare var __filename: string; + + declare class Enumerator { + public atEnd(): boolean; + public moveNext(): boolean; + public item(): any; + constructor(o: any); + } + + export var sys: System = (function () { + + function getWScriptSystem(): System { + + var fso = new ActiveXObject("Scripting.FileSystemObject"); + + var fileStream = new ActiveXObject("ADODB.Stream"); + fileStream.Type = 2 /*text*/; + + var binaryStream = new ActiveXObject("ADODB.Stream"); + binaryStream.Type = 1 /*binary*/; + + var args: string[] = []; + for (var i = 0; i < WScript.Arguments.length; i++) { + args[i] = WScript.Arguments.Item(i); + } + + function readFile(fileName: string, encoding?: string): string { + if (!fso.FileExists(fileName)) { + return undefined; + } + fileStream.Open(); + try { + if (encoding) { + fileStream.Charset = encoding; + fileStream.LoadFromFile(fileName); + } + else { + // Load file and read the first two bytes into a string with no interpretation + fileStream.Charset = "x-ansi"; + fileStream.LoadFromFile(fileName); + var bom = fileStream.ReadText(2) || ""; + // Position must be at 0 before encoding can be changed + fileStream.Position = 0; + // [0xFF,0xFE] and [0xFE,0xFF] mean utf-16 (little or big endian), otherwise default to utf-8 + fileStream.Charset = bom.length >= 2 && (bom.charCodeAt(0) === 0xFF && bom.charCodeAt(1) === 0xFE || bom.charCodeAt(0) === 0xFE && bom.charCodeAt(1) === 0xFF) ? "unicode" : "utf-8"; + } + // ReadText method always strips byte order mark from resulting string + return fileStream.ReadText(); + } + catch (e) { + throw e; + } + finally { + fileStream.Close(); + } + } + + function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void { + fileStream.Open(); + binaryStream.Open(); + try { + // Write characters in UTF-8 encoding + fileStream.Charset = "utf-8"; + fileStream.WriteText(data); + // If we don't want the BOM, then skip it by setting the starting location to 3 (size of BOM). + // If not, start from position 0, as the BOM will be added automatically when charset==utf8. + if (writeByteOrderMark) { + fileStream.Position = 0; + } + else { + fileStream.Position = 3; + } + fileStream.CopyTo(binaryStream); + binaryStream.SaveToFile(fileName, 2 /*overwrite*/); + } + finally { + binaryStream.Close(); + fileStream.Close(); + } + } + + function getNames(collection: any): string[] { + var result: string[] = []; + for (var e = new Enumerator(collection); !e.atEnd(); e.moveNext()) { + result.push(e.item().Name); + } + return result.sort(); + } + + function readDirectory(path: string, extension?: string): string[] { + var result: string[] = []; + visitDirectory(path); + return result; + function visitDirectory(path: string) { + var folder = fso.GetFolder(path || "."); + var files = getNames(folder.files); + for (let name of files) { + if (!extension || fileExtensionIs(name, extension)) { + result.push(combinePaths(path, name)); + } + } + var subfolders = getNames(folder.subfolders); + for (let current of subfolders) { + visitDirectory(combinePaths(path, current)); + } + } + } + + return { + args, + newLine: "\r\n", + useCaseSensitiveFileNames: false, + write(s: string): void { + WScript.StdOut.Write(s); + }, + readFile, + writeFile, + resolvePath(path: string): string { + return fso.GetAbsolutePathName(path); + }, + fileExists(path: string): boolean { + return fso.FileExists(path); + }, + directoryExists(path: string) { + return fso.FolderExists(path); + }, + createDirectory(directoryName: string) { + if (!this.directoryExists(directoryName)) { + fso.CreateFolder(directoryName); + } + }, + getExecutingFilePath() { + return WScript.ScriptFullName; + }, + getCurrentDirectory() { + return new ActiveXObject("WScript.Shell").CurrentDirectory; + }, + readDirectory, + exit(exitCode?: number): void { + try { + WScript.Quit(exitCode); + } + catch (e) { + } + } + }; + } + function getNodeSystem(): System { + var _fs = require("fs"); + var _path = require("path"); + var _os = require('os'); + + var platform: string = _os.platform(); + // win32\win64 are case insensitive platforms, MacOS (darwin) by default is also case insensitive + var useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin"; + + function readFile(fileName: string, encoding?: string): string { + if (!_fs.existsSync(fileName)) { + return undefined; + } + var buffer = _fs.readFileSync(fileName); + var len = buffer.length; + if (len >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) { + // Big endian UTF-16 byte order mark detected. Since big endian is not supported by node.js, + // flip all byte pairs and treat as little endian. + len &= ~1; + for (var i = 0; i < len; i += 2) { + var temp = buffer[i]; + buffer[i] = buffer[i + 1]; + buffer[i + 1] = temp; + } + return buffer.toString("utf16le", 2); + } + if (len >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) { + // Little endian UTF-16 byte order mark detected + return buffer.toString("utf16le", 2); + } + if (len >= 3 && buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) { + // UTF-8 byte order mark detected + return buffer.toString("utf8", 3); + } + // Default is UTF-8 with no byte order mark + return buffer.toString("utf8"); + } + + function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void { + // If a BOM is required, emit one + if (writeByteOrderMark) { + data = '\uFEFF' + data; + } + + _fs.writeFileSync(fileName, data, "utf8"); + } + + function readDirectory(path: string, extension?: string): string[] { + var result: string[] = []; + visitDirectory(path); + return result; + function visitDirectory(path: string) { + var files = _fs.readdirSync(path || ".").sort(); + var directories: string[] = []; + for (let current of files) { + var name = combinePaths(path, current); + var stat = _fs.lstatSync(name); + if (stat.isFile()) { + if (!extension || fileExtensionIs(name, extension)) { + result.push(name); + } + } + else if (stat.isDirectory()) { + directories.push(name); + } + } + for (let current of directories) { + visitDirectory(current); + } + } + } + + return { + args: process.argv.slice(2), + newLine: _os.EOL, + useCaseSensitiveFileNames: useCaseSensitiveFileNames, + write(s: string): void { + // 1 is a standard descriptor for stdout + _fs.writeSync(1, s); + }, + readFile, + writeFile, + watchFile: (fileName, callback) => { + // watchFile polls a file every 250ms, picking up file notifications. + _fs.watchFile(fileName, { persistent: true, interval: 250 }, fileChanged); + + return { + close() { _fs.unwatchFile(fileName, fileChanged); } + }; + + function fileChanged(curr: any, prev: any) { + if (+curr.mtime <= +prev.mtime) { + return; + } + + callback(fileName); + }; + }, + resolvePath: function (path: string): string { + return _path.resolve(path); + }, + fileExists(path: string): boolean { + return _fs.existsSync(path); + }, + directoryExists(path: string) { + return _fs.existsSync(path) && _fs.statSync(path).isDirectory(); + }, + createDirectory(directoryName: string) { + if (!this.directoryExists(directoryName)) { + _fs.mkdirSync(directoryName); + } + }, + getExecutingFilePath() { + return __filename; + }, + getCurrentDirectory() { + return process.cwd(); + }, + readDirectory, + getMemoryUsage() { + if (global.gc) { + global.gc(); + } + return process.memoryUsage().heapUsed; + }, + exit(exitCode?: number): void { + process.exit(exitCode); + } + }; + } + if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") { + return getWScriptSystem(); + } + else if (typeof module !== "undefined" && module.exports) { + return getNodeSystem(); + } + else { + return undefined; // Unsupported host + } + })(); +} \ No newline at end of file diff --git a/lib/typescript/compiler/types.ts b/lib/typescript/compiler/types.ts new file mode 100644 index 000000000..09c389b31 --- /dev/null +++ b/lib/typescript/compiler/types.ts @@ -0,0 +1,1898 @@ +module ts { + export interface Map { + [index: string]: T; + } + + export interface TextRange { + pos: number; + end: number; + } + + // token > SyntaxKind.Identifer => token is a keyword + export const enum SyntaxKind { + Unknown, + EndOfFileToken, + SingleLineCommentTrivia, + MultiLineCommentTrivia, + NewLineTrivia, + WhitespaceTrivia, + // We detect and provide better error recovery when we encounter a git merge marker. This + // allows us to edit files with git-conflict markers in them in a much more pleasant manner. + ConflictMarkerTrivia, + // Literals + NumericLiteral, + StringLiteral, + RegularExpressionLiteral, + NoSubstitutionTemplateLiteral, + // Pseudo-literals + TemplateHead, + TemplateMiddle, + TemplateTail, + // Punctuation + OpenBraceToken, + CloseBraceToken, + OpenParenToken, + CloseParenToken, + OpenBracketToken, + CloseBracketToken, + DotToken, + DotDotDotToken, + SemicolonToken, + CommaToken, + LessThanToken, + GreaterThanToken, + LessThanEqualsToken, + GreaterThanEqualsToken, + EqualsEqualsToken, + ExclamationEqualsToken, + EqualsEqualsEqualsToken, + ExclamationEqualsEqualsToken, + EqualsGreaterThanToken, + PlusToken, + MinusToken, + AsteriskToken, + SlashToken, + PercentToken, + PlusPlusToken, + MinusMinusToken, + LessThanLessThanToken, + GreaterThanGreaterThanToken, + GreaterThanGreaterThanGreaterThanToken, + AmpersandToken, + BarToken, + CaretToken, + ExclamationToken, + TildeToken, + AmpersandAmpersandToken, + BarBarToken, + QuestionToken, + ColonToken, + AtToken, + // Assignments + EqualsToken, + PlusEqualsToken, + MinusEqualsToken, + AsteriskEqualsToken, + SlashEqualsToken, + PercentEqualsToken, + LessThanLessThanEqualsToken, + GreaterThanGreaterThanEqualsToken, + GreaterThanGreaterThanGreaterThanEqualsToken, + AmpersandEqualsToken, + BarEqualsToken, + CaretEqualsToken, + // Identifiers + Identifier, + // Reserved words + BreakKeyword, + CaseKeyword, + CatchKeyword, + ClassKeyword, + ConstKeyword, + ContinueKeyword, + DebuggerKeyword, + DefaultKeyword, + DeleteKeyword, + DoKeyword, + ElseKeyword, + EnumKeyword, + ExportKeyword, + ExtendsKeyword, + FalseKeyword, + FinallyKeyword, + ForKeyword, + FunctionKeyword, + IfKeyword, + ImportKeyword, + InKeyword, + InstanceOfKeyword, + NewKeyword, + NullKeyword, + ReturnKeyword, + SuperKeyword, + SwitchKeyword, + ThisKeyword, + ThrowKeyword, + TrueKeyword, + TryKeyword, + TypeOfKeyword, + VarKeyword, + VoidKeyword, + WhileKeyword, + WithKeyword, + // Strict mode reserved words + ImplementsKeyword, + InterfaceKeyword, + LetKeyword, + PackageKeyword, + PrivateKeyword, + ProtectedKeyword, + PublicKeyword, + StaticKeyword, + YieldKeyword, + // Contextual keywords + AsKeyword, + AnyKeyword, + BooleanKeyword, + ConstructorKeyword, + DeclareKeyword, + GetKeyword, + ModuleKeyword, + RequireKeyword, + NumberKeyword, + SetKeyword, + StringKeyword, + SymbolKeyword, + TypeKeyword, + FromKeyword, + OfKeyword, // LastKeyword and LastToken + + // Parse tree nodes + + // Names + QualifiedName, + ComputedPropertyName, + // Signature elements + TypeParameter, + Parameter, + Decorator, + // TypeMember + PropertySignature, + PropertyDeclaration, + MethodSignature, + MethodDeclaration, + Constructor, + GetAccessor, + SetAccessor, + CallSignature, + ConstructSignature, + IndexSignature, + // Type + TypeReference, + FunctionType, + ConstructorType, + TypeQuery, + TypeLiteral, + ArrayType, + TupleType, + UnionType, + ParenthesizedType, + // Binding patterns + ObjectBindingPattern, + ArrayBindingPattern, + BindingElement, + // Expression + ArrayLiteralExpression, + ObjectLiteralExpression, + PropertyAccessExpression, + ElementAccessExpression, + CallExpression, + NewExpression, + TaggedTemplateExpression, + TypeAssertionExpression, + ParenthesizedExpression, + FunctionExpression, + ArrowFunction, + DeleteExpression, + TypeOfExpression, + VoidExpression, + PrefixUnaryExpression, + PostfixUnaryExpression, + BinaryExpression, + ConditionalExpression, + TemplateExpression, + YieldExpression, + SpreadElementExpression, + ClassExpression, + OmittedExpression, + // Misc + TemplateSpan, + HeritageClauseElement, + SemicolonClassElement, + // Element + Block, + VariableStatement, + EmptyStatement, + ExpressionStatement, + IfStatement, + DoStatement, + WhileStatement, + ForStatement, + ForInStatement, + ForOfStatement, + ContinueStatement, + BreakStatement, + ReturnStatement, + WithStatement, + SwitchStatement, + LabeledStatement, + ThrowStatement, + TryStatement, + DebuggerStatement, + VariableDeclaration, + VariableDeclarationList, + FunctionDeclaration, + ClassDeclaration, + InterfaceDeclaration, + TypeAliasDeclaration, + EnumDeclaration, + ModuleDeclaration, + ModuleBlock, + CaseBlock, + ImportEqualsDeclaration, + ImportDeclaration, + ImportClause, + NamespaceImport, + NamedImports, + ImportSpecifier, + ExportAssignment, + ExportDeclaration, + NamedExports, + ExportSpecifier, + MissingDeclaration, + + // Module references + ExternalModuleReference, + + // Clauses + CaseClause, + DefaultClause, + HeritageClause, + CatchClause, + + // Property assignments + PropertyAssignment, + ShorthandPropertyAssignment, + + // Enum + EnumMember, + // Top-level nodes + SourceFile, + + // Synthesized list + SyntaxList, + // Enum value count + Count, + // Markers + FirstAssignment = EqualsToken, + LastAssignment = CaretEqualsToken, + FirstReservedWord = BreakKeyword, + LastReservedWord = WithKeyword, + FirstKeyword = BreakKeyword, + LastKeyword = OfKeyword, + FirstFutureReservedWord = ImplementsKeyword, + LastFutureReservedWord = YieldKeyword, + FirstTypeNode = TypeReference, + LastTypeNode = ParenthesizedType, + FirstPunctuation = OpenBraceToken, + LastPunctuation = CaretEqualsToken, + FirstToken = Unknown, + LastToken = LastKeyword, + FirstTriviaToken = SingleLineCommentTrivia, + LastTriviaToken = ConflictMarkerTrivia, + FirstLiteralToken = NumericLiteral, + LastLiteralToken = NoSubstitutionTemplateLiteral, + FirstTemplateToken = NoSubstitutionTemplateLiteral, + LastTemplateToken = TemplateTail, + FirstBinaryOperator = LessThanToken, + LastBinaryOperator = CaretEqualsToken, + FirstNode = QualifiedName, + } + + export const enum NodeFlags { + Export = 0x00000001, // Declarations + Ambient = 0x00000002, // Declarations + Public = 0x00000010, // Property/Method + Private = 0x00000020, // Property/Method + Protected = 0x00000040, // Property/Method + Static = 0x00000080, // Property/Method + Default = 0x00000100, // Function/Class (export default declaration) + MultiLine = 0x00000200, // Multi-line array or object literal + Synthetic = 0x00000400, // Synthetic node (for full fidelity) + DeclarationFile = 0x00000800, // Node is a .d.ts file + Let = 0x00001000, // Variable declaration + Const = 0x00002000, // Variable declaration + OctalLiteral = 0x00004000, + ExportContext = 0x00008000, // Export context (initialized by binding) + + Modifier = Export | Ambient | Public | Private | Protected | Static | Default, + AccessibilityModifier = Public | Private | Protected, + BlockScoped = Let | Const + } + + /* @internal */ + export const enum ParserContextFlags { + // Set if this node was parsed in strict mode. Used for grammar error checks, as well as + // checking if the node can be reused in incremental settings. + StrictMode = 1 << 0, + + // If this node was parsed in a context where 'in-expressions' are not allowed. + DisallowIn = 1 << 1, + + // If this node was parsed in the 'yield' context created when parsing a generator. + Yield = 1 << 2, + + // If this node was parsed in the parameters of a generator. + GeneratorParameter = 1 << 3, + + // If this node was parsed as part of a decorator + Decorator = 1 << 4, + + // If the parser encountered an error when parsing the code that created this node. Note + // the parser only sets this directly on the node it creates right after encountering the + // error. + ThisNodeHasError = 1 << 5, + + // Context flags set directly by the parser. + ParserGeneratedFlags = StrictMode | DisallowIn | Yield | GeneratorParameter | Decorator | ThisNodeHasError, + + // Context flags computed by aggregating child flags upwards. + + // Used during incremental parsing to determine if this node or any of its children had an + // error. Computed only once and then cached. + ThisNodeOrAnySubNodesHasError = 1 << 6, + + // Used to know if we've computed data from children and cached it in this node. + HasAggregatedChildData = 1 << 7 + } + + /* @internal */ + export const enum RelationComparisonResult { + Succeeded = 1, // Should be truthy + Failed = 2, + FailedAndReported = 3 + } + + export interface Node extends TextRange { + kind: SyntaxKind; + flags: NodeFlags; + // Specific context the parser was in when this node was created. Normally undefined. + // Only set when the parser was in some interesting context (like async/yield). + /* @internal */ parserContextFlags?: ParserContextFlags; + decorators?: NodeArray; // Array of decorators (in document order) + modifiers?: ModifiersArray; // Array of modifiers + /* @internal */ id?: number; // Unique id (used to look up NodeLinks) + parent?: Node; // Parent node (initialized by binding) + /* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding) + /* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding) + /* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding) + /* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes) + } + + export interface NodeArray extends Array, TextRange { + hasTrailingComma?: boolean; + } + + export interface ModifiersArray extends NodeArray { + flags: number; + } + + export interface Identifier extends PrimaryExpression { + text: string; // Text of identifier (with escapes converted to characters) + originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later + } + + export interface QualifiedName extends Node { + // Must have same layout as PropertyAccess + left: EntityName; + right: Identifier; + } + + export type EntityName = Identifier | QualifiedName; + + export type DeclarationName = Identifier | LiteralExpression | ComputedPropertyName | BindingPattern; + + export interface Declaration extends Node { + _declarationBrand: any; + name?: DeclarationName; + } + + export interface ComputedPropertyName extends Node { + expression: Expression; + } + + export interface Decorator extends Node { + expression: LeftHandSideExpression; + } + + export interface TypeParameterDeclaration extends Declaration { + name: Identifier; + constraint?: TypeNode; + + // For error recovery purposes. + expression?: Expression; + } + + export interface SignatureDeclaration extends Declaration { + typeParameters?: NodeArray; + parameters: NodeArray; + type?: TypeNode; + } + + // SyntaxKind.VariableDeclaration + export interface VariableDeclaration extends Declaration { + parent?: VariableDeclarationList; + name: Identifier | BindingPattern; // Declared variable name + type?: TypeNode; // Optional type annotation + initializer?: Expression; // Optional initializer + } + + export interface VariableDeclarationList extends Node { + declarations: NodeArray; + } + + // SyntaxKind.Parameter + export interface ParameterDeclaration extends Declaration { + dotDotDotToken?: Node; // Present on rest parameter + name: Identifier | BindingPattern; // Declared parameter name + questionToken?: Node; // Present on optional parameter + type?: TypeNode; // Optional type annotation + initializer?: Expression; // Optional initializer + } + + // SyntaxKind.BindingElement + export interface BindingElement extends Declaration { + propertyName?: Identifier; // Binding property name (in object binding pattern) + dotDotDotToken?: Node; // Present on rest binding element + name: Identifier | BindingPattern; // Declared binding element name + initializer?: Expression; // Optional initializer + } + + // SyntaxKind.Property + export interface PropertyDeclaration extends Declaration, ClassElement { + name: DeclarationName; // Declared property name + questionToken?: Node; // Present on optional property + type?: TypeNode; // Optional type annotation + initializer?: Expression; // Optional initializer + } + + export interface ObjectLiteralElement extends Declaration { + _objectLiteralBrandBrand: any; + } + + // SyntaxKind.PropertyAssignment + export interface PropertyAssignment extends ObjectLiteralElement { + _propertyAssignmentBrand: any; + name: DeclarationName; + questionToken?: Node; + initializer: Expression; + } + + // SyntaxKind.ShorthandPropertyAssignment + export interface ShorthandPropertyAssignment extends ObjectLiteralElement { + name: Identifier; + questionToken?: Node; + } + + // SyntaxKind.VariableDeclaration + // SyntaxKind.Parameter + // SyntaxKind.BindingElement + // SyntaxKind.Property + // SyntaxKind.PropertyAssignment + // SyntaxKind.ShorthandPropertyAssignment + // SyntaxKind.EnumMember + export interface VariableLikeDeclaration extends Declaration { + propertyName?: Identifier; + dotDotDotToken?: Node; + name: DeclarationName; + questionToken?: Node; + type?: TypeNode; + initializer?: Expression; + } + + export interface BindingPattern extends Node { + elements: NodeArray; + } + + /** + * Several node kinds share function-like features such as a signature, + * a name, and a body. These nodes should extend FunctionLikeDeclaration. + * Examples: + * FunctionDeclaration + * MethodDeclaration + * AccessorDeclaration + */ + export interface FunctionLikeDeclaration extends SignatureDeclaration { + _functionLikeDeclarationBrand: any; + + asteriskToken?: Node; + questionToken?: Node; + body?: Block | Expression; + } + + export interface FunctionDeclaration extends FunctionLikeDeclaration, Statement { + name?: Identifier; + body?: Block; + } + + // Note that a MethodDeclaration is considered both a ClassElement and an ObjectLiteralElement. + // Both the grammars for ClassDeclaration and ObjectLiteralExpression allow for MethodDeclarations + // as child elements, and so a MethodDeclaration satisfies both interfaces. This avoids the + // alternative where we would need separate kinds/types for ClassMethodDeclaration and + // ObjectLiteralMethodDeclaration, which would look identical. + // + // Because of this, it may be necessary to determine what sort of MethodDeclaration you have + // at later stages of the compiler pipeline. In that case, you can either check the parent kind + // of the method, or use helpers like isObjectLiteralMethodDeclaration + export interface MethodDeclaration extends FunctionLikeDeclaration, ClassElement, ObjectLiteralElement { + body?: Block; + } + + export interface ConstructorDeclaration extends FunctionLikeDeclaration, ClassElement { + body?: Block; + } + + // For when we encounter a semicolon in a class declaration. ES6 allows these as class elements. + export interface SemicolonClassElement extends ClassElement { + _semicolonClassElementBrand: any; + } + + // See the comment on MethodDeclaration for the intuition behind AccessorDeclaration being a + // ClassElement and an ObjectLiteralElement. + export interface AccessorDeclaration extends FunctionLikeDeclaration, ClassElement, ObjectLiteralElement { + _accessorDeclarationBrand: any; + body: Block; + } + + export interface IndexSignatureDeclaration extends SignatureDeclaration, ClassElement { + _indexSignatureDeclarationBrand: any; + } + + export interface TypeNode extends Node { + _typeNodeBrand: any; + } + + export interface FunctionOrConstructorTypeNode extends TypeNode, SignatureDeclaration { + _functionOrConstructorTypeNodeBrand: any; + } + + export interface TypeReferenceNode extends TypeNode { + typeName: EntityName; + typeArguments?: NodeArray; + } + + export interface TypeQueryNode extends TypeNode { + exprName: EntityName; + } + + // A TypeLiteral is the declaration node for an anonymous symbol. + export interface TypeLiteralNode extends TypeNode, Declaration { + members: NodeArray; + } + + export interface ArrayTypeNode extends TypeNode { + elementType: TypeNode; + } + + export interface TupleTypeNode extends TypeNode { + elementTypes: NodeArray; + } + + export interface UnionTypeNode extends TypeNode { + types: NodeArray; + } + + export interface ParenthesizedTypeNode extends TypeNode { + type: TypeNode; + } + + // Note that a StringLiteral AST node is both an Expression and a TypeNode. The latter is + // because string literals can appear in the type annotation of a parameter node. + export interface StringLiteral extends LiteralExpression, TypeNode { + _stringLiteralBrand: any; + } + + // Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing. + // Consider 'Expression'. Without the brand, 'Expression' is actually no different + // (structurally) than 'Node'. Because of this you can pass any Node to a function that + // takes an Expression without any error. By using the 'brands' we ensure that the type + // checker actually thinks you have something of the right type. Note: the brands are + // never actually given values. At runtime they have zero cost. + + export interface Expression extends Node { + _expressionBrand: any; + contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution + } + + export interface UnaryExpression extends Expression { + _unaryExpressionBrand: any; + } + + export interface PrefixUnaryExpression extends UnaryExpression { + operator: SyntaxKind; + operand: UnaryExpression; + } + + export interface PostfixUnaryExpression extends PostfixExpression { + operand: LeftHandSideExpression; + operator: SyntaxKind; + } + + export interface PostfixExpression extends UnaryExpression { + _postfixExpressionBrand: any; + } + + export interface LeftHandSideExpression extends PostfixExpression { + _leftHandSideExpressionBrand: any; + } + + export interface MemberExpression extends LeftHandSideExpression { + _memberExpressionBrand: any; + } + + export interface PrimaryExpression extends MemberExpression { + _primaryExpressionBrand: any; + } + + export interface DeleteExpression extends UnaryExpression { + expression: UnaryExpression; + } + + export interface TypeOfExpression extends UnaryExpression { + expression: UnaryExpression; + } + + export interface VoidExpression extends UnaryExpression { + expression: UnaryExpression; + } + + export interface YieldExpression extends Expression { + asteriskToken?: Node; + expression: Expression; + } + + export interface BinaryExpression extends Expression { + left: Expression; + operatorToken: Node; + right: Expression; + } + + export interface ConditionalExpression extends Expression { + condition: Expression; + questionToken: Node; + whenTrue: Expression; + colonToken: Node; + whenFalse: Expression; + } + + export interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclaration { + name?: Identifier; + body: Block | Expression; // Required, whereas the member inherited from FunctionDeclaration is optional + } + + export interface ArrowFunction extends Expression, FunctionLikeDeclaration { + equalsGreaterThanToken: Node; + } + + // The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral, + // or any literal of a template, this means quotes have been removed and escapes have been converted to actual characters. + // For a NumericLiteral, the stored value is the toString() representation of the number. For example 1, 1.00, and 1e0 are all stored as just "1". + export interface LiteralExpression extends PrimaryExpression { + text: string; + isUnterminated?: boolean; + hasExtendedUnicodeEscape?: boolean; + } + + export interface TemplateExpression extends PrimaryExpression { + head: LiteralExpression; + templateSpans: NodeArray; + } + + // Each of these corresponds to a substitution expression and a template literal, in that order. + // The template literal must have kind TemplateMiddleLiteral or TemplateTailLiteral. + export interface TemplateSpan extends Node { + expression: Expression; + literal: LiteralExpression; + } + + export interface ParenthesizedExpression extends PrimaryExpression { + expression: Expression; + } + + export interface ArrayLiteralExpression extends PrimaryExpression { + elements: NodeArray; + } + + export interface SpreadElementExpression extends Expression { + expression: Expression; + } + + // An ObjectLiteralExpression is the declaration node for an anonymous symbol. + export interface ObjectLiteralExpression extends PrimaryExpression, Declaration { + properties: NodeArray; + } + + export interface PropertyAccessExpression extends MemberExpression { + expression: LeftHandSideExpression; + dotToken: Node; + name: Identifier; + } + + export interface ElementAccessExpression extends MemberExpression { + expression: LeftHandSideExpression; + argumentExpression?: Expression; + } + + export interface CallExpression extends LeftHandSideExpression { + expression: LeftHandSideExpression; + typeArguments?: NodeArray; + arguments: NodeArray; + } + + export interface HeritageClauseElement extends TypeNode { + expression: LeftHandSideExpression; + typeArguments?: NodeArray; + } + + export interface NewExpression extends CallExpression, PrimaryExpression { } + + export interface TaggedTemplateExpression extends MemberExpression { + tag: LeftHandSideExpression; + template: LiteralExpression | TemplateExpression; + } + + export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression; + + export interface TypeAssertion extends UnaryExpression { + type: TypeNode; + expression: UnaryExpression; + } + + export interface Statement extends Node, ModuleElement { + _statementBrand: any; + } + + export interface Block extends Statement { + statements: NodeArray; + } + + export interface VariableStatement extends Statement { + declarationList: VariableDeclarationList; + } + + export interface ExpressionStatement extends Statement { + expression: Expression; + } + + export interface IfStatement extends Statement { + expression: Expression; + thenStatement: Statement; + elseStatement?: Statement; + } + + export interface IterationStatement extends Statement { + statement: Statement; + } + + export interface DoStatement extends IterationStatement { + expression: Expression; + } + + export interface WhileStatement extends IterationStatement { + expression: Expression; + } + + export interface ForStatement extends IterationStatement { + initializer?: VariableDeclarationList | Expression; + condition?: Expression; + incrementor?: Expression; + } + + export interface ForInStatement extends IterationStatement { + initializer: VariableDeclarationList | Expression; + expression: Expression; + } + + export interface ForOfStatement extends IterationStatement { + initializer: VariableDeclarationList | Expression; + expression: Expression; + } + + export interface BreakOrContinueStatement extends Statement { + label?: Identifier; + } + + export interface ReturnStatement extends Statement { + expression?: Expression; + } + + export interface WithStatement extends Statement { + expression: Expression; + statement: Statement; + } + + export interface SwitchStatement extends Statement { + expression: Expression; + caseBlock: CaseBlock; + } + + export interface CaseBlock extends Node { + clauses: NodeArray; + } + + export interface CaseClause extends Node { + expression?: Expression; + statements: NodeArray; + } + + export interface DefaultClause extends Node { + statements: NodeArray; + } + + export type CaseOrDefaultClause = CaseClause | DefaultClause; + + export interface LabeledStatement extends Statement { + label: Identifier; + statement: Statement; + } + + export interface ThrowStatement extends Statement { + expression: Expression; + } + + export interface TryStatement extends Statement { + tryBlock: Block; + catchClause?: CatchClause; + finallyBlock?: Block; + } + + export interface CatchClause extends Node { + variableDeclaration: VariableDeclaration; + block: Block; + } + + export interface ModuleElement extends Node { + _moduleElementBrand: any; + } + + export interface ClassLikeDeclaration extends Declaration { + name?: Identifier; + typeParameters?: NodeArray; + heritageClauses?: NodeArray; + members: NodeArray; + } + + export interface ClassDeclaration extends ClassLikeDeclaration, Statement { + } + + export interface ClassExpression extends ClassLikeDeclaration, PrimaryExpression { + } + + export interface ClassElement extends Declaration { + _classElementBrand: any; + } + + export interface InterfaceDeclaration extends Declaration, ModuleElement { + name: Identifier; + typeParameters?: NodeArray; + heritageClauses?: NodeArray; + members: NodeArray; + } + + export interface HeritageClause extends Node { + token: SyntaxKind; + types?: NodeArray; + } + + export interface TypeAliasDeclaration extends Declaration, ModuleElement { + name: Identifier; + type: TypeNode; + } + + export interface EnumMember extends Declaration { + // This does include ComputedPropertyName, but the parser will give an error + // if it parses a ComputedPropertyName in an EnumMember + name: DeclarationName; + initializer?: Expression; + } + + export interface EnumDeclaration extends Declaration, ModuleElement { + name: Identifier; + members: NodeArray; + } + + export interface ModuleDeclaration extends Declaration, ModuleElement { + name: Identifier | LiteralExpression; + body: ModuleBlock | ModuleDeclaration; + } + + export interface ModuleBlock extends Node, ModuleElement { + statements: NodeArray + } + + export interface ImportEqualsDeclaration extends Declaration, ModuleElement { + name: Identifier; + + // 'EntityName' for an internal module reference, 'ExternalModuleReference' for an external + // module reference. + moduleReference: EntityName | ExternalModuleReference; + } + + export interface ExternalModuleReference extends Node { + expression?: Expression; + } + + // In case of: + // import "mod" => importClause = undefined, moduleSpecifier = "mod" + // In rest of the cases, module specifier is string literal corresponding to module + // ImportClause information is shown at its declaration below. + export interface ImportDeclaration extends ModuleElement { + importClause?: ImportClause; + moduleSpecifier: Expression; + } + + // In case of: + // import d from "mod" => name = d, namedBinding = undefined + // import * as ns from "mod" => name = undefined, namedBinding: NamespaceImport = { name: ns } + // import d, * as ns from "mod" => name = d, namedBinding: NamespaceImport = { name: ns } + // import { a, b as x } from "mod" => name = undefined, namedBinding: NamedImports = { elements: [{ name: a }, { name: x, propertyName: b}]} + // import d, { a, b as x } from "mod" => name = d, namedBinding: NamedImports = { elements: [{ name: a }, { name: x, propertyName: b}]} + export interface ImportClause extends Declaration { + name?: Identifier; // Default binding + namedBindings?: NamespaceImport | NamedImports; + } + + export interface NamespaceImport extends Declaration { + name: Identifier; + } + + export interface ExportDeclaration extends Declaration, ModuleElement { + exportClause?: NamedExports; + moduleSpecifier?: Expression; + } + + export interface NamedImportsOrExports extends Node { + elements: NodeArray; + } + + export type NamedImports = NamedImportsOrExports; + export type NamedExports = NamedImportsOrExports; + + export interface ImportOrExportSpecifier extends Declaration { + propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent) + name: Identifier; // Declared name + } + + export type ImportSpecifier = ImportOrExportSpecifier; + export type ExportSpecifier = ImportOrExportSpecifier; + + export interface ExportAssignment extends Declaration, ModuleElement { + isExportEquals?: boolean; + expression: Expression; + } + + export interface FileReference extends TextRange { + fileName: string; + } + + export interface CommentRange extends TextRange { + hasTrailingNewLine?: boolean; + kind: SyntaxKind; + } + + // Source files are declarations when they are external modules. + export interface SourceFile extends Declaration { + statements: NodeArray; + endOfFileToken: Node; + + fileName: string; + text: string; + + amdDependencies: {path: string; name: string}[]; + amdModuleName: string; + referencedFiles: FileReference[]; + + hasNoDefaultLib: boolean; + + languageVersion: ScriptTarget; + + // The first node that causes this file to be an external module + /* @internal */ externalModuleIndicator: Node; + + /* @internal */ identifiers: Map; + /* @internal */ nodeCount: number; + /* @internal */ identifierCount: number; + /* @internal */ symbolCount: number; + + // File level diagnostics reported by the parser (includes diagnostics about /// references + // as well as code diagnostics). + /* @internal */ parseDiagnostics: Diagnostic[]; + + // File level diagnostics reported by the binder. + /* @internal */ bindDiagnostics: Diagnostic[]; + + // Stores a line map for the file. + // This field should never be used directly to obtain line map, use getLineMap function instead. + /* @internal */ lineMap: number[]; + } + + export interface ScriptReferenceHost { + getCompilerOptions(): CompilerOptions; + getSourceFile(fileName: string): SourceFile; + getCurrentDirectory(): string; + } + + export interface ParseConfigHost { + readDirectory(rootDir: string, extension: string): string[]; + } + + export interface WriteFileCallback { + (fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void): void; + } + + export interface Program extends ScriptReferenceHost { + /** + * Get a list of files in the program + */ + getSourceFiles(): SourceFile[]; + + /** + * Emits the JavaScript and declaration files. If targetSourceFile is not specified, then + * the JavaScript and declaration files will be produced for all the files in this program. + * If targetSourceFile is specified, then only the JavaScript and declaration for that + * specific file will be generated. + * + * If writeFile is not specified then the writeFile callback from the compiler host will be + * used for writing the JavaScript and declaration files. Otherwise, the writeFile parameter + * will be invoked when writing the JavaScript and declaration files. + */ + emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult; + + getSyntacticDiagnostics(sourceFile?: SourceFile): Diagnostic[]; + getGlobalDiagnostics(): Diagnostic[]; + getSemanticDiagnostics(sourceFile?: SourceFile): Diagnostic[]; + getDeclarationDiagnostics(sourceFile?: SourceFile): Diagnostic[]; + + /** + * Gets a type checker that can be used to semantically analyze source fils in the program. + */ + getTypeChecker(): TypeChecker; + + /* @internal */ getCommonSourceDirectory(): string; + + // For testing purposes only. Should not be used by any other consumers (including the + // language service). + /* @internal */ getDiagnosticsProducingTypeChecker(): TypeChecker; + + /* @internal */ getNodeCount(): number; + /* @internal */ getIdentifierCount(): number; + /* @internal */ getSymbolCount(): number; + /* @internal */ getTypeCount(): number; + } + + export interface SourceMapSpan { + /** Line number in the .js file. */ + emittedLine: number; + /** Column number in the .js file. */ + emittedColumn: number; + /** Line number in the .ts file. */ + sourceLine: number; + /** Column number in the .ts file. */ + sourceColumn: number; + /** Optional name (index into names array) associated with this span. */ + nameIndex?: number; + /** .ts file (index into sources array) associated with this span */ + sourceIndex: number; + } + + export interface SourceMapData { + sourceMapFilePath: string; // Where the sourcemap file is written + jsSourceMappingURL: string; // source map URL written in the .js file + sourceMapFile: string; // Source map's file field - .js file name + sourceMapSourceRoot: string; // Source map's sourceRoot field - location where the sources will be present if not "" + sourceMapSources: string[]; // Source map's sources field - list of sources that can be indexed in this source map + inputSourceFileNames: string[]; // Input source file (which one can use on program to get the file), 1:1 mapping with the sourceMapSources list + sourceMapNames?: string[]; // Source map's names field - list of names that can be indexed in this source map + sourceMapMappings: string; // Source map's mapping field - encoded source map spans + sourceMapDecodedMappings: SourceMapSpan[]; // Raw source map spans that were encoded into the sourceMapMappings + } + + /** Return code used by getEmitOutput function to indicate status of the function */ + export enum ExitStatus { + // Compiler ran successfully. Either this was a simple do-nothing compilation (for example, + // when -version or -help was provided, or this was a normal compilation, no diagnostics + // were produced, and all outputs were generated successfully. + Success = 0, + + // Diagnostics were produced and because of them no code was generated. + DiagnosticsPresent_OutputsSkipped = 1, + + // Diagnostics were produced and outputs were generated in spite of them. + DiagnosticsPresent_OutputsGenerated = 2, + } + + export interface EmitResult { + emitSkipped: boolean; + diagnostics: Diagnostic[]; + /* @internal */ sourceMaps: SourceMapData[]; // Array of sourceMapData if compiler emitted sourcemaps + } + + export interface TypeCheckerHost { + getCompilerOptions(): CompilerOptions; + + getSourceFiles(): SourceFile[]; + getSourceFile(fileName: string): SourceFile; + } + + export interface TypeChecker { + getTypeOfSymbolAtLocation(symbol: Symbol, node: Node): Type; + getDeclaredTypeOfSymbol(symbol: Symbol): Type; + getPropertiesOfType(type: Type): Symbol[]; + getPropertyOfType(type: Type, propertyName: string): Symbol; + getSignaturesOfType(type: Type, kind: SignatureKind): Signature[]; + getIndexTypeOfType(type: Type, kind: IndexKind): Type; + getReturnTypeOfSignature(signature: Signature): Type; + + getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; + getSymbolAtLocation(node: Node): Symbol; + getShorthandAssignmentValueSymbol(location: Node): Symbol; + getTypeAtLocation(node: Node): Type; + typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; + symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string; + getSymbolDisplayBuilder(): SymbolDisplayBuilder; + getFullyQualifiedName(symbol: Symbol): string; + getAugmentedPropertiesOfType(type: Type): Symbol[]; + getRootSymbols(symbol: Symbol): Symbol[]; + getContextualType(node: Expression): Type; + getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature; + getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature; + isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; + isUndefinedSymbol(symbol: Symbol): boolean; + isArgumentsSymbol(symbol: Symbol): boolean; + + getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; + isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean; + getAliasedSymbol(symbol: Symbol): Symbol; + getExportsOfModule(moduleSymbol: Symbol): Symbol[]; + + // Should not be called directly. Should only be accessed through the Program instance. + /* @internal */ getDiagnostics(sourceFile?: SourceFile): Diagnostic[]; + /* @internal */ getGlobalDiagnostics(): Diagnostic[]; + /* @internal */ getEmitResolver(sourceFile?: SourceFile): EmitResolver; + + /* @internal */ getNodeCount(): number; + /* @internal */ getIdentifierCount(): number; + /* @internal */ getSymbolCount(): number; + /* @internal */ getTypeCount(): number; + } + + export interface SymbolDisplayBuilder { + buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; + buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void; + buildSignatureDisplay(signatures: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; + buildParameterDisplay(parameter: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; + buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; + buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags): void; + buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; + buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; + buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; + } + + export interface SymbolWriter { + writeKeyword(text: string): void; + writeOperator(text: string): void; + writePunctuation(text: string): void; + writeSpace(text: string): void; + writeStringLiteral(text: string): void; + writeParameter(text: string): void; + writeSymbol(text: string, symbol: Symbol): void; + writeLine(): void; + increaseIndent(): void; + decreaseIndent(): void; + clear(): void; + + // Called when the symbol writer encounters a symbol to write. Currently only used by the + // declaration emitter to help determine if it should patch up the final declaration file + // with import statements it previously saw (but chose not to emit). + trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void; + } + + export const enum TypeFormatFlags { + None = 0x00000000, + WriteArrayAsGenericType = 0x00000001, // Write Array instead T[] + UseTypeOfFunction = 0x00000002, // Write typeof instead of function type literal + NoTruncation = 0x00000004, // Don't truncate typeToString result + WriteArrowStyleSignature = 0x00000008, // Write arrow style signature + WriteOwnNameForAnyLike = 0x00000010, // Write symbol's own name instead of 'any' for any like types (eg. unknown, __resolving__ etc) + WriteTypeArgumentsOfSignature = 0x00000020, // Write the type arguments instead of type parameters of the signature + InElementType = 0x00000040, // Writing an array or union element type + UseFullyQualifiedType = 0x00000080, // Write out the fully qualified type name (eg. Module.Type, instead of Type) + } + + export const enum SymbolFormatFlags { + None = 0x00000000, + + // Write symbols's type argument if it is instantiated symbol + // eg. class C { p: T } <-- Show p as C.p here + // var a: C; + // var p = a.p; <--- Here p is property of C so show it as C.p instead of just C.p + WriteTypeParametersOrArguments = 0x00000001, + + // Use only external alias information to get the symbol name in the given context + // eg. module m { export class c { } } import x = m.c; + // When this flag is specified m.c will be used to refer to the class instead of alias symbol x + UseOnlyExternalAliasing = 0x00000002, + } + + /* @internal */ + export const enum SymbolAccessibility { + Accessible, + NotAccessible, + CannotBeNamed + } + + /* @internal */ + export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration; + + /* @internal */ + export interface SymbolVisibilityResult { + accessibility: SymbolAccessibility; + aliasesToMakeVisible?: AnyImportSyntax[]; // aliases that need to have this symbol visible + errorSymbolName?: string; // Optional symbol name that results in error + errorNode?: Node; // optional node that results in error + } + + /* @internal */ + export interface SymbolAccessiblityResult extends SymbolVisibilityResult { + errorModuleName?: string // If the symbol is not visible from module, module's name + } + + /* @internal */ + export interface EmitResolver { + hasGlobalName(name: string): boolean; + getExpressionNameSubstitution(node: Identifier, getGeneratedNameForNode: (node: Node) => string): string; + isValueAliasDeclaration(node: Node): boolean; + isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean; + isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; + getNodeCheckFlags(node: Node): NodeCheckFlags; + isDeclarationVisible(node: Declaration): boolean; + collectLinkedAliases(node: Identifier): Node[]; + isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; + writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; + writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; + writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; + isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult; + isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult; + // Returns the constant value this property access resolves to, or 'undefined' for a non-constant + getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; + resolvesToSomeValue(location: Node, name: string): boolean; + getBlockScopedVariableId(node: Identifier): number; + serializeTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[]; + serializeParameterTypesOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): (string | string[])[]; + serializeReturnTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[]; + } + + export const enum SymbolFlags { + FunctionScopedVariable = 0x00000001, // Variable (var) or parameter + BlockScopedVariable = 0x00000002, // A block-scoped variable (let or const) + Property = 0x00000004, // Property or enum member + EnumMember = 0x00000008, // Enum member + Function = 0x00000010, // Function + Class = 0x00000020, // Class + Interface = 0x00000040, // Interface + ConstEnum = 0x00000080, // Const enum + RegularEnum = 0x00000100, // Enum + ValueModule = 0x00000200, // Instantiated module + NamespaceModule = 0x00000400, // Uninstantiated module + TypeLiteral = 0x00000800, // Type Literal + ObjectLiteral = 0x00001000, // Object Literal + Method = 0x00002000, // Method + Constructor = 0x00004000, // Constructor + GetAccessor = 0x00008000, // Get accessor + SetAccessor = 0x00010000, // Set accessor + Signature = 0x00020000, // Call, construct, or index signature + TypeParameter = 0x00040000, // Type parameter + TypeAlias = 0x00080000, // Type alias + ExportValue = 0x00100000, // Exported value marker (see comment in declareModuleMember in binder) + ExportType = 0x00200000, // Exported type marker (see comment in declareModuleMember in binder) + ExportNamespace = 0x00400000, // Exported namespace marker (see comment in declareModuleMember in binder) + Alias = 0x00800000, // An alias for another symbol (see comment in isAliasSymbolDeclaration in checker) + Instantiated = 0x01000000, // Instantiated symbol + Merged = 0x02000000, // Merged symbol (created during program binding) + Transient = 0x04000000, // Transient symbol (created during type check) + Prototype = 0x08000000, // Prototype property (no source representation) + UnionProperty = 0x10000000, // Property in union type + Optional = 0x20000000, // Optional property + ExportStar = 0x40000000, // Export * declaration + + Enum = RegularEnum | ConstEnum, + Variable = FunctionScopedVariable | BlockScopedVariable, + Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor, + Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias, + Namespace = ValueModule | NamespaceModule, + Module = ValueModule | NamespaceModule, + Accessor = GetAccessor | SetAccessor, + + // Variables can be redeclared, but can not redeclare a block-scoped declaration with the + // same name, or any other value that is not a variable, e.g. ValueModule or Class + FunctionScopedVariableExcludes = Value & ~FunctionScopedVariable, + + // Block-scoped declarations are not allowed to be re-declared + // they can not merge with anything in the value space + BlockScopedVariableExcludes = Value, + + ParameterExcludes = Value, + PropertyExcludes = Value, + EnumMemberExcludes = Value, + FunctionExcludes = Value & ~(Function | ValueModule), + ClassExcludes = (Value | Type) & ~ValueModule, + InterfaceExcludes = Type & ~Interface, + RegularEnumExcludes = (Value | Type) & ~(RegularEnum | ValueModule), // regular enums merge only with regular enums and modules + ConstEnumExcludes = (Value | Type) & ~ConstEnum, // const enums merge only with const enums + ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule), + NamespaceModuleExcludes = 0, + MethodExcludes = Value & ~Method, + GetAccessorExcludes = Value & ~SetAccessor, + SetAccessorExcludes = Value & ~GetAccessor, + TypeParameterExcludes = Type & ~TypeParameter, + TypeAliasExcludes = Type, + AliasExcludes = Alias, + + ModuleMember = Variable | Function | Class | Interface | Enum | Module | TypeAlias | Alias, + + ExportHasLocal = Function | Class | Enum | ValueModule, + + HasLocals = Function | Module | Method | Constructor | Accessor | Signature, + HasExports = Class | Enum | Module, + HasMembers = Class | Interface | TypeLiteral | ObjectLiteral, + + IsContainer = HasLocals | HasExports | HasMembers, + PropertyOrAccessor = Property | Accessor, + Export = ExportNamespace | ExportType | ExportValue, + } + + export interface Symbol { + flags: SymbolFlags; // Symbol flags + name: string; // Name of symbol + /* @internal */ id?: number; // Unique id (used to look up SymbolLinks) + /* @internal */ mergeId?: number; // Merge id (used to look up merged symbol) + declarations?: Declaration[]; // Declarations associated with this symbol + /* @internal */ parent?: Symbol; // Parent symbol + members?: SymbolTable; // Class, interface or literal instance members + exports?: SymbolTable; // Module exports + /* @internal */ exportSymbol?: Symbol; // Exported symbol associated with this symbol + valueDeclaration?: Declaration; // First value declaration of the symbol + /* @internal */ constEnumOnlyModule?: boolean; // True if module contains only const enums or other modules with only const enums + } + + /* @internal */ + export interface SymbolLinks { + target?: Symbol; // Resolved (non-alias) target of an alias + type?: Type; // Type of value symbol + declaredType?: Type; // Type of class, interface, enum, or type parameter + mapper?: TypeMapper; // Type mapper for instantiation alias + referenced?: boolean; // True if alias symbol has been referenced as a value + unionType?: UnionType; // Containing union type for union property + resolvedExports?: SymbolTable; // Resolved exports of module + exportsChecked?: boolean; // True if exports of external module have been checked + } + + /* @internal */ + export interface TransientSymbol extends Symbol, SymbolLinks { } + + export interface SymbolTable { + [index: string]: Symbol; + } + + /* @internal */ + export const enum NodeCheckFlags { + TypeChecked = 0x00000001, // Node has been type checked + LexicalThis = 0x00000002, // Lexical 'this' reference + CaptureThis = 0x00000004, // Lexical 'this' used in body + EmitExtends = 0x00000008, // Emit __extends + SuperInstance = 0x00000010, // Instance 'super' reference + SuperStatic = 0x00000020, // Static 'super' reference + ContextChecked = 0x00000040, // Contextual types have been assigned + + // Values for enum members have been computed, and any errors have been reported for them. + EnumValuesComputed = 0x00000080, + BlockScopedBindingInLoop = 0x00000100, + EmitDecorate = 0x00000200, // Emit __decorate + EmitParam = 0x00000400, // Emit __param helper for decorators + LexicalModuleMergesWithClass = 0x00000800, // Instantiated lexical module declaration is merged with a previous class declaration. + } + + /* @internal */ + export interface NodeLinks { + resolvedType?: Type; // Cached type of type node + resolvedSignature?: Signature; // Cached signature of signature node or call expression + resolvedSymbol?: Symbol; // Cached name resolution result + flags?: NodeCheckFlags; // Set of flags specific to Node + enumMemberValue?: number; // Constant value of enum member + isIllegalTypeReferenceInConstraint?: boolean; // Is type reference in constraint refers to the type parameter from the same list + isVisible?: boolean; // Is this node visible + generatedName?: string; // Generated name for module, enum, or import declaration + generatedNames?: Map; // Generated names table for source file + assignmentChecks?: Map; // Cache of assignment checks + hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context + importOnRightSide?: Symbol; // for import declarations - import that appear on the right side + } + + export const enum TypeFlags { + Any = 0x00000001, + String = 0x00000002, + Number = 0x00000004, + Boolean = 0x00000008, + Void = 0x00000010, + Undefined = 0x00000020, + Null = 0x00000040, + Enum = 0x00000080, // Enum type + StringLiteral = 0x00000100, // String literal type + TypeParameter = 0x00000200, // Type parameter + Class = 0x00000400, // Class + Interface = 0x00000800, // Interface + Reference = 0x00001000, // Generic type reference + Tuple = 0x00002000, // Tuple + Union = 0x00004000, // Union + Anonymous = 0x00008000, // Anonymous + /* @internal */ + FromSignature = 0x00010000, // Created for signature assignment check + ObjectLiteral = 0x00020000, // Originates in an object literal + /* @internal */ + ContainsUndefinedOrNull = 0x00040000, // Type is or contains Undefined or Null type + /* @internal */ + ContainsObjectLiteral = 0x00080000, // Type is or contains object literal type + ESSymbol = 0x00100000, // Type of symbol primitive introduced in ES6 + + /* @internal */ + Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null, + /* @internal */ + Primitive = String | Number | Boolean | ESSymbol | Void | Undefined | Null | StringLiteral | Enum, + StringLike = String | StringLiteral, + NumberLike = Number | Enum, + ObjectType = Class | Interface | Reference | Tuple | Anonymous, + /* @internal */ + RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral + } + + // Properties common to all types + export interface Type { + flags: TypeFlags; // Flags + /* @internal */ id: number; // Unique ID + symbol?: Symbol; // Symbol associated with type (if any) + } + + /* @internal */ + // Intrinsic types (TypeFlags.Intrinsic) + export interface IntrinsicType extends Type { + intrinsicName: string; // Name of intrinsic type + } + + // String literal types (TypeFlags.StringLiteral) + export interface StringLiteralType extends Type { + text: string; // Text of string literal + } + + // Object types (TypeFlags.ObjectType) + export interface ObjectType extends Type { } + + // Class and interface types (TypeFlags.Class and TypeFlags.Interface) + export interface InterfaceType extends ObjectType { + typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic) + } + + export interface InterfaceTypeWithBaseTypes extends InterfaceType { + baseTypes: ObjectType[]; + } + + export interface InterfaceTypeWithDeclaredMembers extends InterfaceType { + declaredProperties: Symbol[]; // Declared members + declaredCallSignatures: Signature[]; // Declared call signatures + declaredConstructSignatures: Signature[]; // Declared construct signatures + declaredStringIndexType: Type; // Declared string index type + declaredNumberIndexType: Type; // Declared numeric index type + } + + // Type references (TypeFlags.Reference) + export interface TypeReference extends ObjectType { + target: GenericType; // Type reference target + typeArguments: Type[]; // Type reference type arguments + } + + // Generic class and interface types + export interface GenericType extends InterfaceType, TypeReference { + /* @internal */ + instantiations: Map; // Generic instantiation cache + } + + export interface TupleType extends ObjectType { + elementTypes: Type[]; // Element types + baseArrayType: TypeReference; // Array where T is best common type of element types + } + + export interface UnionType extends Type { + types: Type[]; // Constituent types + /* @internal */ + reducedType: Type; // Reduced union type (all subtypes removed) + /* @internal */ + resolvedProperties: SymbolTable; // Cache of resolved properties + } + + /* @internal */ + // Resolved object or union type + export interface ResolvedType extends ObjectType, UnionType { + members: SymbolTable; // Properties by name + properties: Symbol[]; // Properties + callSignatures: Signature[]; // Call signatures of type + constructSignatures: Signature[]; // Construct signatures of type + stringIndexType: Type; // String index type + numberIndexType: Type; // Numeric index type + } + + // Type parameters (TypeFlags.TypeParameter) + export interface TypeParameter extends Type { + constraint: Type; // Constraint + /* @internal */ + target?: TypeParameter; // Instantiation target + /* @internal */ + mapper?: TypeMapper; // Instantiation mapper + } + + export const enum SignatureKind { + Call, + Construct, + } + + export interface Signature { + declaration: SignatureDeclaration; // Originating declaration + typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic) + parameters: Symbol[]; // Parameters + /* @internal */ + resolvedReturnType: Type; // Resolved return type + /* @internal */ + minArgumentCount: number; // Number of non-optional parameters + /* @internal */ + hasRestParameter: boolean; // True if last parameter is rest parameter + /* @internal */ + hasStringLiterals: boolean; // True if specialized + /* @internal */ + target?: Signature; // Instantiation target + /* @internal */ + mapper?: TypeMapper; // Instantiation mapper + /* @internal */ + unionSignatures?: Signature[]; // Underlying signatures of a union signature + /* @internal */ + erasedSignatureCache?: Signature; // Erased version of signature (deferred) + /* @internal */ + isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison + } + + export const enum IndexKind { + String, + Number, + } + + /* @internal */ + export interface TypeMapper { + (t: TypeParameter): Type; + } + + /* @internal */ + export interface TypeInferences { + primary: Type[]; // Inferences made directly to a type parameter + secondary: Type[]; // Inferences made to a type parameter in a union type + isFixed: boolean; // Whether the type parameter is fixed, as defined in section 4.12.2 of the TypeScript spec + // If a type parameter is fixed, no more inferences can be made for the type parameter + } + + /* @internal */ + export interface InferenceContext { + typeParameters: TypeParameter[]; // Type parameters for which inferences are made + inferUnionTypes: boolean; // Infer union types for disjoint candidates (otherwise undefinedType) + inferences: TypeInferences[]; // Inferences made for each type parameter + inferredTypes: Type[]; // Inferred type for each type parameter + failedTypeParameterIndex?: number; // Index of type parameter for which inference failed + // It is optional because in contextual signature instantiation, nothing fails + } + + export interface DiagnosticMessage { + key: string; + category: DiagnosticCategory; + code: number; + } + + /** + * A linked list of formatted diagnostic messages to be used as part of a multiline message. + * It is built from the bottom up, leaving the head to be the "main" diagnostic. + * While it seems that DiagnosticMessageChain is structurally similar to DiagnosticMessage, + * the difference is that messages are all preformatted in DMC. + */ + export interface DiagnosticMessageChain { + messageText: string; + category: DiagnosticCategory; + code: number; + next?: DiagnosticMessageChain; + } + + export interface Diagnostic { + file: SourceFile; + start: number; + length: number; + messageText: string | DiagnosticMessageChain; + category: DiagnosticCategory; + code: number; + } + + export enum DiagnosticCategory { + Warning, + Error, + Message, + } + + export interface CompilerOptions { + allowNonTsExtensions?: boolean; + charset?: string; + declaration?: boolean; + diagnostics?: boolean; + emitBOM?: boolean; + help?: boolean; + listFiles?: boolean; + locale?: string; + mapRoot?: string; + module?: ModuleKind; + noEmit?: boolean; + noEmitOnError?: boolean; + noErrorTruncation?: boolean; + noImplicitAny?: boolean; + noLib?: boolean; + noResolve?: boolean; + out?: string; + outDir?: string; + preserveConstEnums?: boolean; + project?: string; + removeComments?: boolean; + rootDir?: string; + sourceMap?: boolean; + sourceRoot?: string; + suppressImplicitAnyIndexErrors?: boolean; + target?: ScriptTarget; + version?: boolean; + watch?: boolean; + separateCompilation?: boolean; + emitDecoratorMetadata?: boolean; + /* @internal */ stripInternal?: boolean; + [option: string]: string | number | boolean; + } + + export const enum ModuleKind { + None = 0, + CommonJS = 1, + AMD = 2, + UMD = 3, + } + + export interface LineAndCharacter { + line: number; + /* + * This value denotes the character position in line and is different from the 'column' because of tab characters. + */ + character: number; + } + + export const enum ScriptTarget { + ES3 = 0, + ES5 = 1, + ES6 = 2, + Latest = ES6, + } + + export interface ParsedCommandLine { + options: CompilerOptions; + fileNames: string[]; + errors: Diagnostic[]; + } + + /* @internal */ + export interface CommandLineOption { + name: string; + type: string | Map; // "string", "number", "boolean", or an object literal mapping named values to actual values + isFilePath?: boolean; // True if option value is a path or fileName + shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help' + description?: DiagnosticMessage; // The message describing what the command line switch does + paramType?: DiagnosticMessage; // The name to be used for a non-boolean option's parameter + error?: DiagnosticMessage; // The error given when the argument does not fit a customized 'type' + experimental?: boolean; + } + + /* @internal */ + export const enum CharacterCodes { + nullCharacter = 0, + maxAsciiCharacter = 0x7F, + + lineFeed = 0x0A, // \n + carriageReturn = 0x0D, // \r + lineSeparator = 0x2028, + paragraphSeparator = 0x2029, + nextLine = 0x0085, + + // Unicode 3.0 space characters + space = 0x0020, // " " + nonBreakingSpace = 0x00A0, // + enQuad = 0x2000, + emQuad = 0x2001, + enSpace = 0x2002, + emSpace = 0x2003, + threePerEmSpace = 0x2004, + fourPerEmSpace = 0x2005, + sixPerEmSpace = 0x2006, + figureSpace = 0x2007, + punctuationSpace = 0x2008, + thinSpace = 0x2009, + hairSpace = 0x200A, + zeroWidthSpace = 0x200B, + narrowNoBreakSpace = 0x202F, + ideographicSpace = 0x3000, + mathematicalSpace = 0x205F, + ogham = 0x1680, + + _ = 0x5F, + $ = 0x24, + + _0 = 0x30, + _1 = 0x31, + _2 = 0x32, + _3 = 0x33, + _4 = 0x34, + _5 = 0x35, + _6 = 0x36, + _7 = 0x37, + _8 = 0x38, + _9 = 0x39, + + a = 0x61, + b = 0x62, + c = 0x63, + d = 0x64, + e = 0x65, + f = 0x66, + g = 0x67, + h = 0x68, + i = 0x69, + j = 0x6A, + k = 0x6B, + l = 0x6C, + m = 0x6D, + n = 0x6E, + o = 0x6F, + p = 0x70, + q = 0x71, + r = 0x72, + s = 0x73, + t = 0x74, + u = 0x75, + v = 0x76, + w = 0x77, + x = 0x78, + y = 0x79, + z = 0x7A, + + A = 0x41, + B = 0x42, + C = 0x43, + D = 0x44, + E = 0x45, + F = 0x46, + G = 0x47, + H = 0x48, + I = 0x49, + J = 0x4A, + K = 0x4B, + L = 0x4C, + M = 0x4D, + N = 0x4E, + O = 0x4F, + P = 0x50, + Q = 0x51, + R = 0x52, + S = 0x53, + T = 0x54, + U = 0x55, + V = 0x56, + W = 0x57, + X = 0x58, + Y = 0x59, + Z = 0x5a, + + ampersand = 0x26, // & + asterisk = 0x2A, // * + at = 0x40, // @ + backslash = 0x5C, // \ + backtick = 0x60, // ` + bar = 0x7C, // | + caret = 0x5E, // ^ + closeBrace = 0x7D, // } + closeBracket = 0x5D, // ] + closeParen = 0x29, // ) + colon = 0x3A, // : + comma = 0x2C, // , + dot = 0x2E, // . + doubleQuote = 0x22, // " + equals = 0x3D, // = + exclamation = 0x21, // ! + greaterThan = 0x3E, // > + hash = 0x23, // # + lessThan = 0x3C, // < + minus = 0x2D, // - + openBrace = 0x7B, // { + openBracket = 0x5B, // [ + openParen = 0x28, // ( + percent = 0x25, // % + plus = 0x2B, // + + question = 0x3F, // ? + semicolon = 0x3B, // ; + singleQuote = 0x27, // ' + slash = 0x2F, // / + tilde = 0x7E, // ~ + + backspace = 0x08, // \b + formFeed = 0x0C, // \f + byteOrderMark = 0xFEFF, + tab = 0x09, // \t + verticalTab = 0x0B, // \v + } + + export interface CancellationToken { + isCancellationRequested(): boolean; + } + + export interface CompilerHost { + getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile; + getDefaultLibFileName(options: CompilerOptions): string; + getCancellationToken? (): CancellationToken; + writeFile: WriteFileCallback; + getCurrentDirectory(): string; + getCanonicalFileName(fileName: string): string; + useCaseSensitiveFileNames(): boolean; + getNewLine(): string; + } + + export interface TextSpan { + start: number; + length: number; + } + + export interface TextChangeRange { + span: TextSpan; + newLength: number; + } + + /* @internal */ + export interface DiagnosticCollection { + // Adds a diagnostic to this diagnostic collection. + add(diagnostic: Diagnostic): void; + + // Gets all the diagnostics that aren't associated with a file. + getGlobalDiagnostics(): Diagnostic[]; + + // If fileName is provided, gets all the diagnostics associated with that file name. + // Otherwise, returns all the diagnostics (global and file associated) in this colletion. + getDiagnostics(fileName?: string): Diagnostic[]; + + // Gets a count of how many times this collection has been modified. This value changes + // each time 'add' is called (regardless of whether or not an equivalent diagnostic was + // already in the collection). As such, it can be used as a simple way to tell if any + // operation caused diagnostics to be returned by storing and comparing the return value + // of this method before/after the operation is performed. + getModificationCount(): number; + } +} diff --git a/lib/typescript/compiler/utilities.ts b/lib/typescript/compiler/utilities.ts new file mode 100644 index 000000000..6c17c6fc3 --- /dev/null +++ b/lib/typescript/compiler/utilities.ts @@ -0,0 +1,1915 @@ +/// + +/* @internal */ +module ts { + export interface ReferencePathMatchResult { + fileReference?: FileReference + diagnosticMessage?: DiagnosticMessage + isNoDefaultLib?: boolean + } + + export interface SynthesizedNode extends Node { + leadingCommentRanges?: CommentRange[]; + trailingCommentRanges?: CommentRange[]; + startsOnNewLine: boolean; + } + + export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration { + let declarations = symbol.declarations; + for (let declaration of declarations) { + if (declaration.kind === kind) { + return declaration; + } + } + + return undefined; + } + + export interface StringSymbolWriter extends SymbolWriter { + string(): string; + } + + export interface EmitHost extends ScriptReferenceHost { + getSourceFiles(): SourceFile[]; + + getCommonSourceDirectory(): string; + getCanonicalFileName(fileName: string): string; + getNewLine(): string; + + writeFile: WriteFileCallback; + } + + // Pool writers to avoid needing to allocate them for every symbol we write. + let stringWriters: StringSymbolWriter[] = []; + export function getSingleLineStringWriter(): StringSymbolWriter { + if (stringWriters.length == 0) { + let str = ""; + + let writeText: (text: string) => void = text => str += text; + return { + string: () => str, + writeKeyword: writeText, + writeOperator: writeText, + writePunctuation: writeText, + writeSpace: writeText, + writeStringLiteral: writeText, + writeParameter: writeText, + writeSymbol: writeText, + + // Completely ignore indentation for string writers. And map newlines to + // a single space. + writeLine: () => str += " ", + increaseIndent: () => { }, + decreaseIndent: () => { }, + clear: () => str = "", + trackSymbol: () => { } + }; + } + + return stringWriters.pop(); + } + + export function releaseStringWriter(writer: StringSymbolWriter) { + writer.clear() + stringWriters.push(writer); + } + + export function getFullWidth(node: Node) { + return node.end - node.pos; + } + + // Returns true if this node contains a parse error anywhere underneath it. + export function containsParseError(node: Node): boolean { + aggregateChildData(node); + return (node.parserContextFlags & ParserContextFlags.ThisNodeOrAnySubNodesHasError) !== 0 + } + + function aggregateChildData(node: Node): void { + if (!(node.parserContextFlags & ParserContextFlags.HasAggregatedChildData)) { + // A node is considered to contain a parse error if: + // a) the parser explicitly marked that it had an error + // b) any of it's children reported that it had an error. + let thisNodeOrAnySubNodesHasError = ((node.parserContextFlags & ParserContextFlags.ThisNodeHasError) !== 0) || + forEachChild(node, containsParseError); + + // If so, mark ourselves accordingly. + if (thisNodeOrAnySubNodesHasError) { + node.parserContextFlags |= ParserContextFlags.ThisNodeOrAnySubNodesHasError; + } + + // Also mark that we've propogated the child information to this node. This way we can + // always consult the bit directly on this node without needing to check its children + // again. + node.parserContextFlags |= ParserContextFlags.HasAggregatedChildData; + } + } + + export function getSourceFileOfNode(node: Node): SourceFile { + while (node && node.kind !== SyntaxKind.SourceFile) { + node = node.parent; + } + return node; + } + + export function getStartPositionOfLine(line: number, sourceFile: SourceFile): number { + Debug.assert(line >= 0); + return getLineStarts(sourceFile)[line]; + } + + // This is a useful function for debugging purposes. + export function nodePosToString(node: Node): string { + let file = getSourceFileOfNode(node); + let loc = getLineAndCharacterOfPosition(file, node.pos); + return `${ file.fileName }(${ loc.line + 1 },${ loc.character + 1 })`; + } + + export function getStartPosOfNode(node: Node): number { + return node.pos; + } + + // Returns true if this node is missing from the actual source code. 'missing' is different + // from 'undefined/defined'. When a node is undefined (which can happen for optional nodes + // in the tree), it is definitel missing. HOwever, a node may be defined, but still be + // missing. This happens whenever the parser knows it needs to parse something, but can't + // get anything in the source code that it expects at that location. For example: + // + // let a: ; + // + // Here, the Type in the Type-Annotation is not-optional (as there is a colon in the source + // code). So the parser will attempt to parse out a type, and will create an actual node. + // However, this node will be 'missing' in the sense that no actual source-code/tokens are + // contained within it. + export function nodeIsMissing(node: Node) { + if (!node) { + return true; + } + + return node.pos === node.end && node.kind !== SyntaxKind.EndOfFileToken; + } + + export function nodeIsPresent(node: Node) { + return !nodeIsMissing(node); + } + + export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): number { + // With nodes that have no width (i.e. 'Missing' nodes), we actually *don't* + // want to skip trivia because this will launch us forward to the next token. + if (nodeIsMissing(node)) { + return node.pos; + } + + return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos); + } + + export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFile): number { + if (nodeIsMissing(node) || !node.decorators) { + return getTokenPosOfNode(node, sourceFile); + } + + return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.decorators.end); + } + + export function getSourceTextOfNodeFromSourceFile(sourceFile: SourceFile, node: Node): string { + if (nodeIsMissing(node)) { + return ""; + } + + let text = sourceFile.text; + return text.substring(skipTrivia(text, node.pos), node.end); + } + + export function getTextOfNodeFromSourceText(sourceText: string, node: Node): string { + if (nodeIsMissing(node)) { + return ""; + } + + return sourceText.substring(skipTrivia(sourceText, node.pos), node.end); + } + + export function getTextOfNode(node: Node): string { + return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node); + } + + // Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__' + export function escapeIdentifier(identifier: string): string { + return identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier; + } + + // Remove extra underscore from escaped identifier + export function unescapeIdentifier(identifier: string): string { + return identifier.length >= 3 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ && identifier.charCodeAt(2) === CharacterCodes._ ? identifier.substr(1) : identifier; + } + + // Make an identifier from an external module name by extracting the string after the last "/" and replacing + // all non-alphanumeric characters with underscores + export function makeIdentifierFromModuleName(moduleName: string): string { + return getBaseFileName(moduleName).replace(/\W/g, "_"); + } + + export function isBlockOrCatchScoped(declaration: Declaration) { + return (getCombinedNodeFlags(declaration) & NodeFlags.BlockScoped) !== 0 || + isCatchClauseVariableDeclaration(declaration); + } + + // Gets the nearest enclosing block scope container that has the provided node + // as a descendant, that is not the provided node. + export function getEnclosingBlockScopeContainer(node: Node): Node { + let current = node.parent; + while (current) { + if (isFunctionLike(current)) { + return current; + } + switch (current.kind) { + case SyntaxKind.SourceFile: + case SyntaxKind.CaseBlock: + case SyntaxKind.CatchClause: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + return current; + case SyntaxKind.Block: + // function block is not considered block-scope container + // see comment in binder.ts: bind(...), case for SyntaxKind.Block + if (!isFunctionLike(current.parent)) { + return current; + } + } + + current = current.parent; + } + } + + export function isCatchClauseVariableDeclaration(declaration: Declaration) { + return declaration && + declaration.kind === SyntaxKind.VariableDeclaration && + declaration.parent && + declaration.parent.kind === SyntaxKind.CatchClause; + } + + // Return display name of an identifier + // Computed property names will just be emitted as "[]", where is the source + // text of the expression in the computed property. + export function declarationNameToString(name: DeclarationName) { + return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name); + } + + export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): Diagnostic { + let sourceFile = getSourceFileOfNode(node); + let span = getErrorSpanForNode(sourceFile, node); + return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2); + } + + export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain): Diagnostic { + let sourceFile = getSourceFileOfNode(node); + let span = getErrorSpanForNode(sourceFile, node); + return { + file: sourceFile, + start: span.start, + length: span.length, + code: messageChain.code, + category: messageChain.category, + messageText: messageChain.next ? messageChain : messageChain.messageText + }; + } + + export function getSpanOfTokenAtPosition(sourceFile: SourceFile, pos: number): TextSpan { + let scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.text, /*onError:*/ undefined, pos); + scanner.scan(); + let start = scanner.getTokenPos(); + return createTextSpanFromBounds(start, scanner.getTextPos()); + } + + export function getErrorSpanForNode(sourceFile: SourceFile, node: Node): TextSpan { + let errorNode = node; + switch (node.kind) { + case SyntaxKind.SourceFile: + let pos = skipTrivia(sourceFile.text, 0, /*stopAfterLineBreak*/ false); + if (pos === sourceFile.text.length) { + // file is empty - return span for the beginning of the file + return createTextSpan(0, 0); + } + return getSpanOfTokenAtPosition(sourceFile, pos); + // This list is a work in progress. Add missing node kinds to improve their error + // spans. + case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.EnumMember: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + errorNode = (node).name; + break; + } + + if (errorNode === undefined) { + // If we don't have a better node, then just set the error on the first token of + // construct. + return getSpanOfTokenAtPosition(sourceFile, node.pos); + } + + let pos = nodeIsMissing(errorNode) + ? errorNode.pos + : skipTrivia(sourceFile.text, errorNode.pos); + + return createTextSpanFromBounds(pos, errorNode.end); + } + + export function isExternalModule(file: SourceFile): boolean { + return file.externalModuleIndicator !== undefined; + } + + export function isDeclarationFile(file: SourceFile): boolean { + return (file.flags & NodeFlags.DeclarationFile) !== 0; + } + + export function isConstEnumDeclaration(node: Node): boolean { + return node.kind === SyntaxKind.EnumDeclaration && isConst(node); + } + + function walkUpBindingElementsAndPatterns(node: Node): Node { + while (node && (node.kind === SyntaxKind.BindingElement || isBindingPattern(node))) { + node = node.parent; + } + + return node; + } + + // Returns the node flags for this node and all relevant parent nodes. This is done so that + // nodes like variable declarations and binding elements can returned a view of their flags + // that includes the modifiers from their container. i.e. flags like export/declare aren't + // stored on the variable declaration directly, but on the containing variable statement + // (if it has one). Similarly, flags for let/const are store on the variable declaration + // list. By calling this function, all those flags are combined so that the client can treat + // the node as if it actually had those flags. + export function getCombinedNodeFlags(node: Node): NodeFlags { + node = walkUpBindingElementsAndPatterns(node); + + let flags = node.flags; + if (node.kind === SyntaxKind.VariableDeclaration) { + node = node.parent; + } + + if (node && node.kind === SyntaxKind.VariableDeclarationList) { + flags |= node.flags; + node = node.parent; + } + + if (node && node.kind === SyntaxKind.VariableStatement) { + flags |= node.flags; + } + + return flags; + } + + export function isConst(node: Node): boolean { + return !!(getCombinedNodeFlags(node) & NodeFlags.Const); + } + + export function isLet(node: Node): boolean { + return !!(getCombinedNodeFlags(node) & NodeFlags.Let); + } + + export function isPrologueDirective(node: Node): boolean { + return node.kind === SyntaxKind.ExpressionStatement && (node).expression.kind === SyntaxKind.StringLiteral; + } + + export function getLeadingCommentRangesOfNode(node: Node, sourceFileOfNode: SourceFile) { + // If parameter/type parameter, the prev token trailing comments are part of this node too + if (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter) { + // e.g. (/** blah */ a, /** blah */ b); + + // e.g.: ( + // /** blah */ a, + // /** blah */ b); + return concatenate( + getTrailingCommentRanges(sourceFileOfNode.text, node.pos), + getLeadingCommentRanges(sourceFileOfNode.text, node.pos)); + } + else { + return getLeadingCommentRanges(sourceFileOfNode.text, node.pos); + } + } + + export function getJsDocComments(node: Node, sourceFileOfNode: SourceFile) { + return filter(getLeadingCommentRangesOfNode(node, sourceFileOfNode), isJsDocComment); + + function isJsDocComment(comment: CommentRange) { + // True if the comment starts with '/**' but not if it is '/**/' + return sourceFileOfNode.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk && + sourceFileOfNode.text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk && + sourceFileOfNode.text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash; + } + } + + export let fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*/ + + // Warning: This has the same semantics as the forEach family of functions, + // in that traversal terminates in the event that 'visitor' supplies a truthy value. + export function forEachReturnStatement(body: Block, visitor: (stmt: ReturnStatement) => T): T { + + return traverse(body); + + function traverse(node: Node): T { + switch (node.kind) { + case SyntaxKind.ReturnStatement: + return visitor(node); + case SyntaxKind.CaseBlock: + case SyntaxKind.Block: + case SyntaxKind.IfStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + case SyntaxKind.LabeledStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.CatchClause: + return forEachChild(node, traverse); + } + } + } + + export function isVariableLike(node: Node): boolean { + if (node) { + switch (node.kind) { + case SyntaxKind.BindingElement: + case SyntaxKind.EnumMember: + case SyntaxKind.Parameter: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.VariableDeclaration: + return true; + } + } + + return false; + } + + export function isAccessor(node: Node): boolean { + if (node) { + switch (node.kind) { + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return true; + } + } + + return false; + } + + export function isFunctionLike(node: Node): boolean { + if (node) { + switch (node.kind) { + case SyntaxKind.Constructor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionDeclaration: + return true; + } + } + + return false; + } + + export function isFunctionBlock(node: Node) { + return node && node.kind === SyntaxKind.Block && isFunctionLike(node.parent); + } + + export function isObjectLiteralMethod(node: Node) { + return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression; + } + + export function getContainingFunction(node: Node): FunctionLikeDeclaration { + while (true) { + node = node.parent; + if (!node || isFunctionLike(node)) { + return node; + } + } + } + + export function getThisContainer(node: Node, includeArrowFunctions: boolean): Node { + while (true) { + node = node.parent; + if (!node) { + return undefined; + } + switch (node.kind) { + case SyntaxKind.ComputedPropertyName: + // If the grandparent node is an object literal (as opposed to a class), + // then the computed property is not a 'this' container. + // A computed property name in a class needs to be a this container + // so that we can error on it. + if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) { + return node; + } + // If this is a computed property, then the parent should not + // make it a this container. The parent might be a property + // in an object literal, like a method or accessor. But in order for + // such a parent to be a this container, the reference must be in + // the *body* of the container. + node = node.parent; + break; + case SyntaxKind.Decorator: + // Decorators are always applied outside of the body of a class or method. + if (node.parent.kind === SyntaxKind.Parameter && isClassElement(node.parent.parent)) { + // If the decorator's parent is a Parameter, we resolve the this container from + // the grandparent class declaration. + node = node.parent.parent; + } + else if (isClassElement(node.parent)) { + // If the decorator's parent is a class element, we resolve the 'this' container + // from the parent class declaration. + node = node.parent; + } + break; + case SyntaxKind.ArrowFunction: + if (!includeArrowFunctions) { + continue; + } + // Fall through + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.SourceFile: + return node; + } + } + } + + export function getSuperContainer(node: Node, includeFunctions: boolean): Node { + while (true) { + node = node.parent; + if (!node) return node; + switch (node.kind) { + case SyntaxKind.ComputedPropertyName: + // If the grandparent node is an object literal (as opposed to a class), + // then the computed property is not a 'super' container. + // A computed property name in a class needs to be a super container + // so that we can error on it. + if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) { + return node; + } + // If this is a computed property, then the parent should not + // make it a super container. The parent might be a property + // in an object literal, like a method or accessor. But in order for + // such a parent to be a super container, the reference must be in + // the *body* of the container. + node = node.parent; + break; + case SyntaxKind.Decorator: + // Decorators are always applied outside of the body of a class or method. + if (node.parent.kind === SyntaxKind.Parameter && isClassElement(node.parent.parent)) { + // If the decorator's parent is a Parameter, we resolve the this container from + // the grandparent class declaration. + node = node.parent.parent; + } + else if (isClassElement(node.parent)) { + // If the decorator's parent is a class element, we resolve the 'this' container + // from the parent class declaration. + node = node.parent; + } + break; + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + if (!includeFunctions) { + continue; + } + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return node; + } + } + } + + export function getInvokedExpression(node: CallLikeExpression): Expression { + if (node.kind === SyntaxKind.TaggedTemplateExpression) { + return (node).tag; + } + + // Will either be a CallExpression or NewExpression. + return (node).expression; + } + + export function nodeCanBeDecorated(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + // classes are valid targets + return true; + + case SyntaxKind.PropertyDeclaration: + // property declarations are valid if their parent is a class declaration. + return node.parent.kind === SyntaxKind.ClassDeclaration; + + case SyntaxKind.Parameter: + // if the parameter's parent has a body and its grandparent is a class declaration, this is a valid target; + return (node.parent).body && node.parent.parent.kind === SyntaxKind.ClassDeclaration; + + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MethodDeclaration: + // if this method has a body and its parent is a class declaration, this is a valid target. + return (node).body && node.parent.kind === SyntaxKind.ClassDeclaration; + } + + return false; + } + + export function nodeIsDecorated(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + if (node.decorators) { + return true; + } + + return false; + + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.Parameter: + if (node.decorators) { + return true; + } + + return false; + + case SyntaxKind.GetAccessor: + if ((node).body && node.decorators) { + return true; + } + + return false; + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.SetAccessor: + if ((node).body && node.decorators) { + return true; + } + + return false; + } + + return false; + } + + export function childIsDecorated(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + return forEach((node).members, nodeOrChildIsDecorated); + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.SetAccessor: + return forEach((node).parameters, nodeIsDecorated); + } + + return false; + } + + export function nodeOrChildIsDecorated(node: Node): boolean { + return nodeIsDecorated(node) || childIsDecorated(node); + } + + export function isExpression(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.ThisKeyword: + case SyntaxKind.SuperKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + case SyntaxKind.TaggedTemplateExpression: + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ClassExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.VoidExpression: + case SyntaxKind.DeleteExpression: + case SyntaxKind.TypeOfExpression: + case SyntaxKind.PrefixUnaryExpression: + case SyntaxKind.PostfixUnaryExpression: + case SyntaxKind.BinaryExpression: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.SpreadElementExpression: + case SyntaxKind.TemplateExpression: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.OmittedExpression: + return true; + case SyntaxKind.QualifiedName: + while (node.parent.kind === SyntaxKind.QualifiedName) { + node = node.parent; + } + + return node.parent.kind === SyntaxKind.TypeQuery; + case SyntaxKind.Identifier: + if (node.parent.kind === SyntaxKind.TypeQuery) { + return true; + } + // fall through + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + let parent = node.parent; + switch (parent.kind) { + case SyntaxKind.VariableDeclaration: + case SyntaxKind.Parameter: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.EnumMember: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.BindingElement: + return (parent).initializer === node; + case SyntaxKind.ExpressionStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.ReturnStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.CaseClause: + case SyntaxKind.ThrowStatement: + case SyntaxKind.SwitchStatement: + return (parent).expression === node; + case SyntaxKind.ForStatement: + let forStatement = parent; + return (forStatement.initializer === node && forStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) || + forStatement.condition === node || + forStatement.incrementor === node; + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + let forInStatement = parent; + return (forInStatement.initializer === node && forInStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) || + forInStatement.expression === node; + case SyntaxKind.TypeAssertionExpression: + return node === (parent).expression; + case SyntaxKind.TemplateSpan: + return node === (parent).expression; + case SyntaxKind.ComputedPropertyName: + return node === (parent).expression; + case SyntaxKind.Decorator: + return true; + default: + if (isExpression(parent)) { + return true; + } + } + } + return false; + } + + export function isInstantiatedModule(node: ModuleDeclaration, preserveConstEnums: boolean) { + let moduleState = getModuleInstanceState(node) + return moduleState === ModuleInstanceState.Instantiated || + (preserveConstEnums && moduleState === ModuleInstanceState.ConstEnumOnly); + } + + export function isExternalModuleImportEqualsDeclaration(node: Node) { + return node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind === SyntaxKind.ExternalModuleReference; + } + + export function getExternalModuleImportEqualsDeclarationExpression(node: Node) { + Debug.assert(isExternalModuleImportEqualsDeclaration(node)); + return ((node).moduleReference).expression; + } + + export function isInternalModuleImportEqualsDeclaration(node: Node) { + return node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind !== SyntaxKind.ExternalModuleReference; + } + + export function getExternalModuleName(node: Node): Expression { + if (node.kind === SyntaxKind.ImportDeclaration) { + return (node).moduleSpecifier; + } + if (node.kind === SyntaxKind.ImportEqualsDeclaration) { + let reference = (node).moduleReference; + if (reference.kind === SyntaxKind.ExternalModuleReference) { + return (reference).expression; + } + } + if (node.kind === SyntaxKind.ExportDeclaration) { + return (node).moduleSpecifier; + } + } + + export function hasDotDotDotToken(node: Node) { + return node && node.kind === SyntaxKind.Parameter && (node).dotDotDotToken !== undefined; + } + + export function hasQuestionToken(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.Parameter: + return (node).questionToken !== undefined; + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + return (node).questionToken !== undefined; + case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + return (node).questionToken !== undefined; + } + } + + return false; + } + + export function hasRestParameters(s: SignatureDeclaration): boolean { + return s.parameters.length > 0 && s.parameters[s.parameters.length - 1].dotDotDotToken !== undefined; + } + + export function isLiteralKind(kind: SyntaxKind): boolean { + return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken; + } + + export function isTextualLiteralKind(kind: SyntaxKind): boolean { + return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NoSubstitutionTemplateLiteral; + } + + export function isTemplateLiteralKind(kind: SyntaxKind): boolean { + return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken; + } + + export function isBindingPattern(node: Node) { + return !!node && (node.kind === SyntaxKind.ArrayBindingPattern || node.kind === SyntaxKind.ObjectBindingPattern); + } + + export function isInAmbientContext(node: Node): boolean { + while (node) { + if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) { + return true; + } + + node = node.parent; + } + return false; + } + + export function isDeclaration(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.ArrowFunction: + case SyntaxKind.BindingElement: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.Constructor: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.EnumMember: + case SyntaxKind.ExportSpecifier: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.GetAccessor: + case SyntaxKind.ImportClause: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.NamespaceImport: + case SyntaxKind.Parameter: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.SetAccessor: + case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.TypeParameter: + case SyntaxKind.VariableDeclaration: + return true; + } + return false; + } + + export function isStatement(n: Node): boolean { + switch (n.kind) { + case SyntaxKind.BreakStatement: + case SyntaxKind.ContinueStatement: + case SyntaxKind.DebuggerStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.ExpressionStatement: + case SyntaxKind.EmptyStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.LabeledStatement: + case SyntaxKind.ReturnStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.ThrowKeyword: + case SyntaxKind.TryStatement: + case SyntaxKind.VariableStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.ExportAssignment: + return true; + default: + return false; + } + } + + export function isClassElement(n: Node): boolean { + switch (n.kind) { + case SyntaxKind.Constructor: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MethodSignature: + case SyntaxKind.IndexSignature: + return true; + default: + return false; + } + } + + // True if the given identifier, string literal, or number literal is the name of a declaration node + export function isDeclarationName(name: Node): boolean { + if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.StringLiteral && name.kind !== SyntaxKind.NumericLiteral) { + return false; + } + + let parent = name.parent; + if (parent.kind === SyntaxKind.ImportSpecifier || parent.kind === SyntaxKind.ExportSpecifier) { + if ((parent).propertyName) { + return true; + } + } + + if (isDeclaration(parent)) { + return (parent).name === name; + } + + return false; + } + + // An alias symbol is created by one of the following declarations: + // import = ... + // import from ... + // import * as from ... + // import { x as } from ... + // export { x as } from ... + // export = ... + // export default ... + export function isAliasSymbolDeclaration(node: Node): boolean { + return node.kind === SyntaxKind.ImportEqualsDeclaration || + node.kind === SyntaxKind.ImportClause && !!(node).name || + node.kind === SyntaxKind.NamespaceImport || + node.kind === SyntaxKind.ImportSpecifier || + node.kind === SyntaxKind.ExportSpecifier || + node.kind === SyntaxKind.ExportAssignment && (node).expression.kind === SyntaxKind.Identifier; + } + + export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration) { + let heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword); + return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined; + } + + export function getClassImplementsHeritageClauseElements(node: ClassDeclaration) { + let heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ImplementsKeyword); + return heritageClause ? heritageClause.types : undefined; + } + + export function getInterfaceBaseTypeNodes(node: InterfaceDeclaration) { + let heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword); + return heritageClause ? heritageClause.types : undefined; + } + + export function getHeritageClause(clauses: NodeArray, kind: SyntaxKind) { + if (clauses) { + for (let clause of clauses) { + if (clause.token === kind) { + return clause; + } + } + } + + return undefined; + } + + export function tryResolveScriptReference(host: ScriptReferenceHost, sourceFile: SourceFile, reference: FileReference) { + if (!host.getCompilerOptions().noResolve) { + let referenceFileName = isRootedDiskPath(reference.fileName) ? reference.fileName : combinePaths(getDirectoryPath(sourceFile.fileName), reference.fileName); + referenceFileName = getNormalizedAbsolutePath(referenceFileName, host.getCurrentDirectory()); + return host.getSourceFile(referenceFileName); + } + } + + export function getAncestor(node: Node, kind: SyntaxKind): Node { + while (node) { + if (node.kind === kind) { + return node; + } + node = node.parent; + } + return undefined; + } + + export function getFileReferenceFromReferencePath(comment: string, commentRange: CommentRange): ReferencePathMatchResult { + let simpleReferenceRegEx = /^\/\/\/\s*/gim; + if (simpleReferenceRegEx.exec(comment)) { + if (isNoDefaultLibRegEx.exec(comment)) { + return { + isNoDefaultLib: true + } + } + else { + let matchResult = fullTripleSlashReferencePathRegEx.exec(comment); + if (matchResult) { + let start = commentRange.pos; + let end = commentRange.end; + return { + fileReference: { + pos: start, + end: end, + fileName: matchResult[3] + }, + isNoDefaultLib: false + }; + } + else { + return { + diagnosticMessage: Diagnostics.Invalid_reference_directive_syntax, + isNoDefaultLib: false + }; + } + } + } + + return undefined; + } + + export function isKeyword(token: SyntaxKind): boolean { + return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword; + } + + export function isTrivia(token: SyntaxKind) { + return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken; + } + + /** + * A declaration has a dynamic name if both of the following are true: + * 1. The declaration has a computed property name + * 2. The computed name is *not* expressed as Symbol., where name + * is a property of the Symbol constructor that denotes a built in + * Symbol. + */ + export function hasDynamicName(declaration: Declaration): boolean { + return declaration.name && + declaration.name.kind === SyntaxKind.ComputedPropertyName && + !isWellKnownSymbolSyntactically((declaration.name).expression); + } + + /** + * Checks if the expression is of the form: + * Symbol.name + * where Symbol is literally the word "Symbol", and name is any identifierName + */ + export function isWellKnownSymbolSyntactically(node: Expression): boolean { + return node.kind === SyntaxKind.PropertyAccessExpression && isESSymbolIdentifier((node).expression); + } + + export function getPropertyNameForPropertyNameNode(name: DeclarationName): string { + if (name.kind === SyntaxKind.Identifier || name.kind === SyntaxKind.StringLiteral || name.kind === SyntaxKind.NumericLiteral) { + return (name).text; + } + if (name.kind === SyntaxKind.ComputedPropertyName) { + let nameExpression = (name).expression; + if (isWellKnownSymbolSyntactically(nameExpression)) { + let rightHandSideName = (nameExpression).name.text; + return getPropertyNameForKnownSymbolName(rightHandSideName); + } + } + + return undefined; + } + + export function getPropertyNameForKnownSymbolName(symbolName: string): string { + return "__@" + symbolName; + } + + /** + * Includes the word "Symbol" with unicode escapes + */ + export function isESSymbolIdentifier(node: Node): boolean { + return node.kind === SyntaxKind.Identifier && (node).text === "Symbol"; + } + + export function isModifier(token: SyntaxKind): boolean { + switch (token) { + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.StaticKeyword: + case SyntaxKind.ExportKeyword: + case SyntaxKind.DeclareKeyword: + case SyntaxKind.ConstKeyword: + case SyntaxKind.DefaultKeyword: + return true; + } + return false; + } + + export function nodeStartsNewLexicalEnvironment(n: Node): boolean { + return isFunctionLike(n) || n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.SourceFile; + } + + export function nodeIsSynthesized(node: Node): boolean { + return node.pos === -1; + } + + export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node { + let node = createNode(kind); + node.pos = -1; + node.end = -1; + node.startsOnNewLine = startsOnNewLine; + return node; + } + + export function createSynthesizedNodeArray(): NodeArray { + var array = >[]; + array.pos = -1; + array.end = -1; + return array; + } + + export function createDiagnosticCollection(): DiagnosticCollection { + let nonFileDiagnostics: Diagnostic[] = []; + let fileDiagnostics: Map = {}; + + let diagnosticsModified = false; + let modificationCount = 0; + + return { + add, + getGlobalDiagnostics, + getDiagnostics, + getModificationCount + }; + + function getModificationCount() { + return modificationCount; + } + + function add(diagnostic: Diagnostic): void { + let diagnostics: Diagnostic[]; + if (diagnostic.file) { + diagnostics = fileDiagnostics[diagnostic.file.fileName]; + if (!diagnostics) { + diagnostics = []; + fileDiagnostics[diagnostic.file.fileName] = diagnostics; + } + } + else { + diagnostics = nonFileDiagnostics; + } + + diagnostics.push(diagnostic); + diagnosticsModified = true; + modificationCount++; + } + + function getGlobalDiagnostics(): Diagnostic[] { + sortAndDeduplicate(); + return nonFileDiagnostics; + } + + function getDiagnostics(fileName?: string): Diagnostic[] { + sortAndDeduplicate(); + if (fileName) { + return fileDiagnostics[fileName] || []; + } + + let allDiagnostics: Diagnostic[] = []; + function pushDiagnostic(d: Diagnostic) { + allDiagnostics.push(d); + } + + forEach(nonFileDiagnostics, pushDiagnostic); + + for (let key in fileDiagnostics) { + if (hasProperty(fileDiagnostics, key)) { + forEach(fileDiagnostics[key], pushDiagnostic); + } + } + + return sortAndDeduplicateDiagnostics(allDiagnostics); + } + + function sortAndDeduplicate() { + if (!diagnosticsModified) { + return; + } + + diagnosticsModified = false; + nonFileDiagnostics = sortAndDeduplicateDiagnostics(nonFileDiagnostics); + + for (let key in fileDiagnostics) { + if (hasProperty(fileDiagnostics, key)) { + fileDiagnostics[key] = sortAndDeduplicateDiagnostics(fileDiagnostics[key]); + } + } + } + } + + // This consists of the first 19 unprintable ASCII characters, canonical escapes, lineSeparator, + // paragraphSeparator, and nextLine. The latter three are just desirable to suppress new lines in + // the language service. These characters should be escaped when printing, and if any characters are added, + // the map below must be updated. Note that this regexp *does not* include the 'delete' character. + // There is no reason for this other than that JSON.stringify does not handle it either. + let escapedCharsRegExp = /[\\\"\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g; + let escapedCharsMap: Map = { + "\0": "\\0", + "\t": "\\t", + "\v": "\\v", + "\f": "\\f", + "\b": "\\b", + "\r": "\\r", + "\n": "\\n", + "\\": "\\\\", + "\"": "\\\"", + "\u2028": "\\u2028", // lineSeparator + "\u2029": "\\u2029", // paragraphSeparator + "\u0085": "\\u0085" // nextLine + }; + + /** + * Based heavily on the abstract 'Quote'/'QuoteJSONString' operation from ECMA-262 (24.3.2.2), + * but augmented for a few select characters (e.g. lineSeparator, paragraphSeparator, nextLine) + * Note that this doesn't actually wrap the input in double quotes. + */ + export function escapeString(s: string): string { + s = escapedCharsRegExp.test(s) ? s.replace(escapedCharsRegExp, getReplacement) : s; + + return s; + + function getReplacement(c: string) { + return escapedCharsMap[c] || get16BitUnicodeEscapeSequence(c.charCodeAt(0)); + } + } + + function get16BitUnicodeEscapeSequence(charCode: number): string { + let hexCharCode = charCode.toString(16).toUpperCase(); + let paddedHexCode = ("0000" + hexCharCode).slice(-4); + return "\\u" + paddedHexCode; + } + + let nonAsciiCharacters = /[^\u0000-\u007F]/g; + export function escapeNonAsciiCharacters(s: string): string { + // Replace non-ASCII characters with '\uNNNN' escapes if any exist. + // Otherwise just return the original string. + return nonAsciiCharacters.test(s) ? + s.replace(nonAsciiCharacters, c => get16BitUnicodeEscapeSequence(c.charCodeAt(0))) : + s; + } + + export interface EmitTextWriter { + write(s: string): void; + writeTextOfNode(sourceFile: SourceFile, node: Node): void; + writeLine(): void; + increaseIndent(): void; + decreaseIndent(): void; + getText(): string; + rawWrite(s: string): void; + writeLiteral(s: string): void; + getTextPos(): number; + getLine(): number; + getColumn(): number; + getIndent(): number; + } + + let indentStrings: string[] = ["", " "]; + export function getIndentString(level: number) { + if (indentStrings[level] === undefined) { + indentStrings[level] = getIndentString(level - 1) + indentStrings[1]; + } + return indentStrings[level]; + } + + export function getIndentSize() { + return indentStrings[1].length; + } + + export function createTextWriter(newLine: String): EmitTextWriter { + let output = ""; + let indent = 0; + let lineStart = true; + let lineCount = 0; + let linePos = 0; + + function write(s: string) { + if (s && s.length) { + if (lineStart) { + output += getIndentString(indent); + lineStart = false; + } + output += s; + } + } + + function rawWrite(s: string) { + if (s !== undefined) { + if (lineStart) { + lineStart = false; + } + output += s; + } + } + + function writeLiteral(s: string) { + if (s && s.length) { + write(s); + let lineStartsOfS = computeLineStarts(s); + if (lineStartsOfS.length > 1) { + lineCount = lineCount + lineStartsOfS.length - 1; + linePos = output.length - s.length + lineStartsOfS[lineStartsOfS.length - 1]; + } + } + } + + function writeLine() { + if (!lineStart) { + output += newLine; + lineCount++; + linePos = output.length; + lineStart = true; + } + } + + function writeTextOfNode(sourceFile: SourceFile, node: Node) { + write(getSourceTextOfNodeFromSourceFile(sourceFile, node)); + } + + return { + write, + rawWrite, + writeTextOfNode, + writeLiteral, + writeLine, + increaseIndent: () => indent++, + decreaseIndent: () => indent--, + getIndent: () => indent, + getTextPos: () => output.length, + getLine: () => lineCount + 1, + getColumn: () => lineStart ? indent * getIndentSize() + 1 : output.length - linePos + 1, + getText: () => output, + }; + } + + export function getOwnEmitOutputFilePath(sourceFile: SourceFile, host: EmitHost, extension: string) { + let compilerOptions = host.getCompilerOptions(); + let emitOutputFilePathWithoutExtension: string; + if (compilerOptions.outDir) { + emitOutputFilePathWithoutExtension = removeFileExtension(getSourceFilePathInNewDir(sourceFile, host, compilerOptions.outDir)); + } + else { + emitOutputFilePathWithoutExtension = removeFileExtension(sourceFile.fileName); + } + + return emitOutputFilePathWithoutExtension + extension; + } + + export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) { + let sourceFilePath = getNormalizedAbsolutePath(sourceFile.fileName, host.getCurrentDirectory()); + sourceFilePath = sourceFilePath.replace(host.getCommonSourceDirectory(), ""); + return combinePaths(newDirPath, sourceFilePath); + } + + export function writeFile(host: EmitHost, diagnostics: Diagnostic[], fileName: string, data: string, writeByteOrderMark: boolean) { + host.writeFile(fileName, data, writeByteOrderMark, hostErrorMessage => { + diagnostics.push(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage)); + }); + } + + export function getLineOfLocalPosition(currentSourceFile: SourceFile, pos: number) { + return getLineAndCharacterOfPosition(currentSourceFile, pos).line; + } + + export function getFirstConstructorWithBody(node: ClassLikeDeclaration): ConstructorDeclaration { + return forEach(node.members, member => { + if (member.kind === SyntaxKind.Constructor && nodeIsPresent((member).body)) { + return member; + } + }); + } + + export function shouldEmitToOwnFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean { + if (!isDeclarationFile(sourceFile)) { + if ((isExternalModule(sourceFile) || !compilerOptions.out) && !fileExtensionIs(sourceFile.fileName, ".js")) { + return true; + } + return false; + } + return false; + } + + export function getAllAccessorDeclarations(declarations: NodeArray, accessor: AccessorDeclaration) { + let firstAccessor: AccessorDeclaration; + let secondAccessor: AccessorDeclaration; + let getAccessor: AccessorDeclaration; + let setAccessor: AccessorDeclaration; + if (hasDynamicName(accessor)) { + firstAccessor = accessor; + if (accessor.kind === SyntaxKind.GetAccessor) { + getAccessor = accessor; + } + else if (accessor.kind === SyntaxKind.SetAccessor) { + setAccessor = accessor; + } + else { + Debug.fail("Accessor has wrong kind"); + } + } + else { + forEach(declarations, (member: Declaration) => { + if ((member.kind === SyntaxKind.GetAccessor || member.kind === SyntaxKind.SetAccessor) + && (member.flags & NodeFlags.Static) === (accessor.flags & NodeFlags.Static)) { + let memberName = getPropertyNameForPropertyNameNode(member.name); + let accessorName = getPropertyNameForPropertyNameNode(accessor.name); + if (memberName === accessorName) { + if (!firstAccessor) { + firstAccessor = member; + } + else if (!secondAccessor) { + secondAccessor = member; + } + + if (member.kind === SyntaxKind.GetAccessor && !getAccessor) { + getAccessor = member; + } + + if (member.kind === SyntaxKind.SetAccessor && !setAccessor) { + setAccessor = member; + } + } + } + }); + } + return { + firstAccessor, + secondAccessor, + getAccessor, + setAccessor + }; + } + + export function emitNewLineBeforeLeadingComments(currentSourceFile: SourceFile, writer: EmitTextWriter, node: TextRange, leadingComments: CommentRange[]) { + // If the leading comments start on different line than the start of node, write new line + if (leadingComments && leadingComments.length && node.pos !== leadingComments[0].pos && + getLineOfLocalPosition(currentSourceFile, node.pos) !== getLineOfLocalPosition(currentSourceFile, leadingComments[0].pos)) { + writer.writeLine(); + } + } + + export function emitComments(currentSourceFile: SourceFile, writer: EmitTextWriter, comments: CommentRange[], trailingSeparator: boolean, newLine: string, + writeComment: (currentSourceFile: SourceFile, writer: EmitTextWriter, comment: CommentRange, newLine: string) => void) { + let emitLeadingSpace = !trailingSeparator; + forEach(comments, comment => { + if (emitLeadingSpace) { + writer.write(" "); + emitLeadingSpace = false; + } + writeComment(currentSourceFile, writer, comment, newLine); + if (comment.hasTrailingNewLine) { + writer.writeLine(); + } + else if (trailingSeparator) { + writer.write(" "); + } + else { + // Emit leading space to separate comment during next comment emit + emitLeadingSpace = true; + } + }); + } + + export function writeCommentRange(currentSourceFile: SourceFile, writer: EmitTextWriter, comment: CommentRange, newLine: string) { + if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) { + let firstCommentLineAndCharacter = getLineAndCharacterOfPosition(currentSourceFile, comment.pos); + let lineCount = getLineStarts(currentSourceFile).length; + let firstCommentLineIndent: number; + for (let pos = comment.pos, currentLine = firstCommentLineAndCharacter.line; pos < comment.end; currentLine++) { + let nextLineStart = (currentLine + 1) === lineCount + ? currentSourceFile.text.length + 1 + : getStartPositionOfLine(currentLine + 1, currentSourceFile); + + if (pos !== comment.pos) { + // If we are not emitting first line, we need to write the spaces to adjust the alignment + if (firstCommentLineIndent === undefined) { + firstCommentLineIndent = calculateIndent(getStartPositionOfLine(firstCommentLineAndCharacter.line, currentSourceFile), comment.pos); + } + + // These are number of spaces writer is going to write at current indent + let currentWriterIndentSpacing = writer.getIndent() * getIndentSize(); + + // Number of spaces we want to be writing + // eg: Assume writer indent + // module m { + // /* starts at character 9 this is line 1 + // * starts at character pos 4 line --1 = 8 - 8 + 3 + // More left indented comment */ --2 = 8 - 8 + 2 + // class c { } + // } + // module m { + // /* this is line 1 -- Assume current writer indent 8 + // * line --3 = 8 - 4 + 5 + // More right indented comment */ --4 = 8 - 4 + 11 + // class c { } + // } + let spacesToEmit = currentWriterIndentSpacing - firstCommentLineIndent + calculateIndent(pos, nextLineStart); + if (spacesToEmit > 0) { + let numberOfSingleSpacesToEmit = spacesToEmit % getIndentSize(); + let indentSizeSpaceString = getIndentString((spacesToEmit - numberOfSingleSpacesToEmit) / getIndentSize()); + + // Write indent size string ( in eg 1: = "", 2: "" , 3: string with 8 spaces 4: string with 12 spaces + writer.rawWrite(indentSizeSpaceString); + + // Emit the single spaces (in eg: 1: 3 spaces, 2: 2 spaces, 3: 1 space, 4: 3 spaces) + while (numberOfSingleSpacesToEmit) { + writer.rawWrite(" "); + numberOfSingleSpacesToEmit--; + } + } + else { + // No spaces to emit write empty string + writer.rawWrite(""); + } + } + + // Write the comment line text + writeTrimmedCurrentLine(pos, nextLineStart); + + pos = nextLineStart; + } + } + else { + // Single line comment of style //.... + writer.write(currentSourceFile.text.substring(comment.pos, comment.end)); + } + + function writeTrimmedCurrentLine(pos: number, nextLineStart: number) { + let end = Math.min(comment.end, nextLineStart - 1); + let currentLineText = currentSourceFile.text.substring(pos, end).replace(/^\s+|\s+$/g, ''); + if (currentLineText) { + // trimmed forward and ending spaces text + writer.write(currentLineText); + if (end !== comment.end) { + writer.writeLine(); + } + } + else { + // Empty string - make sure we write empty line + writer.writeLiteral(newLine); + } + } + + function calculateIndent(pos: number, end: number) { + let currentLineIndent = 0; + for (; pos < end && isWhiteSpace(currentSourceFile.text.charCodeAt(pos)); pos++) { + if (currentSourceFile.text.charCodeAt(pos) === CharacterCodes.tab) { + // Tabs = TabSize = indent size and go to next tabStop + currentLineIndent += getIndentSize() - (currentLineIndent % getIndentSize()); + } + else { + // Single space + currentLineIndent++; + } + } + + return currentLineIndent; + } + } + + export function modifierToFlag(token: SyntaxKind): NodeFlags { + switch (token) { + case SyntaxKind.StaticKeyword: return NodeFlags.Static; + case SyntaxKind.PublicKeyword: return NodeFlags.Public; + case SyntaxKind.ProtectedKeyword: return NodeFlags.Protected; + case SyntaxKind.PrivateKeyword: return NodeFlags.Private; + case SyntaxKind.ExportKeyword: return NodeFlags.Export; + case SyntaxKind.DeclareKeyword: return NodeFlags.Ambient; + case SyntaxKind.ConstKeyword: return NodeFlags.Const; + case SyntaxKind.DefaultKeyword: return NodeFlags.Default; + } + return 0; + } + + export function isLeftHandSideExpression(expr: Expression): boolean { + if (expr) { + switch (expr.kind) { + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.NewExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.TaggedTemplateExpression: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.ClassExpression: + case SyntaxKind.FunctionExpression: + case SyntaxKind.Identifier: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.TemplateExpression: + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.ThisKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.SuperKeyword: + return true; + } + } + + return false; + } + + export function isAssignmentOperator(token: SyntaxKind): boolean { + return token >= SyntaxKind.FirstAssignment && token <= SyntaxKind.LastAssignment; + } + + // Returns false if this heritage clause element's expression contains something unsupported + // (i.e. not a name or dotted name). + export function isSupportedHeritageClauseElement(node: HeritageClauseElement): boolean { + return isSupportedHeritageClauseElementExpression(node.expression); + } + + function isSupportedHeritageClauseElementExpression(node: Expression): boolean { + if (node.kind === SyntaxKind.Identifier) { + return true; + } + else if (node.kind === SyntaxKind.PropertyAccessExpression) { + return isSupportedHeritageClauseElementExpression((node).expression); + } + else { + return false; + } + } + + export function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) { + return (node.parent.kind === SyntaxKind.QualifiedName && (node.parent).right === node) || + (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent).name === node); + } + + export function getLocalSymbolForExportDefault(symbol: Symbol) { + return symbol && symbol.valueDeclaration && (symbol.valueDeclaration.flags & NodeFlags.Default) ? symbol.valueDeclaration.localSymbol : undefined; + } +} + +module ts { + export function getDefaultLibFileName(options: CompilerOptions): string { + return options.target === ScriptTarget.ES6 ? "lib.es6.d.ts" : "lib.d.ts"; + } + + export function textSpanEnd(span: TextSpan) { + return span.start + span.length + } + + export function textSpanIsEmpty(span: TextSpan) { + return span.length === 0 + } + + export function textSpanContainsPosition(span: TextSpan, position: number) { + return position >= span.start && position < textSpanEnd(span); + } + + // Returns true if 'span' contains 'other'. + export function textSpanContainsTextSpan(span: TextSpan, other: TextSpan) { + return other.start >= span.start && textSpanEnd(other) <= textSpanEnd(span); + } + + export function textSpanOverlapsWith(span: TextSpan, other: TextSpan) { + let overlapStart = Math.max(span.start, other.start); + let overlapEnd = Math.min(textSpanEnd(span), textSpanEnd(other)); + return overlapStart < overlapEnd; + } + + export function textSpanOverlap(span1: TextSpan, span2: TextSpan) { + let overlapStart = Math.max(span1.start, span2.start); + let overlapEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2)); + if (overlapStart < overlapEnd) { + return createTextSpanFromBounds(overlapStart, overlapEnd); + } + return undefined; + } + + export function textSpanIntersectsWithTextSpan(span: TextSpan, other: TextSpan) { + return other.start <= textSpanEnd(span) && textSpanEnd(other) >= span.start + } + + export function textSpanIntersectsWith(span: TextSpan, start: number, length: number) { + let end = start + length; + return start <= textSpanEnd(span) && end >= span.start; + } + + export function textSpanIntersectsWithPosition(span: TextSpan, position: number) { + return position <= textSpanEnd(span) && position >= span.start; + } + + export function textSpanIntersection(span1: TextSpan, span2: TextSpan) { + let intersectStart = Math.max(span1.start, span2.start); + let intersectEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2)); + if (intersectStart <= intersectEnd) { + return createTextSpanFromBounds(intersectStart, intersectEnd); + } + return undefined; + } + + export function createTextSpan(start: number, length: number): TextSpan { + if (start < 0) { + throw new Error("start < 0"); + } + if (length < 0) { + throw new Error("length < 0"); + } + + return { start, length }; + } + + export function createTextSpanFromBounds(start: number, end: number) { + return createTextSpan(start, end - start); + } + + export function textChangeRangeNewSpan(range: TextChangeRange) { + return createTextSpan(range.span.start, range.newLength); + } + + export function textChangeRangeIsUnchanged(range: TextChangeRange) { + return textSpanIsEmpty(range.span) && range.newLength === 0; + } + + export function createTextChangeRange(span: TextSpan, newLength: number): TextChangeRange { + if (newLength < 0) { + throw new Error("newLength < 0"); + } + + return { span, newLength }; + } + + export let unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0); + + /** + * Called to merge all the changes that occurred across several versions of a script snapshot + * into a single change. i.e. if a user keeps making successive edits to a script we will + * have a text change from V1 to V2, V2 to V3, ..., Vn. + * + * This function will then merge those changes into a single change range valid between V1 and + * Vn. + */ + export function collapseTextChangeRangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange { + if (changes.length === 0) { + return unchangedTextChangeRange; + } + + if (changes.length === 1) { + return changes[0]; + } + + // We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd } + // as it makes things much easier to reason about. + let change0 = changes[0]; + + let oldStartN = change0.span.start; + let oldEndN = textSpanEnd(change0.span); + let newEndN = oldStartN + change0.newLength; + + for (let i = 1; i < changes.length; i++) { + let nextChange = changes[i]; + + // Consider the following case: + // i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting + // at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }. + // i.e. the span starting at 30 with length 30 is increased to length 40. + // + // 0 10 20 30 40 50 60 70 80 90 100 + // ------------------------------------------------------------------------------------------------------- + // | / + // | /---- + // T1 | /---- + // | /---- + // | /---- + // ------------------------------------------------------------------------------------------------------- + // | \ + // | \ + // T2 | \ + // | \ + // | \ + // ------------------------------------------------------------------------------------------------------- + // + // Merging these turns out to not be too difficult. First, determining the new start of the change is trivial + // it's just the min of the old and new starts. i.e.: + // + // 0 10 20 30 40 50 60 70 80 90 100 + // ------------------------------------------------------------*------------------------------------------ + // | / + // | /---- + // T1 | /---- + // | /---- + // | /---- + // ----------------------------------------$-------------------$------------------------------------------ + // . | \ + // . | \ + // T2 . | \ + // . | \ + // . | \ + // ----------------------------------------------------------------------*-------------------------------- + // + // (Note the dots represent the newly inferrred start. + // Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the + // absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see + // which if the two $'s precedes the other, and we move that one forward until they line up. in this case that + // means: + // + // 0 10 20 30 40 50 60 70 80 90 100 + // --------------------------------------------------------------------------------*---------------------- + // | / + // | /---- + // T1 | /---- + // | /---- + // | /---- + // ------------------------------------------------------------$------------------------------------------ + // . | \ + // . | \ + // T2 . | \ + // . | \ + // . | \ + // ----------------------------------------------------------------------*-------------------------------- + // + // In other words (in this case), we're recognizing that the second edit happened after where the first edit + // ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started + // that's the same as if we started at char 80 instead of 60. + // + // As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter + // than pusing the first edit forward to match the second, we'll push the second edit forward to match the + // first. + // + // In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange + // semantics: { { start: 10, length: 70 }, newLength: 60 } + // + // The math then works out as follows. + // If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the + // final result like so: + // + // { + // oldStart3: Min(oldStart1, oldStart2), + // oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)), + // newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)) + // } + + let oldStart1 = oldStartN; + let oldEnd1 = oldEndN; + let newEnd1 = newEndN; + + let oldStart2 = nextChange.span.start; + let oldEnd2 = textSpanEnd(nextChange.span); + let newEnd2 = oldStart2 + nextChange.newLength; + + oldStartN = Math.min(oldStart1, oldStart2); + oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)); + newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)); + } + + return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength:*/ newEndN - oldStartN); + } +} diff --git a/lib/typescript/makeTypeScriptGlobal.ts b/lib/typescript/makeTypeScriptGlobal.ts new file mode 100644 index 000000000..d266987a1 --- /dev/null +++ b/lib/typescript/makeTypeScriptGlobal.ts @@ -0,0 +1,61 @@ +// Put the whole of `ts` namespace into the global `ts` variable +// IMPORTANT!!!!!!!!!!!! `diagnosticInformationMap` needs to be before `commandLineParser` +var servicesFiles = [ + "../compiler/core.ts", + "../compiler/sys.ts", + "../compiler/types.ts", + "../compiler/scanner.ts", + "../compiler/parser.ts", + "../compiler/utilities.ts", + "../compiler/binder.ts", + "../compiler/checker.ts", + "../compiler/emitter.ts", + "../compiler/program.ts", + "../compiler/diagnosticInformationMap.generated.ts", + "../compiler/commandLineParser.ts", + "breakpoints.ts", + "navigationBar.ts", + "outliningElementsCollector.ts", + "services.ts", + "shims.ts", + "signatureHelp.ts", + "utilities.ts", + "formatting/formatting.ts", + "formatting/formattingContext.ts", + "formatting/formattingRequestKind.ts", + "formatting/formattingScanner.ts", + "formatting/references.ts", + "formatting/rule.ts", + "formatting/ruleAction.ts", + "formatting/ruleDescriptor.ts", + "formatting/ruleFlag.ts", + "formatting/ruleOperation.ts", + "formatting/ruleOperationContext.ts", + "formatting/rules.ts", + "formatting/rulesMap.ts", + "formatting/rulesProvider.ts", + "formatting/smartIndenter.ts", + "formatting/tokenRange.ts" +]; + + +var files = servicesFiles.map(f=> `./services/${f.replace('.ts', '.js') }`); + +////////////////////////////////// MAGIC +import vm = require('vm'); +import fs = require('fs'); +import path = require('path'); + + +export function makeTsGlobal() { + // This is going to gather the ts module exports + var sandbox = { ts: {} }; + vm.createContext(sandbox); + + files.forEach(f=> { + vm.runInContext(fs.readFileSync(path.resolve(__dirname,f)).toString(), sandbox); + }); + + // Finally export ts to the global namespace + global.ts = sandbox.ts; +} diff --git a/lib/typescript/readme.md b/lib/typescript/readme.md new file mode 100644 index 000000000..f079b4eb0 --- /dev/null +++ b/lib/typescript/readme.md @@ -0,0 +1,22 @@ +# How to update the compiler source +* get a copy of `microsoft/typescript` and checkout `master`. +* Copy the `compiler` and `services` folders from the TypeScript `master` to here. +* Delete the following: + * `compiler/tsc.ts` as that is not a part of `services` proper and is used for command line handling which we don't need. + * `compiler/tsconfig.json` + * `services/tsconfig.json` + + +# Magic +Basically we run `makeTypeScriptGlobal.ts` (both in parent and child) to export `module ts` to the variable `global.ts` so we can just use `ts.` without any imports. +This isn't ideal but if you are willing to do more work to make it easier/safer to use the compiler source send a PR :P. + +# Notes +We list the files in `makeTypeScriptGlobal.ts`, these are basically the `tsconfig.json` files from the `services` folder, with a minor change to preserve the order: + +```ts +"../compiler/diagnosticInformationMap.generated.ts", +"../compiler/commandLineParser.ts", +``` + +as `commandLineParser` depends on stuff from `compiler/diagnosticInformationMap.generated.ts`. We should report this to the TS team. \ No newline at end of file diff --git a/lib/typescript/services/breakpoints.ts b/lib/typescript/services/breakpoints.ts new file mode 100644 index 000000000..36450fd49 --- /dev/null +++ b/lib/typescript/services/breakpoints.ts @@ -0,0 +1,529 @@ +// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. +// See LICENSE.txt in the project root for complete license information. + +/// + +/* @internal */ +module ts.BreakpointResolver { + /** + * Get the breakpoint span in given sourceFile + */ + export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: number) { + // Cannot set breakpoint in dts file + if (sourceFile.flags & NodeFlags.DeclarationFile) { + return undefined; + } + + let tokenAtLocation = getTokenAtPosition(sourceFile, position); + let lineOfPosition = sourceFile.getLineAndCharacterOfPosition(position).line; + if (sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getStart()).line > lineOfPosition) { + // Get previous token if the token is returned starts on new line + // eg: let x =10; |--- cursor is here + // let y = 10; + // token at position will return let keyword on second line as the token but we would like to use + // token on same line if trailing trivia (comments or white spaces on same line) part of the last token on that line + tokenAtLocation = findPrecedingToken(tokenAtLocation.pos, sourceFile); + + // Its a blank line + if (!tokenAtLocation || sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getEnd()).line !== lineOfPosition) { + return undefined; + } + } + + // Cannot set breakpoint in ambient declarations + if (isInAmbientContext(tokenAtLocation)) { + return undefined; + } + + // Get the span in the node based on its syntax + return spanInNode(tokenAtLocation); + + function textSpan(startNode: Node, endNode?: Node) { + return createTextSpanFromBounds(startNode.getStart(), (endNode || startNode).getEnd()); + } + + function spanInNodeIfStartsOnSameLine(node: Node, otherwiseOnNode?: Node): TextSpan { + if (node && lineOfPosition === sourceFile.getLineAndCharacterOfPosition(node.getStart()).line) { + return spanInNode(node); + } + return spanInNode(otherwiseOnNode); + } + + function spanInPreviousNode(node: Node): TextSpan { + return spanInNode(findPrecedingToken(node.pos, sourceFile)); + } + + function spanInNextNode(node: Node): TextSpan { + return spanInNode(findNextToken(node, node.parent)); + } + + function spanInNode(node: Node): TextSpan { + if (node) { + if (isExpression(node)) { + if (node.parent.kind === SyntaxKind.DoStatement) { + // Set span as if on while keyword + return spanInPreviousNode(node); + } + + if (node.parent.kind === SyntaxKind.ForStatement) { + // For now lets set the span on this expression, fix it later + return textSpan(node); + } + + if (node.parent.kind === SyntaxKind.BinaryExpression && (node.parent).operatorToken.kind === SyntaxKind.CommaToken) { + // if this is comma expression, the breakpoint is possible in this expression + return textSpan(node); + } + + if (node.parent.kind == SyntaxKind.ArrowFunction && (node.parent).body == node) { + // If this is body of arrow function, it is allowed to have the breakpoint + return textSpan(node); + } + } + + switch (node.kind) { + case SyntaxKind.VariableStatement: + // Span on first variable declaration + return spanInVariableDeclaration((node).declarationList.declarations[0]); + + case SyntaxKind.VariableDeclaration: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + return spanInVariableDeclaration(node); + + case SyntaxKind.Parameter: + return spanInParameterDeclaration(node); + + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.Constructor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + return spanInFunctionDeclaration(node); + + case SyntaxKind.Block: + if (isFunctionBlock(node)) { + return spanInFunctionBlock(node); + } + // Fall through + case SyntaxKind.ModuleBlock: + return spanInBlock(node); + + case SyntaxKind.CatchClause: + return spanInBlock((node).block); + + case SyntaxKind.ExpressionStatement: + // span on the expression + return textSpan((node).expression); + + case SyntaxKind.ReturnStatement: + // span on return keyword and expression if present + return textSpan(node.getChildAt(0), (node).expression); + + case SyntaxKind.WhileStatement: + // Span on while(...) + return textSpan(node, findNextToken((node).expression, node)); + + case SyntaxKind.DoStatement: + // span in statement of the do statement + return spanInNode((node).statement); + + case SyntaxKind.DebuggerStatement: + // span on debugger keyword + return textSpan(node.getChildAt(0)); + + case SyntaxKind.IfStatement: + // set on if(..) span + return textSpan(node, findNextToken((node).expression, node)); + + case SyntaxKind.LabeledStatement: + // span in statement + return spanInNode((node).statement); + + case SyntaxKind.BreakStatement: + case SyntaxKind.ContinueStatement: + // On break or continue keyword and label if present + return textSpan(node.getChildAt(0), (node).label); + + case SyntaxKind.ForStatement: + return spanInForStatement(node); + + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + // span on for (a in ...) + return textSpan(node, findNextToken((node).expression, node)); + + case SyntaxKind.SwitchStatement: + // span on switch(...) + return textSpan(node, findNextToken((node).expression, node)); + + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + // span in first statement of the clause + return spanInNode((node).statements[0]); + + case SyntaxKind.TryStatement: + // span in try block + return spanInBlock((node).tryBlock); + + case SyntaxKind.ThrowStatement: + // span in throw ... + return textSpan(node, (node).expression); + + case SyntaxKind.ExportAssignment: + // span on export = id + return textSpan(node, (node).expression); + + case SyntaxKind.ImportEqualsDeclaration: + // import statement without including semicolon + return textSpan(node, (node).moduleReference); + + case SyntaxKind.ImportDeclaration: + // import statement without including semicolon + return textSpan(node, (node).moduleSpecifier); + + case SyntaxKind.ExportDeclaration: + // import statement without including semicolon + return textSpan(node, (node).moduleSpecifier); + + case SyntaxKind.ModuleDeclaration: + // span on complete module if it is instantiated + if (getModuleInstanceState(node) !== ModuleInstanceState.Instantiated) { + return undefined; + } + + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.EnumMember: + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + // span on complete node + return textSpan(node); + + case SyntaxKind.WithStatement: + // span in statement + return spanInNode((node).statement); + + // No breakpoint in interface, type alias + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: + return undefined; + + // Tokens: + case SyntaxKind.SemicolonToken: + case SyntaxKind.EndOfFileToken: + return spanInNodeIfStartsOnSameLine(findPrecedingToken(node.pos, sourceFile)); + + case SyntaxKind.CommaToken: + return spanInPreviousNode(node) + + case SyntaxKind.OpenBraceToken: + return spanInOpenBraceToken(node); + + case SyntaxKind.CloseBraceToken: + return spanInCloseBraceToken(node); + + case SyntaxKind.OpenParenToken: + return spanInOpenParenToken(node); + + case SyntaxKind.CloseParenToken: + return spanInCloseParenToken(node); + + case SyntaxKind.ColonToken: + return spanInColonToken(node); + + case SyntaxKind.GreaterThanToken: + case SyntaxKind.LessThanToken: + return spanInGreaterThanOrLessThanToken(node); + + // Keywords: + case SyntaxKind.WhileKeyword: + return spanInWhileKeyword(node); + + case SyntaxKind.ElseKeyword: + case SyntaxKind.CatchKeyword: + case SyntaxKind.FinallyKeyword: + return spanInNextNode(node); + + default: + // If this is name of property assignment, set breakpoint in the initializer + if (node.parent.kind === SyntaxKind.PropertyAssignment && (node.parent).name === node) { + return spanInNode((node.parent).initializer); + } + + // Breakpoint in type assertion goes to its operand + if (node.parent.kind === SyntaxKind.TypeAssertionExpression && (node.parent).type === node) { + return spanInNode((node.parent).expression); + } + + // return type of function go to previous token + if (isFunctionLike(node.parent) && (node.parent).type === node) { + return spanInPreviousNode(node); + } + + // Default go to parent to set the breakpoint + return spanInNode(node.parent); + } + } + + function spanInVariableDeclaration(variableDeclaration: VariableDeclaration): TextSpan { + // If declaration of for in statement, just set the span in parent + if (variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement || + variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement) { + return spanInNode(variableDeclaration.parent.parent); + } + + let isParentVariableStatement = variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement; + let isDeclarationOfForStatement = variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement && contains(((variableDeclaration.parent.parent).initializer).declarations, variableDeclaration); + let declarations = isParentVariableStatement + ? (variableDeclaration.parent.parent).declarationList.declarations + : isDeclarationOfForStatement + ? ((variableDeclaration.parent.parent).initializer).declarations + : undefined; + + // Breakpoint is possible in variableDeclaration only if there is initialization + if (variableDeclaration.initializer || (variableDeclaration.flags & NodeFlags.Export)) { + if (declarations && declarations[0] === variableDeclaration) { + if (isParentVariableStatement) { + // First declaration - include let keyword + return textSpan(variableDeclaration.parent, variableDeclaration); + } + else { + Debug.assert(isDeclarationOfForStatement); + // Include let keyword from for statement declarations in the span + return textSpan(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent), variableDeclaration); + } + } + else { + // Span only on this declaration + return textSpan(variableDeclaration); + } + } + else if (declarations && declarations[0] !== variableDeclaration) { + // If we cant set breakpoint on this declaration, set it on previous one + let indexOfCurrentDeclaration = indexOf(declarations, variableDeclaration); + return spanInVariableDeclaration(declarations[indexOfCurrentDeclaration - 1]); + } + } + + function canHaveSpanInParameterDeclaration(parameter: ParameterDeclaration): boolean { + // Breakpoint is possible on parameter only if it has initializer, is a rest parameter, or has public or private modifier + return !!parameter.initializer || parameter.dotDotDotToken !== undefined || + !!(parameter.flags & NodeFlags.Public) || !!(parameter.flags & NodeFlags.Private); + } + + function spanInParameterDeclaration(parameter: ParameterDeclaration): TextSpan { + if (canHaveSpanInParameterDeclaration(parameter)) { + return textSpan(parameter); + } + else { + let functionDeclaration = parameter.parent; + let indexOfParameter = indexOf(functionDeclaration.parameters, parameter); + if (indexOfParameter) { + // Not a first parameter, go to previous parameter + return spanInParameterDeclaration(functionDeclaration.parameters[indexOfParameter - 1]); + } + else { + // Set breakpoint in the function declaration body + return spanInNode(functionDeclaration.body); + } + } + } + + function canFunctionHaveSpanInWholeDeclaration(functionDeclaration: FunctionLikeDeclaration) { + return !!(functionDeclaration.flags & NodeFlags.Export) || + (functionDeclaration.parent.kind === SyntaxKind.ClassDeclaration && functionDeclaration.kind !== SyntaxKind.Constructor); + } + + function spanInFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration): TextSpan { + // No breakpoints in the function signature + if (!functionDeclaration.body) { + return undefined; + } + + if (canFunctionHaveSpanInWholeDeclaration(functionDeclaration)) { + // Set the span on whole function declaration + return textSpan(functionDeclaration); + } + + // Set span in function body + return spanInNode(functionDeclaration.body); + } + + function spanInFunctionBlock(block: Block): TextSpan { + let nodeForSpanInBlock = block.statements.length ? block.statements[0] : block.getLastToken(); + if (canFunctionHaveSpanInWholeDeclaration(block.parent)) { + return spanInNodeIfStartsOnSameLine(block.parent, nodeForSpanInBlock); + } + + return spanInNode(nodeForSpanInBlock); + } + + function spanInBlock(block: Block): TextSpan { + switch (block.parent.kind) { + case SyntaxKind.ModuleDeclaration: + if (getModuleInstanceState(block.parent) !== ModuleInstanceState.Instantiated) { + return undefined; + } + + // Set on parent if on same line otherwise on first statement + case SyntaxKind.WhileStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + return spanInNodeIfStartsOnSameLine(block.parent, block.statements[0]); + + // Set span on previous token if it starts on same line otherwise on the first statement of the block + case SyntaxKind.ForStatement: + return spanInNodeIfStartsOnSameLine(findPrecedingToken(block.pos, sourceFile, block.parent), block.statements[0]); + } + + // Default action is to set on first statement + return spanInNode(block.statements[0]); + } + + function spanInForStatement(forStatement: ForStatement): TextSpan { + if (forStatement.initializer) { + if (forStatement.initializer.kind === SyntaxKind.VariableDeclarationList) { + let variableDeclarationList = forStatement.initializer; + if (variableDeclarationList.declarations.length > 0) { + return spanInNode(variableDeclarationList.declarations[0]); + } + } + else { + return spanInNode(forStatement.initializer); + } + } + + if (forStatement.condition) { + return textSpan(forStatement.condition); + } + if (forStatement.incrementor) { + return textSpan(forStatement.incrementor); + } + } + + // Tokens: + function spanInOpenBraceToken(node: Node): TextSpan { + switch (node.parent.kind) { + case SyntaxKind.EnumDeclaration: + let enumDeclaration = node.parent; + return spanInNodeIfStartsOnSameLine(findPrecedingToken(node.pos, sourceFile, node.parent), enumDeclaration.members.length ? enumDeclaration.members[0] : enumDeclaration.getLastToken(sourceFile)); + + case SyntaxKind.ClassDeclaration: + let classDeclaration = node.parent; + return spanInNodeIfStartsOnSameLine(findPrecedingToken(node.pos, sourceFile, node.parent), classDeclaration.members.length ? classDeclaration.members[0] : classDeclaration.getLastToken(sourceFile)); + + case SyntaxKind.CaseBlock: + return spanInNodeIfStartsOnSameLine(node.parent.parent, (node.parent).clauses[0]); + } + + // Default to parent node + return spanInNode(node.parent); + } + + function spanInCloseBraceToken(node: Node): TextSpan { + switch (node.parent.kind) { + case SyntaxKind.ModuleBlock: + // If this is not instantiated module block no bp span + if (getModuleInstanceState(node.parent.parent) !== ModuleInstanceState.Instantiated) { + return undefined; + } + + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ClassDeclaration: + // Span on close brace token + return textSpan(node); + + case SyntaxKind.Block: + if (isFunctionBlock(node.parent)) { + // Span on close brace token + return textSpan(node); + } + // fall through. + + case SyntaxKind.CatchClause: + return spanInNode((node.parent).statements[(node.parent).statements.length - 1]);; + + case SyntaxKind.CaseBlock: + // breakpoint in last statement of the last clause + let caseBlock = node.parent; + let lastClause = caseBlock.clauses[caseBlock.clauses.length - 1]; + if (lastClause) { + return spanInNode(lastClause.statements[lastClause.statements.length - 1]); + } + return undefined; + + // Default to parent node + default: + return spanInNode(node.parent); + } + } + + function spanInOpenParenToken(node: Node): TextSpan { + if (node.parent.kind === SyntaxKind.DoStatement) { + // Go to while keyword and do action instead + return spanInPreviousNode(node); + } + + // Default to parent node + return spanInNode(node.parent); + } + + function spanInCloseParenToken(node: Node): TextSpan { + // Is this close paren token of parameter list, set span in previous token + switch (node.parent.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.Constructor: + case SyntaxKind.WhileStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.ForStatement: + return spanInPreviousNode(node); + + // Default to parent node + default: + return spanInNode(node.parent); + } + + // Default to parent node + return spanInNode(node.parent); + } + + function spanInColonToken(node: Node): TextSpan { + // Is this : specifying return annotation of the function declaration + if (isFunctionLike(node.parent) || node.parent.kind === SyntaxKind.PropertyAssignment) { + return spanInPreviousNode(node); + } + + return spanInNode(node.parent); + } + + function spanInGreaterThanOrLessThanToken(node: Node): TextSpan { + if (node.parent.kind === SyntaxKind.TypeAssertionExpression) { + return spanInNode((node.parent).expression); + } + + return spanInNode(node.parent); + } + + function spanInWhileKeyword(node: Node): TextSpan { + if (node.parent.kind === SyntaxKind.DoStatement) { + // Set span on while expression + return textSpan(node, findNextToken((node.parent).expression, node.parent)); + } + + // Default to parent node + return spanInNode(node.parent); + } + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/formatting.ts b/lib/typescript/services/formatting/formatting.ts new file mode 100644 index 000000000..408760231 --- /dev/null +++ b/lib/typescript/services/formatting/formatting.ts @@ -0,0 +1,1114 @@ +/// +/// +/// +/// + +/* @internal */ +module ts.formatting { + + export interface TextRangeWithKind extends TextRange { + kind: SyntaxKind; + } + + export interface TokenInfo { + leadingTrivia: TextRangeWithKind[]; + token: TextRangeWithKind; + trailingTrivia: TextRangeWithKind[]; + } + + const enum Constants { + Unknown = -1 + } + + /* + * Indentation for the scope that can be dynamically recomputed. + * i.e + * while(true) + * { let x; + * } + * Normally indentation is applied only to the first token in line so at glance 'var' should not be touched. + * However if some format rule adds new line between '}' and 'var' 'var' will become + * the first token in line so it should be indented + */ + interface DynamicIndentation { + getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind): number; + getIndentationForComment(owningToken: SyntaxKind): number; + /** + * Indentation for open and close tokens of the node if it is block or another node that needs special indentation + * ... { + * ......... + * ....} + * ____ - indentation + * ____ - delta + **/ + getIndentation(): number; + /** + * Prefered relative indentation for child nodes. + * Delta is used to carry the indentation info + * foo(bar({ + * $ + * })) + * Both 'foo', 'bar' introduce new indentation with delta = 4, but total indentation in $ is not 8. + * foo: { indentation: 0, delta: 4 } + * bar: { indentation: foo.indentation + foo.delta = 4, delta: 4} however 'foo' and 'bar' are on the same line + * so bar inherits indentation from foo and bar.delta will be 4 + * + */ + getDelta(): number; + /** + * Formatter calls this function when rule adds or deletes new lines from the text + * so indentation scope can adjust values of indentation and delta. + */ + recomputeIndentation(lineAddedByFormatting: boolean): void; + } + + interface Indentation { + indentation: number; + delta: number + } + + export function formatOnEnter(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] { + let line = sourceFile.getLineAndCharacterOfPosition(position).line; + if (line === 0) { + return []; + } + // get the span for the previous\current line + let span = { + // get start position for the previous line + pos: getStartPositionOfLine(line - 1, sourceFile), + // get end position for the current line (end value is exclusive so add 1 to the result) + end: getEndLinePosition(line, sourceFile) + 1 + } + return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnEnter); + } + + export function formatOnSemicolon(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] { + return formatOutermostParent(position, SyntaxKind.SemicolonToken, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnSemicolon); + } + + export function formatOnClosingCurly(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] { + return formatOutermostParent(position, SyntaxKind.CloseBraceToken, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnClosingCurlyBrace); + } + + export function formatDocument(sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] { + let span = { + pos: 0, + end: sourceFile.text.length + }; + return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatDocument); + } + + export function formatSelection(start: number, end: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] { + // format from the beginning of the line + let span = { + pos: getLineStartPositionForPosition(start, sourceFile), + end: end + }; + return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatSelection); + } + + function formatOutermostParent(position: number, expectedLastToken: SyntaxKind, sourceFile: SourceFile, options: FormatCodeOptions, rulesProvider: RulesProvider, requestKind: FormattingRequestKind): TextChange[] { + let parent = findOutermostParent(position, expectedLastToken, sourceFile); + if (!parent) { + return []; + } + let span = { + pos: getLineStartPositionForPosition(parent.getStart(sourceFile), sourceFile), + end: parent.end + }; + return formatSpan(span, sourceFile, options, rulesProvider, requestKind); + } + + function findOutermostParent(position: number, expectedTokenKind: SyntaxKind, sourceFile: SourceFile): Node { + let precedingToken = findPrecedingToken(position, sourceFile); + + // when it is claimed that trigger character was typed at given position + // we verify that there is a token with a matching kind whose end is equal to position (because the character was just typed). + // If this condition is not hold - then trigger character was typed in some other context, + // i.e.in comment and thus should not trigger autoformatting + if (!precedingToken || + precedingToken.kind !== expectedTokenKind || + position !== precedingToken.getEnd()) { + return undefined; + } + + // walk up and search for the parent node that ends at the same position with precedingToken. + // for cases like this + // + // let x = 1; + // while (true) { + // } + // after typing close curly in while statement we want to reformat just the while statement. + // However if we just walk upwards searching for the parent that has the same end value - + // we'll end up with the whole source file. isListElement allows to stop on the list element level + let current = precedingToken; + while (current && + current.parent && + current.parent.end === precedingToken.end && + !isListElement(current.parent, current)) { + current = current.parent; + } + + return current; + } + + // Returns true if node is a element in some list in parent + // i.e. parent is class declaration with the list of members and node is one of members. + function isListElement(parent: Node, node: Node): boolean { + switch (parent.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + return rangeContainsRange((parent).members, node); + case SyntaxKind.ModuleDeclaration: + let body = (parent).body; + return body && body.kind === SyntaxKind.Block && rangeContainsRange((body).statements, node); + case SyntaxKind.SourceFile: + case SyntaxKind.Block: + case SyntaxKind.ModuleBlock: + return rangeContainsRange((parent).statements, node); + case SyntaxKind.CatchClause: + return rangeContainsRange((parent).block.statements, node); + } + + return false; + } + + /** find node that fully contains given text range */ + function findEnclosingNode(range: TextRange, sourceFile: SourceFile): Node { + return find(sourceFile); + + function find(n: Node): Node { + let candidate = forEachChild(n, c => startEndContainsRange(c.getStart(sourceFile), c.end, range) && c); + if (candidate) { + let result = find(candidate); + if (result) { + return result; + } + } + + return n; + } + } + + /** formatting is not applied to ranges that contain parse errors. + * This function will return a predicate that for a given text range will tell + * if there are any parse errors that overlap with the range. + */ + function prepareRangeContainsErrorFunction(errors: Diagnostic[], originalRange: TextRange): (r: TextRange) => boolean { + if (!errors.length) { + return rangeHasNoErrors; + } + + // pick only errors that fall in range + let sorted = errors + .filter(d => rangeOverlapsWithStartEnd(originalRange, d.start, d.start + d.length)) + .sort((e1, e2) => e1.start - e2.start); + + if (!sorted.length) { + return rangeHasNoErrors; + } + + let index = 0; + + return r => { + // in current implementation sequence of arguments [r1, r2...] is monotonically increasing. + // 'index' tracks the index of the most recent error that was checked. + while (true) { + if (index >= sorted.length) { + // all errors in the range were already checked -> no error in specified range + return false; + } + + let error = sorted[index]; + if (r.end <= error.start) { + // specified range ends before the error refered by 'index' - no error in range + return false; + } + + if (startEndOverlapsWithStartEnd(r.pos, r.end, error.start, error.start + error.length)) { + // specified range overlaps with error range + return true; + } + + index++; + } + }; + + function rangeHasNoErrors(r: TextRange): boolean { + return false; + } + } + + /** + * Start of the original range might fall inside the comment - scanner will not yield appropriate results + * This function will look for token that is located before the start of target range + * and return its end as start position for the scanner. + */ + function getScanStartPosition(enclosingNode: Node, originalRange: TextRange, sourceFile: SourceFile): number { + let start = enclosingNode.getStart(sourceFile); + if (start === originalRange.pos && enclosingNode.end === originalRange.end) { + return start; + } + + let precedingToken = findPrecedingToken(originalRange.pos, sourceFile); + if (!precedingToken) { + // no preceding token found - start from the beginning of enclosing node + return enclosingNode.pos; + } + + // preceding token ends after the start of original range (i.e when originaRange.pos falls in the middle of literal) + // start from the beginning of enclosingNode to handle the entire 'originalRange' + if (precedingToken.end >= originalRange.pos) { + return enclosingNode.pos; + } + + return precedingToken.end; + } + + /* + * For cases like + * if (a || + * b ||$ + * c) {...} + * If we hit Enter at $ we want line ' b ||' to be indented. + * Formatting will be applied to the last two lines. + * Node that fully encloses these lines is binary expression 'a ||...'. + * Initial indentation for this node will be 0. + * Binary expressions don't introduce new indentation scopes, however it is possible + * that some parent node on the same line does - like if statement in this case. + * Note that we are considering parents only from the same line with initial node - + * if parent is on the different line - its delta was already contributed + * to the initial indentation. + */ + function getOwnOrInheritedDelta(n: Node, options: FormatCodeOptions, sourceFile: SourceFile): number { + let previousLine = Constants.Unknown; + let childKind = SyntaxKind.Unknown; + while (n) { + let line = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)).line; + if (previousLine !== Constants.Unknown && line !== previousLine) { + break; + } + + if (SmartIndenter.shouldIndentChildNode(n.kind, childKind)) { + return options.IndentSize; + } + + previousLine = line; + childKind = n.kind; + n = n.parent; + } + return 0; + } + + function formatSpan(originalRange: TextRange, + sourceFile: SourceFile, + options: FormatCodeOptions, + rulesProvider: RulesProvider, + requestKind: FormattingRequestKind): TextChange[] { + + let rangeContainsError = prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange); + + // formatting context is used by rules provider + let formattingContext = new FormattingContext(sourceFile, requestKind); + + // find the smallest node that fully wraps the range and compute the initial indentation for the node + let enclosingNode = findEnclosingNode(originalRange, sourceFile); + + let formattingScanner = getFormattingScanner(sourceFile, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end); + + let initialIndentation = SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options); + + let previousRangeHasError: boolean; + let previousRange: TextRangeWithKind; + let previousParent: Node; + let previousRangeStartLine: number; + + let edits: TextChange[] = []; + + formattingScanner.advance(); + + if (formattingScanner.isOnToken()) { + let startLine = sourceFile.getLineAndCharacterOfPosition(enclosingNode.getStart(sourceFile)).line; + let undecoratedStartLine = startLine; + if (enclosingNode.decorators) { + undecoratedStartLine = sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(enclosingNode, sourceFile)).line; + } + + let delta = getOwnOrInheritedDelta(enclosingNode, options, sourceFile); + processNode(enclosingNode, enclosingNode, startLine, undecoratedStartLine, initialIndentation, delta); + } + + formattingScanner.close(); + + return edits; + + // local functions + + /** Tries to compute the indentation for a list element. + * If list element is not in range then + * function will pick its actual indentation + * so it can be pushed downstream as inherited indentation. + * If list element is in the range - its indentation will be equal + * to inherited indentation from its predecessors. + */ + function tryComputeIndentationForListItem(startPos: number, + endPos: number, + parentStartLine: number, + range: TextRange, + inheritedIndentation: number): number { + + if (rangeOverlapsWithStartEnd(range, startPos, endPos)) { + if (inheritedIndentation !== Constants.Unknown) { + return inheritedIndentation; + } + } + else { + let startLine = sourceFile.getLineAndCharacterOfPosition(startPos).line; + let startLinePosition = getLineStartPositionForPosition(startPos, sourceFile); + let column = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, startPos, sourceFile, options); + if (startLine !== parentStartLine || startPos === column) { + return column + } + } + + return Constants.Unknown; + } + + function computeIndentation( + node: TextRangeWithKind, + startLine: number, + inheritedIndentation: number, + parent: Node, + parentDynamicIndentation: DynamicIndentation, + effectiveParentStartLine: number): Indentation { + + let indentation = inheritedIndentation; + if (indentation === Constants.Unknown) { + if (isSomeBlock(node.kind)) { + // blocks should be indented in + // - other blocks + // - source file + // - switch\default clauses + if (isSomeBlock(parent.kind) || + parent.kind === SyntaxKind.SourceFile || + parent.kind === SyntaxKind.CaseClause || + parent.kind === SyntaxKind.DefaultClause) { + + indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta(); + } + else { + indentation = parentDynamicIndentation.getIndentation(); + } + } + else { + if (SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile)) { + indentation = parentDynamicIndentation.getIndentation(); + } + else { + indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta(); + } + } + } + + var delta = SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown) ? options.IndentSize : 0; + + if (effectiveParentStartLine === startLine) { + // if node is located on the same line with the parent + // - inherit indentation from the parent + // - push children if either parent of node itself has non-zero delta + indentation = parentDynamicIndentation.getIndentation(); + delta = Math.min(options.IndentSize, parentDynamicIndentation.getDelta() + delta); + } + return { + indentation, + delta + } + } + + function getFirstNonDecoratorTokenOfNode(node: Node) { + if (node.modifiers && node.modifiers.length) { + return node.modifiers[0].kind; + } + switch (node.kind) { + case SyntaxKind.ClassDeclaration: return SyntaxKind.ClassKeyword; + case SyntaxKind.InterfaceDeclaration: return SyntaxKind.InterfaceKeyword; + case SyntaxKind.FunctionDeclaration: return SyntaxKind.FunctionKeyword; + case SyntaxKind.EnumDeclaration: return SyntaxKind.EnumDeclaration; + case SyntaxKind.GetAccessor: return SyntaxKind.GetKeyword; + case SyntaxKind.SetAccessor: return SyntaxKind.SetKeyword; + case SyntaxKind.MethodDeclaration: + if ((node).asteriskToken) { + return SyntaxKind.AsteriskToken; + } + // fall-through + + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.Parameter: + return (node).name.kind; + } + } + + function getDynamicIndentation(node: Node, nodeStartLine: number, indentation: number, delta: number): DynamicIndentation { + return { + getIndentationForComment: kind => { + switch (kind) { + // preceding comment to the token that closes the indentation scope inherits the indentation from the scope + // .. { + // // comment + // } + case SyntaxKind.CloseBraceToken: + case SyntaxKind.CloseBracketToken: + return indentation + delta; + } + return indentation; + }, + getIndentationForToken: (line, kind) => { + if (nodeStartLine !== line && node.decorators) { + if (kind === getFirstNonDecoratorTokenOfNode(node)) { + // if this token is the first token following the list of decorators, we do not need to indent + return indentation; + } + } + switch (kind) { + // open and close brace, 'else' and 'while' (in do statement) tokens has indentation of the parent + case SyntaxKind.OpenBraceToken: + case SyntaxKind.CloseBraceToken: + case SyntaxKind.OpenBracketToken: + case SyntaxKind.CloseBracketToken: + case SyntaxKind.ElseKeyword: + case SyntaxKind.WhileKeyword: + case SyntaxKind.AtToken: + return indentation; + default: + // if token line equals to the line of containing node (this is a first token in the node) - use node indentation + return nodeStartLine !== line ? indentation + delta : indentation; + } + }, + getIndentation: () => indentation, + getDelta: () => delta, + recomputeIndentation: lineAdded => { + if (node.parent && SmartIndenter.shouldIndentChildNode(node.parent.kind, node.kind)) { + if (lineAdded) { + indentation += options.IndentSize; + } + else { + indentation -= options.IndentSize; + } + + if (SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown)) { + delta = options.IndentSize; + } + else { + delta = 0; + } + } + }, + } + } + + function processNode(node: Node, contextNode: Node, nodeStartLine: number, undecoratedNodeStartLine: number, indentation: number, delta: number) { + if (!rangeOverlapsWithStartEnd(originalRange, node.getStart(sourceFile), node.getEnd())) { + return; + } + + let nodeDynamicIndentation = getDynamicIndentation(node, nodeStartLine, indentation, delta); + + // a useful observations when tracking context node + // / + // [a] + // / | \ + // [b] [c] [d] + // node 'a' is a context node for nodes 'b', 'c', 'd' + // except for the leftmost leaf token in [b] - in this case context node ('e') is located somewhere above 'a' + // this rule can be applied recursively to child nodes of 'a'. + // + // context node is set to parent node value after processing every child node + // context node is set to parent of the token after processing every token + + let childContextNode = contextNode; + + // if there are any tokens that logically belong to node and interleave child nodes + // such tokens will be consumed in processChildNode for for the child that follows them + forEachChild( + node, + child => { + processChildNode(child, /*inheritedIndentation*/ Constants.Unknown, node, nodeDynamicIndentation, nodeStartLine, undecoratedNodeStartLine, /*isListElement*/ false) + }, + (nodes: NodeArray) => { + processChildNodes(nodes, node, nodeStartLine, nodeDynamicIndentation); + }); + + // proceed any tokens in the node that are located after child nodes + while (formattingScanner.isOnToken()) { + let tokenInfo = formattingScanner.readTokenInfo(node); + if (tokenInfo.token.end > node.end) { + break; + } + consumeTokenAndAdvanceScanner(tokenInfo, node, nodeDynamicIndentation); + } + + function processChildNode( + child: Node, + inheritedIndentation: number, + parent: Node, + parentDynamicIndentation: DynamicIndentation, + parentStartLine: number, + undecoratedParentStartLine: number, + isListItem: boolean): number { + + let childStartPos = child.getStart(sourceFile); + + let childStartLine = sourceFile.getLineAndCharacterOfPosition(childStartPos).line; + + let undecoratedChildStartLine = childStartLine; + if (child.decorators) { + undecoratedChildStartLine = sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(child, sourceFile)).line; + } + + // if child is a list item - try to get its indentation + let childIndentationAmount = Constants.Unknown; + if (isListItem) { + childIndentationAmount = tryComputeIndentationForListItem(childStartPos, child.end, parentStartLine, originalRange, inheritedIndentation); + if (childIndentationAmount !== Constants.Unknown) { + inheritedIndentation = childIndentationAmount; + } + } + + // child node is outside the target range - do not dive inside + if (!rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) { + return inheritedIndentation; + } + + if (child.getFullWidth() === 0) { + return inheritedIndentation; + } + + while (formattingScanner.isOnToken()) { + // proceed any parent tokens that are located prior to child.getStart() + let tokenInfo = formattingScanner.readTokenInfo(node); + if (tokenInfo.token.end > childStartPos) { + // stop when formatting scanner advances past the beginning of the child + break; + } + + consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation); + } + + if (!formattingScanner.isOnToken()) { + return inheritedIndentation; + } + + if (isToken(child)) { + // if child node is a token, it does not impact indentation, proceed it using parent indentation scope rules + let tokenInfo = formattingScanner.readTokenInfo(child); + Debug.assert(tokenInfo.token.end === child.end); + consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation); + return inheritedIndentation; + } + + let effectiveParentStartLine = child.kind === SyntaxKind.Decorator ? childStartLine : undecoratedParentStartLine; + let childIndentation = computeIndentation(child, childStartLine, childIndentationAmount, node, parentDynamicIndentation, effectiveParentStartLine); + + processNode(child, childContextNode, childStartLine, undecoratedChildStartLine, childIndentation.indentation, childIndentation.delta); + + childContextNode = node; + + return inheritedIndentation; + } + + function processChildNodes(nodes: NodeArray, + parent: Node, + parentStartLine: number, + parentDynamicIndentation: DynamicIndentation): void { + + let listStartToken = getOpenTokenForList(parent, nodes); + let listEndToken = getCloseTokenForOpenToken(listStartToken); + + let listDynamicIndentation = parentDynamicIndentation; + let startLine = parentStartLine; + + if (listStartToken !== SyntaxKind.Unknown) { + // introduce a new indentation scope for lists (including list start and end tokens) + while (formattingScanner.isOnToken()) { + let tokenInfo = formattingScanner.readTokenInfo(parent); + if (tokenInfo.token.end > nodes.pos) { + // stop when formatting scanner moves past the beginning of node list + break; + } + else if (tokenInfo.token.kind === listStartToken) { + // consume list start token + startLine = sourceFile.getLineAndCharacterOfPosition(tokenInfo.token.pos).line; + let indentation = + computeIndentation(tokenInfo.token, startLine, Constants.Unknown, parent, parentDynamicIndentation, startLine); + + listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation.indentation, indentation.delta); + consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation); + } + else { + // consume any tokens that precede the list as child elements of 'node' using its indentation scope + consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation); + } + } + } + + let inheritedIndentation = Constants.Unknown; + for (let child of nodes) { + inheritedIndentation = processChildNode(child, inheritedIndentation, node, listDynamicIndentation, startLine, startLine, /*isListElement*/ true) + } + + if (listEndToken !== SyntaxKind.Unknown) { + if (formattingScanner.isOnToken()) { + let tokenInfo = formattingScanner.readTokenInfo(parent); + // consume the list end token only if it is still belong to the parent + // there might be the case when current token matches end token but does not considered as one + // function (x: function) <-- + // without this check close paren will be interpreted as list end token for function expression which is wrong + if (tokenInfo.token.kind === listEndToken && rangeContainsRange(parent, tokenInfo.token)) { + // consume list end token + consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation); + } + } + } + } + + function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation): void { + Debug.assert(rangeContainsRange(parent, currentTokenInfo.token)); + + let lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine(); + let indentToken = false; + + if (currentTokenInfo.leadingTrivia) { + processTrivia(currentTokenInfo.leadingTrivia, parent, childContextNode, dynamicIndentation); + } + + let lineAdded: boolean; + let isTokenInRange = rangeContainsRange(originalRange, currentTokenInfo.token); + + let tokenStart = sourceFile.getLineAndCharacterOfPosition(currentTokenInfo.token.pos); + if (isTokenInRange) { + let rangeHasError = rangeContainsError(currentTokenInfo.token); + // save prevStartLine since processRange will overwrite this value with current ones + let prevStartLine = previousRangeStartLine; + lineAdded = processRange(currentTokenInfo.token, tokenStart, parent, childContextNode, dynamicIndentation); + if (rangeHasError) { + // do not indent comments\token if token range overlaps with some error + indentToken = false; + } + else { + if (lineAdded !== undefined) { + indentToken = lineAdded; + } + else { + indentToken = lastTriviaWasNewLine && tokenStart.line !== prevStartLine; + } + } + } + + if (currentTokenInfo.trailingTrivia) { + processTrivia(currentTokenInfo.trailingTrivia, parent, childContextNode, dynamicIndentation); + } + + if (indentToken) { + let indentNextTokenOrTrivia = true; + if (currentTokenInfo.leadingTrivia) { + for (let triviaItem of currentTokenInfo.leadingTrivia) { + if (!rangeContainsRange(originalRange, triviaItem)) { + continue; + } + + let triviaStartLine = sourceFile.getLineAndCharacterOfPosition(triviaItem.pos).line; + switch (triviaItem.kind) { + case SyntaxKind.MultiLineCommentTrivia: + let commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind); + indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia); + indentNextTokenOrTrivia = false; + break; + case SyntaxKind.SingleLineCommentTrivia: + if (indentNextTokenOrTrivia) { + let commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind); + insertIndentation(triviaItem.pos, commentIndentation, /*lineAdded*/ false); + indentNextTokenOrTrivia = false; + } + break; + case SyntaxKind.NewLineTrivia: + indentNextTokenOrTrivia = true; + break; + } + } + } + + // indent token only if is it is in target range and does not overlap with any error ranges + if (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) { + let tokenIndentation = dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind); + insertIndentation(currentTokenInfo.token.pos, tokenIndentation, lineAdded); + } + } + + formattingScanner.advance(); + + childContextNode = parent; + } + } + + function processTrivia(trivia: TextRangeWithKind[], parent: Node, contextNode: Node, dynamicIndentation: DynamicIndentation): void { + for (let triviaItem of trivia) { + if (isComment(triviaItem.kind) && rangeContainsRange(originalRange, triviaItem)) { + let triviaItemStart = sourceFile.getLineAndCharacterOfPosition(triviaItem.pos); + processRange(triviaItem, triviaItemStart, parent, contextNode, dynamicIndentation); + } + } + } + + function processRange(range: TextRangeWithKind, + rangeStart: LineAndCharacter, + parent: Node, + contextNode: Node, + dynamicIndentation: DynamicIndentation): boolean { + + let rangeHasError = rangeContainsError(range); + let lineAdded: boolean; + if (!rangeHasError && !previousRangeHasError) { + if (!previousRange) { + // trim whitespaces starting from the beginning of the span up to the current line + let originalStart = sourceFile.getLineAndCharacterOfPosition(originalRange.pos); + trimTrailingWhitespacesForLines(originalStart.line, rangeStart.line); + } + else { + lineAdded = + processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, dynamicIndentation) + } + } + + previousRange = range; + previousParent = parent; + previousRangeStartLine = rangeStart.line; + previousRangeHasError = rangeHasError; + + return lineAdded; + } + + function processPair(currentItem: TextRangeWithKind, + currentStartLine: number, + currentParent: Node, + previousItem: TextRangeWithKind, + previousStartLine: number, + previousParent: Node, + contextNode: Node, + dynamicIndentation: DynamicIndentation): boolean { + + formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode); + + let rule = rulesProvider.getRulesMap().GetRule(formattingContext); + + let trimTrailingWhitespaces: boolean; + let lineAdded: boolean; + if (rule) { + applyRuleEdits(rule, previousItem, previousStartLine, currentItem, currentStartLine); + + if (rule.Operation.Action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) { + lineAdded = false; + // Handle the case where the next line is moved to be the end of this line. + // In this case we don't indent the next line in the next pass. + if (currentParent.getStart(sourceFile) === currentItem.pos) { + dynamicIndentation.recomputeIndentation(/*lineAdded*/ false); + } + } + else if (rule.Operation.Action & RuleAction.NewLine && currentStartLine === previousStartLine) { + lineAdded = true; + // Handle the case where token2 is moved to the new line. + // In this case we indent token2 in the next pass but we set + // sameLineIndent flag to notify the indenter that the indentation is within the line. + if (currentParent.getStart(sourceFile) === currentItem.pos) { + dynamicIndentation.recomputeIndentation(/*lineAdded*/ true); + } + } + + // We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line + trimTrailingWhitespaces = + (rule.Operation.Action & (RuleAction.NewLine | RuleAction.Space)) && + rule.Flag !== RuleFlags.CanDeleteNewLines; + } + else { + trimTrailingWhitespaces = true; + } + + if (currentStartLine !== previousStartLine && trimTrailingWhitespaces) { + // We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line + trimTrailingWhitespacesForLines(previousStartLine, currentStartLine, previousItem); + } + + return lineAdded; + } + + function insertIndentation(pos: number, indentation: number, lineAdded: boolean): void { + let indentationString = getIndentationString(indentation, options); + if (lineAdded) { + // new line is added before the token by the formatting rules + // insert indentation string at the very beginning of the token + recordReplace(pos, 0, indentationString); + } + else { + let tokenStart = sourceFile.getLineAndCharacterOfPosition(pos); + if (indentation !== tokenStart.character) { + let startLinePosition = getStartPositionOfLine(tokenStart.line, sourceFile); + recordReplace(startLinePosition, tokenStart.character, indentationString); + } + } + } + + function indentMultilineComment(commentRange: TextRange, indentation: number, firstLineIsIndented: boolean) { + // split comment in lines + let startLine = sourceFile.getLineAndCharacterOfPosition(commentRange.pos).line; + let endLine = sourceFile.getLineAndCharacterOfPosition(commentRange.end).line; + let parts: TextRange[]; + if (startLine === endLine) { + if (!firstLineIsIndented) { + // treat as single line comment + insertIndentation(commentRange.pos, indentation, /*lineAdded*/ false); + } + return; + } + else { + parts = []; + let startPos = commentRange.pos; + for (let line = startLine; line < endLine; ++line) { + let endOfLine = getEndLinePosition(line, sourceFile); + parts.push({ pos: startPos, end: endOfLine }); + startPos = getStartPositionOfLine(line + 1, sourceFile); + } + + parts.push({ pos: startPos, end: commentRange.end }); + } + + let startLinePos = getStartPositionOfLine(startLine, sourceFile); + + let nonWhitespaceColumnInFirstPart = + SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(startLinePos, parts[0].pos, sourceFile, options); + + if (indentation === nonWhitespaceColumnInFirstPart.column) { + return; + } + + let startIndex = 0; + if (firstLineIsIndented) { + startIndex = 1; + startLine++; + } + + // shift all parts on the delta size + let delta = indentation - nonWhitespaceColumnInFirstPart.column; + for (let i = startIndex, len = parts.length; i < len; ++i, ++startLine) { + let startLinePos = getStartPositionOfLine(startLine, sourceFile); + let nonWhitespaceCharacterAndColumn = + i === 0 + ? nonWhitespaceColumnInFirstPart + : SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(parts[i].pos, parts[i].end, sourceFile, options); + + let newIndentation = nonWhitespaceCharacterAndColumn.column + delta; + if (newIndentation > 0) { + let indentationString = getIndentationString(newIndentation, options); + recordReplace(startLinePos, nonWhitespaceCharacterAndColumn.character, indentationString); + } + else { + recordDelete(startLinePos, nonWhitespaceCharacterAndColumn.character); + } + } + } + + function trimTrailingWhitespacesForLines(line1: number, line2: number, range?: TextRangeWithKind) { + for (let line = line1; line < line2; ++line) { + let lineStartPosition = getStartPositionOfLine(line, sourceFile); + let lineEndPosition = getEndLinePosition(line, sourceFile); + + // do not trim whitespaces in comments + if (range && isComment(range.kind) && range.pos <= lineEndPosition && range.end > lineEndPosition) { + continue; + } + + let pos = lineEndPosition; + while (pos >= lineStartPosition && isWhiteSpace(sourceFile.text.charCodeAt(pos))) { + pos--; + } + if (pos !== lineEndPosition) { + Debug.assert(pos === lineStartPosition || !isWhiteSpace(sourceFile.text.charCodeAt(pos))); + recordDelete(pos + 1, lineEndPosition - pos); + } + } + } + + function newTextChange(start: number, len: number, newText: string): TextChange { + return { span: createTextSpan(start, len), newText } + } + + function recordDelete(start: number, len: number) { + if (len) { + edits.push(newTextChange(start, len, "")); + } + } + + function recordReplace(start: number, len: number, newText: string) { + if (len || newText) { + edits.push(newTextChange(start, len, newText)); + } + } + + function applyRuleEdits(rule: Rule, + previousRange: TextRangeWithKind, + previousStartLine: number, + currentRange: TextRangeWithKind, + currentStartLine: number): void { + + let between: TextRange; + switch (rule.Operation.Action) { + case RuleAction.Ignore: + // no action required + return; + case RuleAction.Delete: + if (previousRange.end !== currentRange.pos) { + // delete characters starting from t1.end up to t2.pos exclusive + recordDelete(previousRange.end, currentRange.pos - previousRange.end); + } + break; + case RuleAction.NewLine: + // exit early if we on different lines and rule cannot change number of newlines + // if line1 and line2 are on subsequent lines then no edits are required - ok to exit + // if line1 and line2 are separated with more than one newline - ok to exit since we cannot delete extra new lines + if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) { + return; + } + + // edit should not be applied only if we have one line feed between elements + let lineDelta = currentStartLine - previousStartLine; + if (lineDelta !== 1) { + recordReplace(previousRange.end, currentRange.pos - previousRange.end, options.NewLineCharacter); + } + break; + case RuleAction.Space: + // exit early if we on different lines and rule cannot change number of newlines + if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) { + return; + } + + let posDelta = currentRange.pos - previousRange.end; + if (posDelta !== 1 || sourceFile.text.charCodeAt(previousRange.end) !== CharacterCodes.space) { + recordReplace(previousRange.end, currentRange.pos - previousRange.end, " "); + } + break; + } + } + } + + function isSomeBlock(kind: SyntaxKind): boolean { + switch (kind) { + case SyntaxKind.Block: + case SyntaxKind.ModuleBlock: + return true; + } + return false; + } + + function getOpenTokenForList(node: Node, list: Node[]) { + switch (node.kind) { + case SyntaxKind.Constructor: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.ArrowFunction: + if ((node).typeParameters === list) { + return SyntaxKind.LessThanToken; + } + else if ((node).parameters === list) { + return SyntaxKind.OpenParenToken; + } + break; + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + if ((node).typeArguments === list) { + return SyntaxKind.LessThanToken; + } + else if ((node).arguments === list) { + return SyntaxKind.OpenParenToken; + } + break; + case SyntaxKind.TypeReference: + if ((node).typeArguments === list) { + return SyntaxKind.LessThanToken; + } + } + + return SyntaxKind.Unknown; + } + + function getCloseTokenForOpenToken(kind: SyntaxKind) { + switch (kind) { + case SyntaxKind.OpenParenToken: + return SyntaxKind.CloseParenToken; + case SyntaxKind.LessThanToken: + return SyntaxKind.GreaterThanToken; + } + + return SyntaxKind.Unknown; + } + + var internedSizes: { tabSize: number; indentSize: number }; + var internedTabsIndentation: string[]; + var internedSpacesIndentation: string[]; + + export function getIndentationString(indentation: number, options: FormatCodeOptions): string { + // reset interned strings if FormatCodeOptions were changed + let resetInternedStrings = + !internedSizes || (internedSizes.tabSize !== options.TabSize || internedSizes.indentSize !== options.IndentSize); + + if (resetInternedStrings) { + internedSizes = { tabSize: options.TabSize, indentSize: options.IndentSize }; + internedTabsIndentation = internedSpacesIndentation = undefined; + } + + if (!options.ConvertTabsToSpaces) { + let tabs = Math.floor(indentation / options.TabSize); + let spaces = indentation - tabs * options.TabSize; + + let tabString: string; + if (!internedTabsIndentation) { + internedTabsIndentation = []; + } + + if (internedTabsIndentation[tabs] === undefined) { + internedTabsIndentation[tabs] = tabString = repeat('\t', tabs); + } + else { + tabString = internedTabsIndentation[tabs]; + } + + return spaces ? tabString + repeat(" ", spaces) : tabString; + } + else { + let spacesString: string; + let quotient = Math.floor(indentation / options.IndentSize); + let remainder = indentation % options.IndentSize; + if (!internedSpacesIndentation) { + internedSpacesIndentation = []; + } + + if (internedSpacesIndentation[quotient] === undefined) { + spacesString = repeat(" ", options.IndentSize * quotient); + internedSpacesIndentation[quotient] = spacesString; + } + else { + spacesString = internedSpacesIndentation[quotient]; + } + + return remainder ? spacesString + repeat(" ", remainder) : spacesString; + } + + function repeat(value: string, count: number): string { + let s = ""; + for (let i = 0; i < count; ++i) { + s += value; + } + + return s; + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/formattingContext.ts b/lib/typescript/services/formatting/formattingContext.ts new file mode 100644 index 000000000..b34dad8ac --- /dev/null +++ b/lib/typescript/services/formatting/formattingContext.ts @@ -0,0 +1,101 @@ +/// + +/* @internal */ +module ts.formatting { + export class FormattingContext { + public currentTokenSpan: TextRangeWithKind; + public nextTokenSpan: TextRangeWithKind; + public contextNode: Node; + public currentTokenParent: Node; + public nextTokenParent: Node; + + private contextNodeAllOnSameLine: boolean; + private nextNodeAllOnSameLine: boolean; + private tokensAreOnSameLine: boolean; + private contextNodeBlockIsOnOneLine: boolean; + private nextNodeBlockIsOnOneLine: boolean; + + constructor(public sourceFile: SourceFile, public formattingRequestKind: FormattingRequestKind) { + } + + public updateContext(currentRange: TextRangeWithKind, currentTokenParent: Node, nextRange: TextRangeWithKind, nextTokenParent: Node, commonParent: Node) { + Debug.assert(currentRange !== undefined, "currentTokenSpan is null"); + Debug.assert(currentTokenParent !== undefined, "currentTokenParent is null"); + Debug.assert(nextRange !== undefined, "nextTokenSpan is null"); + Debug.assert(nextTokenParent !== undefined, "nextTokenParent is null"); + Debug.assert(commonParent !== undefined, "commonParent is null"); + + this.currentTokenSpan = currentRange; + this.currentTokenParent = currentTokenParent; + this.nextTokenSpan = nextRange; + this.nextTokenParent = nextTokenParent; + this.contextNode = commonParent; + + // drop cached results + this.contextNodeAllOnSameLine = undefined; + this.nextNodeAllOnSameLine = undefined; + this.tokensAreOnSameLine = undefined; + this.contextNodeBlockIsOnOneLine = undefined; + this.nextNodeBlockIsOnOneLine = undefined; + } + + public ContextNodeAllOnSameLine(): boolean { + if (this.contextNodeAllOnSameLine === undefined) { + this.contextNodeAllOnSameLine = this.NodeIsOnOneLine(this.contextNode); + } + + return this.contextNodeAllOnSameLine; + } + + public NextNodeAllOnSameLine(): boolean { + if (this.nextNodeAllOnSameLine === undefined) { + this.nextNodeAllOnSameLine = this.NodeIsOnOneLine(this.nextTokenParent); + } + + return this.nextNodeAllOnSameLine; + } + + public TokensAreOnSameLine(): boolean { + if (this.tokensAreOnSameLine === undefined) { + let startLine = this.sourceFile.getLineAndCharacterOfPosition(this.currentTokenSpan.pos).line; + let endLine = this.sourceFile.getLineAndCharacterOfPosition(this.nextTokenSpan.pos).line; + this.tokensAreOnSameLine = (startLine == endLine); + } + + return this.tokensAreOnSameLine; + } + + public ContextNodeBlockIsOnOneLine() { + if (this.contextNodeBlockIsOnOneLine === undefined) { + this.contextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.contextNode); + } + + return this.contextNodeBlockIsOnOneLine; + } + + public NextNodeBlockIsOnOneLine() { + if (this.nextNodeBlockIsOnOneLine === undefined) { + this.nextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.nextTokenParent); + } + + return this.nextNodeBlockIsOnOneLine; + } + + private NodeIsOnOneLine(node: Node): boolean { + let startLine = this.sourceFile.getLineAndCharacterOfPosition(node.getStart(this.sourceFile)).line; + let endLine = this.sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line; + return startLine == endLine; + } + + private BlockIsOnOneLine(node: Node): boolean { + let openBrace = findChildOfKind(node, SyntaxKind.OpenBraceToken, this.sourceFile); + let closeBrace = findChildOfKind(node, SyntaxKind.CloseBraceToken, this.sourceFile); + if (openBrace && closeBrace) { + let startLine = this.sourceFile.getLineAndCharacterOfPosition(openBrace.getEnd()).line; + let endLine = this.sourceFile.getLineAndCharacterOfPosition(closeBrace.getStart(this.sourceFile)).line; + return startLine === endLine; + } + return false; + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/formattingRequestKind.ts b/lib/typescript/services/formatting/formattingRequestKind.ts new file mode 100644 index 000000000..3bf60cd2a --- /dev/null +++ b/lib/typescript/services/formatting/formattingRequestKind.ts @@ -0,0 +1,12 @@ +/// + +/* @internal */ +module ts.formatting { + export const enum FormattingRequestKind { + FormatDocument, + FormatSelection, + FormatOnEnter, + FormatOnSemicolon, + FormatOnClosingCurlyBrace + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/formattingScanner.ts b/lib/typescript/services/formatting/formattingScanner.ts new file mode 100644 index 000000000..680602ece --- /dev/null +++ b/lib/typescript/services/formatting/formattingScanner.ts @@ -0,0 +1,243 @@ +/// +/// + +/* @internal */ +module ts.formatting { + let scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false); + + export interface FormattingScanner { + advance(): void; + isOnToken(): boolean; + readTokenInfo(n: Node): TokenInfo; + lastTrailingTriviaWasNewLine(): boolean; + close(): void; + } + + const enum ScanAction{ + Scan, + RescanGreaterThanToken, + RescanSlashToken, + RescanTemplateToken + } + + export function getFormattingScanner(sourceFile: SourceFile, startPos: number, endPos: number): FormattingScanner { + + scanner.setText(sourceFile.text); + scanner.setTextPos(startPos); + + let wasNewLine: boolean = true; + let leadingTrivia: TextRangeWithKind[]; + let trailingTrivia: TextRangeWithKind[]; + + let savedPos: number; + let lastScanAction: ScanAction; + let lastTokenInfo: TokenInfo; + + return { + advance: advance, + readTokenInfo: readTokenInfo, + isOnToken: isOnToken, + lastTrailingTriviaWasNewLine: () => wasNewLine, + close: () => { + lastTokenInfo = undefined; + scanner.setText(undefined); + } + } + + function advance(): void { + lastTokenInfo = undefined; + let isStarted = scanner.getStartPos() !== startPos; + + if (isStarted) { + if (trailingTrivia) { + Debug.assert(trailingTrivia.length !== 0); + wasNewLine = trailingTrivia[trailingTrivia.length - 1].kind === SyntaxKind.NewLineTrivia; + } + else { + wasNewLine = false; + } + } + + leadingTrivia = undefined; + trailingTrivia = undefined; + + if (!isStarted) { + scanner.scan(); + } + + let t: SyntaxKind; + let pos = scanner.getStartPos(); + + // Read leading trivia and token + while (pos < endPos) { + let t = scanner.getToken(); + if (!isTrivia(t)) { + break; + } + + // consume leading trivia + scanner.scan(); + let item = { + pos: pos, + end: scanner.getStartPos(), + kind: t + } + + pos = scanner.getStartPos(); + + if (!leadingTrivia) { + leadingTrivia = []; + } + leadingTrivia.push(item); + } + + savedPos = scanner.getStartPos(); + } + + function shouldRescanGreaterThanToken(node: Node): boolean { + if (node) { + switch (node.kind) { + case SyntaxKind.GreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanToken: + return true; + } + } + + return false; + } + + function shouldRescanSlashToken(container: Node): boolean { + return container.kind === SyntaxKind.RegularExpressionLiteral; + } + + function shouldRescanTemplateToken(container: Node): boolean { + return container.kind === SyntaxKind.TemplateMiddle || + container.kind === SyntaxKind.TemplateTail; + } + + function startsWithSlashToken(t: SyntaxKind): boolean { + return t === SyntaxKind.SlashToken || t === SyntaxKind.SlashEqualsToken; + } + + function readTokenInfo(n: Node): TokenInfo { + if (!isOnToken()) { + // scanner is not on the token (either advance was not called yet or scanner is already past the end position) + return { + leadingTrivia: leadingTrivia, + trailingTrivia: undefined, + token: undefined + }; + } + + // normally scanner returns the smallest available token + // check the kind of context node to determine if scanner should have more greedy behavior and consume more text. + let expectedScanAction = + shouldRescanGreaterThanToken(n) + ? ScanAction.RescanGreaterThanToken + : shouldRescanSlashToken(n) + ? ScanAction.RescanSlashToken + : shouldRescanTemplateToken(n) + ? ScanAction.RescanTemplateToken + : ScanAction.Scan + + if (lastTokenInfo && expectedScanAction === lastScanAction) { + // readTokenInfo was called before with the same expected scan action. + // No need to re-scan text, return existing 'lastTokenInfo' + // it is ok to call fixTokenKind here since it does not affect + // what portion of text is consumed. In opposize rescanning can change it, + // i.e. for '>=' when originally scanner eats just one character + // and rescanning forces it to consume more. + return fixTokenKind(lastTokenInfo, n); + } + + if (scanner.getStartPos() !== savedPos) { + Debug.assert(lastTokenInfo !== undefined); + // readTokenInfo was called before but scan action differs - rescan text + scanner.setTextPos(savedPos); + scanner.scan(); + } + + let currentToken = scanner.getToken(); + + if (expectedScanAction === ScanAction.RescanGreaterThanToken && currentToken === SyntaxKind.GreaterThanToken) { + currentToken = scanner.reScanGreaterToken(); + Debug.assert(n.kind === currentToken); + lastScanAction = ScanAction.RescanGreaterThanToken; + } + else if (expectedScanAction === ScanAction.RescanSlashToken && startsWithSlashToken(currentToken)) { + currentToken = scanner.reScanSlashToken(); + Debug.assert(n.kind === currentToken); + lastScanAction = ScanAction.RescanSlashToken; + } + else if (expectedScanAction === ScanAction.RescanTemplateToken && currentToken === SyntaxKind.CloseBraceToken) { + currentToken = scanner.reScanTemplateToken(); + lastScanAction = ScanAction.RescanTemplateToken; + } + else { + lastScanAction = ScanAction.Scan; + } + + let token: TextRangeWithKind = { + pos: scanner.getStartPos(), + end: scanner.getTextPos(), + kind: currentToken + } + + // consume trailing trivia + if (trailingTrivia) { + trailingTrivia = undefined; + } + while(scanner.getStartPos() < endPos) { + currentToken = scanner.scan(); + if (!isTrivia(currentToken)) { + break; + } + let trivia = { + pos: scanner.getStartPos(), + end: scanner.getTextPos(), + kind: currentToken + }; + + if (!trailingTrivia) { + trailingTrivia = []; + } + + trailingTrivia.push(trivia); + + if (currentToken === SyntaxKind.NewLineTrivia) { + // move past new line + scanner.scan(); + break; + } + } + + lastTokenInfo = { + leadingTrivia: leadingTrivia, + trailingTrivia: trailingTrivia, + token: token + } + + return fixTokenKind(lastTokenInfo, n); + } + + function isOnToken(): boolean { + let current = (lastTokenInfo && lastTokenInfo.token.kind) || scanner.getToken(); + let startPos = (lastTokenInfo && lastTokenInfo.token.pos) || scanner.getStartPos(); + return startPos < endPos && current !== SyntaxKind.EndOfFileToken && !isTrivia(current); + } + + // when containing node in the tree is token + // but its kind differs from the kind that was returned by the scanner, + // then kind needs to be fixed. This might happen in cases + // when parser interprets token differently, i.e keyword treated as identifier + function fixTokenKind(tokenInfo: TokenInfo, container: Node): TokenInfo { + if (isToken(container) && tokenInfo.token.kind !== container.kind) { + tokenInfo.token.kind = container.kind; + } + return tokenInfo; + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/references.ts b/lib/typescript/services/formatting/references.ts new file mode 100644 index 000000000..e23ead5c5 --- /dev/null +++ b/lib/typescript/services/formatting/references.ts @@ -0,0 +1,12 @@ +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// \ No newline at end of file diff --git a/lib/typescript/services/formatting/rule.ts b/lib/typescript/services/formatting/rule.ts new file mode 100644 index 000000000..807e0f056 --- /dev/null +++ b/lib/typescript/services/formatting/rule.ts @@ -0,0 +1,18 @@ +/// + +/* @internal */ +module ts.formatting { + export class Rule { + constructor( + public Descriptor: RuleDescriptor, + public Operation: RuleOperation, + public Flag: RuleFlags = RuleFlags.None) { + } + + public toString() { + return "[desc=" + this.Descriptor + "," + + "operation=" + this.Operation + "," + + "flag=" + this.Flag + "]"; + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/ruleAction.ts b/lib/typescript/services/formatting/ruleAction.ts new file mode 100644 index 000000000..18d591199 --- /dev/null +++ b/lib/typescript/services/formatting/ruleAction.ts @@ -0,0 +1,11 @@ +/// + +/* @internal */ +module ts.formatting { + export const enum RuleAction { + Ignore = 0x00000001, + Space = 0x00000002, + NewLine = 0x00000004, + Delete = 0x00000008 + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/ruleDescriptor.ts b/lib/typescript/services/formatting/ruleDescriptor.ts new file mode 100644 index 000000000..f4ef9da34 --- /dev/null +++ b/lib/typescript/services/formatting/ruleDescriptor.ts @@ -0,0 +1,30 @@ +/// + +/* @internal */ +module ts.formatting { + export class RuleDescriptor { + constructor(public LeftTokenRange: Shared.TokenRange, public RightTokenRange: Shared.TokenRange) { + } + + public toString(): string { + return "[leftRange=" + this.LeftTokenRange + "," + + "rightRange=" + this.RightTokenRange + "]"; + } + + static create1(left: SyntaxKind, right: SyntaxKind): RuleDescriptor { + return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), Shared.TokenRange.FromToken(right)); + } + + static create2(left: Shared.TokenRange, right: SyntaxKind): RuleDescriptor { + return RuleDescriptor.create4(left, Shared.TokenRange.FromToken(right)); + } + + static create3(left: SyntaxKind, right: Shared.TokenRange): RuleDescriptor { + return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), right); + } + + static create4(left: Shared.TokenRange, right: Shared.TokenRange): RuleDescriptor { + return new RuleDescriptor(left, right); + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/ruleFlag.ts b/lib/typescript/services/formatting/ruleFlag.ts new file mode 100644 index 000000000..697aa5312 --- /dev/null +++ b/lib/typescript/services/formatting/ruleFlag.ts @@ -0,0 +1,10 @@ +/// + + +/* @internal */ +module ts.formatting { + export const enum RuleFlags { + None, + CanDeleteNewLines + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/ruleOperation.ts b/lib/typescript/services/formatting/ruleOperation.ts new file mode 100644 index 000000000..387b79537 --- /dev/null +++ b/lib/typescript/services/formatting/ruleOperation.ts @@ -0,0 +1,30 @@ +/// + +/* @internal */ +module ts.formatting { + export class RuleOperation { + public Context: RuleOperationContext; + public Action: RuleAction; + + constructor() { + this.Context = null; + this.Action = null; + } + + public toString(): string { + return "[context=" + this.Context + "," + + "action=" + this.Action + "]"; + } + + static create1(action: RuleAction) { + return RuleOperation.create2(RuleOperationContext.Any, action) + } + + static create2(context: RuleOperationContext, action: RuleAction) { + let result = new RuleOperation(); + result.Context = context; + result.Action = action; + return result; + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/ruleOperationContext.ts b/lib/typescript/services/formatting/ruleOperationContext.ts new file mode 100644 index 000000000..d4e103cef --- /dev/null +++ b/lib/typescript/services/formatting/ruleOperationContext.ts @@ -0,0 +1,33 @@ +/// + +/* @internal */ +module ts.formatting { + + export class RuleOperationContext { + private customContextChecks: { (context: FormattingContext): boolean; }[]; + + constructor(...funcs: { (context: FormattingContext): boolean; }[]) { + this.customContextChecks = funcs; + } + + static Any: RuleOperationContext = new RuleOperationContext(); + + + public IsAny(): boolean { + return this == RuleOperationContext.Any; + } + + public InContext(context: FormattingContext): boolean { + if (this.IsAny()) { + return true; + } + + for (let check of this.customContextChecks) { + if (!check(context)) { + return false; + } + } + return true; + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/rules.ts b/lib/typescript/services/formatting/rules.ts new file mode 100644 index 000000000..e4b54d1ba --- /dev/null +++ b/lib/typescript/services/formatting/rules.ts @@ -0,0 +1,717 @@ +/// + +/* @internal */ +module ts.formatting { + export class Rules { + public getRuleName(rule: Rule) { + let o: ts.Map = this; + for (let name in o) { + if (o[name] === rule) { + return name; + } + } + throw new Error("Unknown rule"); + } + + [name: string]: any; + + public IgnoreBeforeComment: Rule; + public IgnoreAfterLineComment: Rule; + + // Space after keyword but not before ; or : or ? + public NoSpaceBeforeSemicolon: Rule; + public NoSpaceBeforeColon: Rule; + public NoSpaceBeforeQuestionMark: Rule; + public SpaceAfterColon: Rule; + // insert space after '?' only when it is used in conditional operator + public SpaceAfterQuestionMarkInConditionalOperator: Rule; + // in other cases there should be no space between '?' and next token + public NoSpaceAfterQuestionMark: Rule; + + public SpaceAfterSemicolon: Rule; + + // Space/new line after }. + public SpaceAfterCloseBrace: Rule; + + // Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied + // Also should not apply to }) + public SpaceBetweenCloseBraceAndElse: Rule; + public SpaceBetweenCloseBraceAndWhile: Rule; + public NoSpaceAfterCloseBrace: Rule; + + // No space for indexer and dot + public NoSpaceBeforeDot: Rule; + public NoSpaceAfterDot: Rule; + public NoSpaceBeforeOpenBracket: Rule; + public NoSpaceAfterOpenBracket: Rule; + public NoSpaceBeforeCloseBracket: Rule; + public NoSpaceAfterCloseBracket: Rule; + + // Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}. + public SpaceAfterOpenBrace: Rule; + public SpaceBeforeCloseBrace: Rule; + public NoSpaceBetweenEmptyBraceBrackets: Rule; + + // Insert new line after { and before } in multi-line contexts. + public NewLineAfterOpenBraceInBlockContext: Rule; + + // For functions and control block place } on a new line [multi-line rule] + public NewLineBeforeCloseBraceInBlockContext: Rule; + + // Special handling of unary operators. + // Prefix operators generally shouldn't have a space between + // them and their target unary expression. + public NoSpaceAfterUnaryPrefixOperator: Rule; + public NoSpaceAfterUnaryPreincrementOperator: Rule; + public NoSpaceAfterUnaryPredecrementOperator: Rule; + public NoSpaceBeforeUnaryPostincrementOperator: Rule; + public NoSpaceBeforeUnaryPostdecrementOperator: Rule; + + // More unary operator special-casing. + // DevDiv 181814: Be careful when removing leading whitespace + // around unary operators. Examples: + // 1 - -2 --X--> 1--2 + // a + ++b --X--> a+++b + public SpaceAfterPostincrementWhenFollowedByAdd: Rule; + public SpaceAfterAddWhenFollowedByUnaryPlus: Rule; + public SpaceAfterAddWhenFollowedByPreincrement: Rule; + public SpaceAfterPostdecrementWhenFollowedBySubtract: Rule; + public SpaceAfterSubtractWhenFollowedByUnaryMinus: Rule; + public SpaceAfterSubtractWhenFollowedByPredecrement: Rule; + + public NoSpaceBeforeComma: Rule; + + public SpaceAfterCertainKeywords: Rule; + public SpaceAfterLetConstInVariableDeclaration: Rule; + public NoSpaceBeforeOpenParenInFuncCall: Rule; + public SpaceAfterFunctionInFuncDecl: Rule; + public NoSpaceBeforeOpenParenInFuncDecl: Rule; + public SpaceAfterVoidOperator: Rule; + + public NoSpaceBetweenReturnAndSemicolon: Rule; + + // Add a space between statements. All keywords except (do,else,case) has open/close parens after them. + // So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any] + public SpaceBetweenStatements: Rule; + + // This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter. + public SpaceAfterTryFinally: Rule; + + // For get/set members, we check for (identifier,identifier) since get/set don't have tokens and they are represented as just an identifier token. + // Though, we do extra check on the context to make sure we are dealing with get/set node. Example: + // get x() {} + // set x(val) {} + public SpaceAfterGetSetInMember: Rule; + + // Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options. + public SpaceBeforeBinaryKeywordOperator: Rule; + public SpaceAfterBinaryKeywordOperator: Rule; + + // TypeScript-specific rules + + // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses + public NoSpaceAfterConstructor: Rule; + + // Use of module as a function call. e.g.: import m2 = module("m2"); + public NoSpaceAfterModuleImport: Rule; + + // Add a space around certain TypeScript keywords + public SpaceAfterCertainTypeScriptKeywords: Rule; + public SpaceBeforeCertainTypeScriptKeywords: Rule; + + // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" { + public SpaceAfterModuleName: Rule; + + // Lambda expressions + public SpaceAfterArrow: Rule; + + // Optional parameters and let args + public NoSpaceAfterEllipsis: Rule; + public NoSpaceAfterOptionalParameters: Rule; + + // generics + public NoSpaceBeforeOpenAngularBracket: Rule; + public NoSpaceBetweenCloseParenAndAngularBracket: Rule; + public NoSpaceAfterOpenAngularBracket: Rule; + public NoSpaceBeforeCloseAngularBracket: Rule; + public NoSpaceAfterCloseAngularBracket: Rule; + + // Remove spaces in empty interface literals. e.g.: x: {} + public NoSpaceBetweenEmptyInterfaceBraceBrackets: Rule; + + // These rules are higher in priority than user-configurable rules. + public HighPriorityCommonRules: Rule[]; + + // These rules are lower in priority than user-configurable rules. + public LowPriorityCommonRules: Rule[]; + + /// + /// Rules controlled by user options + /// + + // Insert space after comma delimiter + public SpaceAfterComma: Rule; + public NoSpaceAfterComma: Rule; + + // Insert space before and after binary operators + public SpaceBeforeBinaryOperator: Rule; + public SpaceAfterBinaryOperator: Rule; + public NoSpaceBeforeBinaryOperator: Rule; + public NoSpaceAfterBinaryOperator: Rule; + + // Insert space after keywords in control flow statements + public SpaceAfterKeywordInControl: Rule; + public NoSpaceAfterKeywordInControl: Rule; + + // Open Brace braces after function + //TypeScript: Function can have return types, which can be made of tons of different token kinds + public FunctionOpenBraceLeftTokenRange: Shared.TokenRange; + public SpaceBeforeOpenBraceInFunction: Rule; + public NewLineBeforeOpenBraceInFunction: Rule; + + // Open Brace braces after TypeScript module/class/interface + public TypeScriptOpenBraceLeftTokenRange: Shared.TokenRange; + public SpaceBeforeOpenBraceInTypeScriptDeclWithBlock: Rule; + public NewLineBeforeOpenBraceInTypeScriptDeclWithBlock: Rule; + + // Open Brace braces after control block + public ControlOpenBraceLeftTokenRange: Shared.TokenRange; + public SpaceBeforeOpenBraceInControl: Rule; + public NewLineBeforeOpenBraceInControl: Rule; + + // Insert space after semicolon in for statement + public SpaceAfterSemicolonInFor: Rule; + public NoSpaceAfterSemicolonInFor: Rule; + + // Insert space after opening and before closing nonempty parenthesis + public SpaceAfterOpenParen: Rule; + public SpaceBeforeCloseParen: Rule; + public NoSpaceBetweenParens: Rule; + public NoSpaceAfterOpenParen: Rule; + public NoSpaceBeforeCloseParen: Rule; + + // Insert space after function keyword for anonymous functions + public SpaceAfterAnonymousFunctionKeyword: Rule; + public NoSpaceAfterAnonymousFunctionKeyword: Rule; + + // Insert space after @ in decorator + public SpaceBeforeAt: Rule; + public NoSpaceAfterAt: Rule; + public SpaceAfterDecorator: Rule; + + constructor() { + /// + /// Common Rules + /// + + // Leave comments alone + this.IgnoreBeforeComment = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.Comments), RuleOperation.create1(RuleAction.Ignore)); + this.IgnoreAfterLineComment = new Rule(RuleDescriptor.create3(SyntaxKind.SingleLineCommentTrivia, Shared.TokenRange.Any), RuleOperation.create1(RuleAction.Ignore)); + + // Space after keyword but not before ; or : or ? + this.NoSpaceBeforeSemicolon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeColon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.ColonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); + this.NoSpaceBeforeQuestionMark = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.QuestionToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); + this.SpaceAfterColon = new Rule(RuleDescriptor.create3(SyntaxKind.ColonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space)); + this.SpaceAfterQuestionMarkInConditionalOperator = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsConditionalOperatorContext), RuleAction.Space)); + this.NoSpaceAfterQuestionMark = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.SpaceAfterSemicolon = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + + // Space after }. + this.SpaceAfterCloseBrace = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsAfterCodeBlockContext), RuleAction.Space)); + + // Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied + this.SpaceBetweenCloseBraceAndElse = new Rule(RuleDescriptor.create1(SyntaxKind.CloseBraceToken, SyntaxKind.ElseKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.SpaceBetweenCloseBraceAndWhile = new Rule(RuleDescriptor.create1(SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.NoSpaceAfterCloseBrace = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBraceToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken, SyntaxKind.SemicolonToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // No space for indexer and dot + this.NoSpaceBeforeDot = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.DotToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterDot = new Rule(RuleDescriptor.create3(SyntaxKind.DotToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeOpenBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterOpenBracket = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeCloseBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterCloseBracket = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Place a space before open brace in a function declaration + this.FunctionOpenBraceLeftTokenRange = Shared.TokenRange.AnyIncludingMultilineComments; + this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsBeforeBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines); + + // Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc) + this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia]); + this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines); + + // Place a space before open brace in a control flow construct + this.ControlOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.DoKeyword, SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword, SyntaxKind.ElseKeyword]); + this.SpaceBeforeOpenBraceInControl = new Rule(RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines); + + // Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}. + this.SpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSingleLineBlockContext), RuleAction.Space)); + this.SpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSingleLineBlockContext), RuleAction.Space)); + this.NoSpaceBetweenEmptyBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsObjectContext), RuleAction.Delete)); + + // Insert new line after { and before } in multi-line contexts. + this.NewLineAfterOpenBraceInBlockContext = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsMultilineBlockContext), RuleAction.NewLine)); + + // For functions and control block place } on a new line [multi-line rule] + this.NewLineBeforeCloseBraceInBlockContext = new Rule(RuleDescriptor.create2(Shared.TokenRange.AnyIncludingMultilineComments, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsMultilineBlockContext), RuleAction.NewLine)); + + // Special handling of unary operators. + // Prefix operators generally shouldn't have a space between + // them and their target unary expression. + this.NoSpaceAfterUnaryPrefixOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.UnaryPrefixOperators, Shared.TokenRange.UnaryPrefixExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); + this.NoSpaceAfterUnaryPreincrementOperator = new Rule(RuleDescriptor.create3(SyntaxKind.PlusPlusToken, Shared.TokenRange.UnaryPreincrementExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterUnaryPredecrementOperator = new Rule(RuleDescriptor.create3(SyntaxKind.MinusMinusToken, Shared.TokenRange.UnaryPredecrementExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeUnaryPostincrementOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.UnaryPostincrementExpressions, SyntaxKind.PlusPlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeUnaryPostdecrementOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.UnaryPostdecrementExpressions, SyntaxKind.MinusMinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // More unary operator special-casing. + // DevDiv 181814: Be careful when removing leading whitespace + // around unary operators. Examples: + // 1 - -2 --X--> 1--2 + // a + ++b --X--> a+++b + this.SpaceAfterPostincrementWhenFollowedByAdd = new Rule(RuleDescriptor.create1(SyntaxKind.PlusPlusToken, SyntaxKind.PlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterAddWhenFollowedByUnaryPlus = new Rule(RuleDescriptor.create1(SyntaxKind.PlusToken, SyntaxKind.PlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterAddWhenFollowedByPreincrement = new Rule(RuleDescriptor.create1(SyntaxKind.PlusToken, SyntaxKind.PlusPlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterPostdecrementWhenFollowedBySubtract = new Rule(RuleDescriptor.create1(SyntaxKind.MinusMinusToken, SyntaxKind.MinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterSubtractWhenFollowedByUnaryMinus = new Rule(RuleDescriptor.create1(SyntaxKind.MinusToken, SyntaxKind.MinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterSubtractWhenFollowedByPredecrement = new Rule(RuleDescriptor.create1(SyntaxKind.MinusToken, SyntaxKind.MinusMinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + + this.NoSpaceBeforeComma = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CommaToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + this.SpaceAfterCertainKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.VarKeyword, SyntaxKind.ThrowKeyword, SyntaxKind.NewKeyword, SyntaxKind.DeleteKeyword, SyntaxKind.ReturnKeyword, SyntaxKind.TypeOfKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.SpaceAfterLetConstInVariableDeclaration = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.LetKeyword, SyntaxKind.ConstKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsStartOfVariableDeclarationList), RuleAction.Space)); + this.NoSpaceBeforeOpenParenInFuncCall = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsFunctionCallOrNewContext, Rules.IsPreviousTokenNotComma), RuleAction.Delete)); + this.SpaceAfterFunctionInFuncDecl = new Rule(RuleDescriptor.create3(SyntaxKind.FunctionKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space)); + this.NoSpaceBeforeOpenParenInFuncDecl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsFunctionDeclContext), RuleAction.Delete)); + this.SpaceAfterVoidOperator = new Rule(RuleDescriptor.create3(SyntaxKind.VoidKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsVoidOpContext), RuleAction.Space)); + + this.NoSpaceBetweenReturnAndSemicolon = new Rule(RuleDescriptor.create1(SyntaxKind.ReturnKeyword, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Add a space between statements. All keywords except (do,else,case) has open/close parens after them. + // So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any] + this.SpaceBetweenStatements = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.DoKeyword, SyntaxKind.ElseKeyword, SyntaxKind.CaseKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotForContext), RuleAction.Space)); + + // This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter. + this.SpaceAfterTryFinally = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword]), SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + + // get x() {} + // set x(val) {} + this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space)); + + // Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options. + this.SpaceBeforeBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryKeywordOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryKeywordOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + + // TypeScript-specific higher priority rules + + // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses + this.NoSpaceAfterConstructor = new Rule(RuleDescriptor.create1(SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Use of module as a function call. e.g.: import m2 = module("m2"); + this.NoSpaceAfterModuleImport = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword]), SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Add a space around certain TypeScript keywords + this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.SpaceBeforeCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + + // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" { + this.SpaceAfterModuleName = new Rule(RuleDescriptor.create1(SyntaxKind.StringLiteral, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsModuleDeclContext), RuleAction.Space)); + + // Lambda expressions + this.SpaceAfterArrow = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsGreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + + // Optional parameters and let args + this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterOptionalParameters = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); + + // generics + this.NoSpaceBeforeOpenAngularBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.TypeNames, SyntaxKind.LessThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete)); + this.NoSpaceBetweenCloseParenAndAngularBracket = new Rule(RuleDescriptor.create1(SyntaxKind.CloseParenToken, SyntaxKind.LessThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete)); + this.NoSpaceAfterOpenAngularBracket = new Rule(RuleDescriptor.create3(SyntaxKind.LessThanToken, Shared.TokenRange.TypeNames), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete)); + this.NoSpaceBeforeCloseAngularBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.GreaterThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete)); + this.NoSpaceAfterCloseAngularBracket = new Rule(RuleDescriptor.create3(SyntaxKind.GreaterThanToken, Shared.TokenRange.FromTokens([SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.GreaterThanToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete)); + + // Remove spaces in empty interface literals. e.g.: x: {} + this.NoSpaceBetweenEmptyInterfaceBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsObjectTypeContext), RuleAction.Delete)); + + // decorators + this.SpaceBeforeAt = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.AtToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.NoSpaceAfterAt = new Rule(RuleDescriptor.create3(SyntaxKind.AtToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.SpaceAfterDecorator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.ExportKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.ClassKeyword, SyntaxKind.StaticKeyword, SyntaxKind.PublicKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.GetKeyword, SyntaxKind.SetKeyword, SyntaxKind.OpenBracketToken, SyntaxKind.AsteriskToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsEndOfDecoratorContextOnSameLine), RuleAction.Space)); + + // These rules are higher in priority than user-configurable rules. + this.HighPriorityCommonRules = + [ + this.IgnoreBeforeComment, this.IgnoreAfterLineComment, + this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQuestionMark, this.SpaceAfterQuestionMarkInConditionalOperator, + this.NoSpaceAfterQuestionMark, + this.NoSpaceBeforeDot, this.NoSpaceAfterDot, + this.NoSpaceAfterUnaryPrefixOperator, + this.NoSpaceAfterUnaryPreincrementOperator, this.NoSpaceAfterUnaryPredecrementOperator, + this.NoSpaceBeforeUnaryPostincrementOperator, this.NoSpaceBeforeUnaryPostdecrementOperator, + this.SpaceAfterPostincrementWhenFollowedByAdd, + this.SpaceAfterAddWhenFollowedByUnaryPlus, this.SpaceAfterAddWhenFollowedByPreincrement, + this.SpaceAfterPostdecrementWhenFollowedBySubtract, + this.SpaceAfterSubtractWhenFollowedByUnaryMinus, this.SpaceAfterSubtractWhenFollowedByPredecrement, + this.NoSpaceAfterCloseBrace, + this.SpaceAfterOpenBrace, this.SpaceBeforeCloseBrace, this.NewLineBeforeCloseBraceInBlockContext, + this.SpaceAfterCloseBrace, this.SpaceBetweenCloseBraceAndElse, this.SpaceBetweenCloseBraceAndWhile, this.NoSpaceBetweenEmptyBraceBrackets, + this.SpaceAfterFunctionInFuncDecl, this.NewLineAfterOpenBraceInBlockContext, this.SpaceAfterGetSetInMember, + this.NoSpaceBetweenReturnAndSemicolon, + this.SpaceAfterCertainKeywords, + this.SpaceAfterLetConstInVariableDeclaration, + this.NoSpaceBeforeOpenParenInFuncCall, + this.SpaceBeforeBinaryKeywordOperator, this.SpaceAfterBinaryKeywordOperator, + this.SpaceAfterVoidOperator, + + // TypeScript-specific rules + this.NoSpaceAfterConstructor, this.NoSpaceAfterModuleImport, + this.SpaceAfterCertainTypeScriptKeywords, this.SpaceBeforeCertainTypeScriptKeywords, + this.SpaceAfterModuleName, + this.SpaceAfterArrow, + this.NoSpaceAfterEllipsis, + this.NoSpaceAfterOptionalParameters, + this.NoSpaceBetweenEmptyInterfaceBraceBrackets, + this.NoSpaceBeforeOpenAngularBracket, + this.NoSpaceBetweenCloseParenAndAngularBracket, + this.NoSpaceAfterOpenAngularBracket, + this.NoSpaceBeforeCloseAngularBracket, + this.NoSpaceAfterCloseAngularBracket, + this.SpaceBeforeAt, + this.NoSpaceAfterAt, + this.SpaceAfterDecorator, + ]; + + // These rules are lower in priority than user-configurable rules. + this.LowPriorityCommonRules = + [ + this.NoSpaceBeforeSemicolon, + this.SpaceBeforeOpenBraceInControl, this.SpaceBeforeOpenBraceInFunction, this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock, + this.NoSpaceBeforeComma, + this.NoSpaceBeforeOpenBracket, this.NoSpaceAfterOpenBracket, + this.NoSpaceBeforeCloseBracket, this.NoSpaceAfterCloseBracket, + this.SpaceAfterSemicolon, + this.NoSpaceBeforeOpenParenInFuncDecl, + this.SpaceBetweenStatements, this.SpaceAfterTryFinally + ]; + + /// + /// Rules controlled by user options + /// + + // Insert space after comma delimiter + this.SpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.NoSpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Insert space before and after binary operators + this.SpaceBeforeBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.NoSpaceBeforeBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Delete)); + this.NoSpaceAfterBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Delete)); + + // Insert space after keywords in control flow statements + this.SpaceAfterKeywordInControl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Keywords, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext), RuleAction.Space)); + this.NoSpaceAfterKeywordInControl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Keywords, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext), RuleAction.Delete)); + + // Open Brace braces after function + //TypeScript: Function can have return types, which can be made of tons of different token kinds + this.NewLineBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines); + + // Open Brace braces after TypeScript module/class/interface + this.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines); + + // Open Brace braces after control block + this.NewLineBeforeOpenBraceInControl = new Rule(RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines); + + // Insert space after semicolon in for statement + this.SpaceAfterSemicolonInFor = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsForContext), RuleAction.Space)); + this.NoSpaceAfterSemicolonInFor = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsForContext), RuleAction.Delete)); + + // Insert space after opening and before closing nonempty parenthesis + this.SpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.SpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.NoSpaceBetweenParens = new Rule(RuleDescriptor.create1(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Insert space after function keyword for anonymous functions + this.SpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space)); + this.NoSpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Delete)); + } + + /// + /// Contexts + /// + + static IsForContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ForStatement; + } + + static IsNotForContext(context: FormattingContext): boolean { + return !Rules.IsForContext(context); + } + + static IsBinaryOpContext(context: FormattingContext): boolean { + + switch (context.contextNode.kind) { + case SyntaxKind.BinaryExpression: + case SyntaxKind.ConditionalExpression: + return true; + + // equals in binding elements: function foo([[x, y] = [1, 2]]) + case SyntaxKind.BindingElement: + // equals in type X = ... + case SyntaxKind.TypeAliasDeclaration: + // equal in import a = module('a'); + case SyntaxKind.ImportEqualsDeclaration: + // equal in let a = 0; + case SyntaxKind.VariableDeclaration: + // equal in p = 0; + case SyntaxKind.Parameter: + case SyntaxKind.EnumMember: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken; + // "in" keyword in for (let x in []) { } + case SyntaxKind.ForInStatement: + return context.currentTokenSpan.kind === SyntaxKind.InKeyword || context.nextTokenSpan.kind === SyntaxKind.InKeyword; + // Technically, "of" is not a binary operator, but format it the same way as "in" + case SyntaxKind.ForOfStatement: + return context.currentTokenSpan.kind === SyntaxKind.OfKeyword || context.nextTokenSpan.kind === SyntaxKind.OfKeyword; + } + return false; + } + + static IsNotBinaryOpContext(context: FormattingContext): boolean { + return !Rules.IsBinaryOpContext(context); + } + + static IsConditionalOperatorContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ConditionalExpression; + } + + static IsSameLineTokenOrBeforeMultilineBlockContext(context: FormattingContext): boolean { + //// This check is mainly used inside SpaceBeforeOpenBraceInControl and SpaceBeforeOpenBraceInFunction. + //// + //// Ex: + //// if (1) { .... + //// * ) and { are on the same line so apply the rule. Here we don't care whether it's same or multi block context + //// + //// Ex: + //// if (1) + //// { ... } + //// * ) and { are on differnet lines. We only need to format if the block is multiline context. So in this case we don't format. + //// + //// Ex: + //// if (1) + //// { ... + //// } + //// * ) and { are on differnet lines. We only need to format if the block is multiline context. So in this case we format. + + return context.TokensAreOnSameLine() || Rules.IsBeforeMultilineBlockContext(context); + } + + // This check is done before an open brace in a control construct, a function, or a typescript block declaration + static IsBeforeMultilineBlockContext(context: FormattingContext): boolean { + return Rules.IsBeforeBlockContext(context) && !(context.NextNodeAllOnSameLine() || context.NextNodeBlockIsOnOneLine()); + } + + static IsMultilineBlockContext(context: FormattingContext): boolean { + return Rules.IsBlockContext(context) && !(context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); + } + + static IsSingleLineBlockContext(context: FormattingContext): boolean { + return Rules.IsBlockContext(context) && (context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); + } + + static IsBlockContext(context: FormattingContext): boolean { + return Rules.NodeIsBlockContext(context.contextNode); + } + + static IsBeforeBlockContext(context: FormattingContext): boolean { + return Rules.NodeIsBlockContext(context.nextTokenParent); + } + + // IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children + static NodeIsBlockContext(node: Node): boolean { + if (Rules.NodeIsTypeScriptDeclWithBlockContext(node)) { + // This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc). + return true; + } + + switch (node.kind) { + case SyntaxKind.Block: + case SyntaxKind.CaseBlock: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.ModuleBlock: + return true; + } + + return false; + } + + static IsFunctionDeclContext(context: FormattingContext): boolean { + switch (context.contextNode.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + //case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + ///case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.FunctionExpression: + case SyntaxKind.Constructor: + case SyntaxKind.ArrowFunction: + //case SyntaxKind.ConstructorDeclaration: + //case SyntaxKind.SimpleArrowFunctionExpression: + //case SyntaxKind.ParenthesizedArrowFunctionExpression: + case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one + return true; + } + + return false; + } + + static IsTypeScriptDeclWithBlockContext(context: FormattingContext): boolean { + return Rules.NodeIsTypeScriptDeclWithBlockContext(context.contextNode); + } + + static NodeIsTypeScriptDeclWithBlockContext(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.TypeLiteral: + case SyntaxKind.ModuleDeclaration: + return true; + } + + return false; + } + + static IsAfterCodeBlockContext(context: FormattingContext): boolean { + switch (context.currentTokenParent.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.Block: + case SyntaxKind.CatchClause: + case SyntaxKind.ModuleBlock: + case SyntaxKind.SwitchStatement: + return true; + } + return false; + } + + static IsControlDeclContext(context: FormattingContext): boolean { + switch (context.contextNode.kind) { + case SyntaxKind.IfStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WithStatement: + // TODO + // case SyntaxKind.ElseClause: + case SyntaxKind.CatchClause: + return true; + + default: + return false; + } + } + + static IsObjectContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ObjectLiteralExpression; + } + + static IsFunctionCallContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.CallExpression; + } + + static IsNewContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.NewExpression; + } + + static IsFunctionCallOrNewContext(context: FormattingContext): boolean { + return Rules.IsFunctionCallContext(context) || Rules.IsNewContext(context); + } + + static IsPreviousTokenNotComma(context: FormattingContext): boolean { + return context.currentTokenSpan.kind !== SyntaxKind.CommaToken; + } + + static IsSameLineTokenContext(context: FormattingContext): boolean { + return context.TokensAreOnSameLine(); + } + + static IsEndOfDecoratorContextOnSameLine(context: FormattingContext): boolean { + return context.TokensAreOnSameLine() && + context.contextNode.decorators && + Rules.NodeIsInDecoratorContext(context.currentTokenParent) && + !Rules.NodeIsInDecoratorContext(context.nextTokenParent); + } + + static NodeIsInDecoratorContext(node: Node): boolean { + while (isExpression(node)) { + node = node.parent; + } + return node.kind === SyntaxKind.Decorator; + } + + static IsStartOfVariableDeclarationList(context: FormattingContext): boolean { + return context.currentTokenParent.kind === SyntaxKind.VariableDeclarationList && + context.currentTokenParent.getStart(context.sourceFile) === context.currentTokenSpan.pos; + } + + static IsNotFormatOnEnter(context: FormattingContext): boolean { + return context.formattingRequestKind != FormattingRequestKind.FormatOnEnter; + } + + static IsModuleDeclContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ModuleDeclaration; + } + + static IsObjectTypeContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.TypeLiteral;// && context.contextNode.parent.kind !== SyntaxKind.InterfaceDeclaration; + } + + static IsTypeArgumentOrParameter(token: TextRangeWithKind, parent: Node): boolean { + if (token.kind !== SyntaxKind.LessThanToken && token.kind !== SyntaxKind.GreaterThanToken) { + return false; + } + switch (parent.kind) { + case SyntaxKind.TypeReference: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + return true; + default: + return false; + + } + } + + static IsTypeArgumentOrParameterContext(context: FormattingContext): boolean { + return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan, context.currentTokenParent) || + Rules.IsTypeArgumentOrParameter(context.nextTokenSpan, context.nextTokenParent); + } + + static IsVoidOpContext(context: FormattingContext): boolean { + return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.VoidExpression; + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/rulesMap.ts b/lib/typescript/services/formatting/rulesMap.ts new file mode 100644 index 000000000..397a2331e --- /dev/null +++ b/lib/typescript/services/formatting/rulesMap.ts @@ -0,0 +1,175 @@ +/// + +/* @internal */ +module ts.formatting { + export class RulesMap { + public map: RulesBucket[]; + public mapRowLength: number; + + constructor() { + this.map = []; + this.mapRowLength = 0; + } + + static create(rules: Rule[]): RulesMap { + let result = new RulesMap(); + result.Initialize(rules); + return result; + } + + public Initialize(rules: Rule[]) { + this.mapRowLength = SyntaxKind.LastToken + 1; + this.map = new Array(this.mapRowLength * this.mapRowLength);//new Array(this.mapRowLength * this.mapRowLength); + + // This array is used only during construction of the rulesbucket in the map + let rulesBucketConstructionStateList: RulesBucketConstructionState[] = new Array(this.map.length);//new Array(this.map.length); + + this.FillRules(rules, rulesBucketConstructionStateList); + return this.map; + } + + public FillRules(rules: Rule[], rulesBucketConstructionStateList: RulesBucketConstructionState[]): void { + rules.forEach((rule) => { + this.FillRule(rule, rulesBucketConstructionStateList); + }); + } + + private GetRuleBucketIndex(row: number, column: number): number { + let rulesBucketIndex = (row * this.mapRowLength) + column; + //Debug.Assert(rulesBucketIndex < this.map.Length, "Trying to access an index outside the array."); + return rulesBucketIndex; + } + + private FillRule(rule: Rule, rulesBucketConstructionStateList: RulesBucketConstructionState[]): void { + let specificRule = rule.Descriptor.LeftTokenRange != Shared.TokenRange.Any && + rule.Descriptor.RightTokenRange != Shared.TokenRange.Any; + + rule.Descriptor.LeftTokenRange.GetTokens().forEach((left) => { + rule.Descriptor.RightTokenRange.GetTokens().forEach((right) => { + let rulesBucketIndex = this.GetRuleBucketIndex(left, right); + + let rulesBucket = this.map[rulesBucketIndex]; + if (rulesBucket == undefined) { + rulesBucket = this.map[rulesBucketIndex] = new RulesBucket(); + } + + rulesBucket.AddRule(rule, specificRule, rulesBucketConstructionStateList, rulesBucketIndex); + }) + }) + } + + public GetRule(context: FormattingContext): Rule { + let bucketIndex = this.GetRuleBucketIndex(context.currentTokenSpan.kind, context.nextTokenSpan.kind); + let bucket = this.map[bucketIndex]; + if (bucket != null) { + for (let rule of bucket.Rules()) { + if (rule.Operation.Context.InContext(context)) { + return rule; + } + } + } + return null; + } + } + + let MaskBitSize = 5; + let Mask = 0x1f; + + export enum RulesPosition { + IgnoreRulesSpecific = 0, + IgnoreRulesAny = MaskBitSize * 1, + ContextRulesSpecific = MaskBitSize * 2, + ContextRulesAny = MaskBitSize * 3, + NoContextRulesSpecific = MaskBitSize * 4, + NoContextRulesAny = MaskBitSize * 5 + } + + export class RulesBucketConstructionState { + private rulesInsertionIndexBitmap: number; + + constructor() { + //// The Rules list contains all the inserted rules into a rulebucket in the following order: + //// 1- Ignore rules with specific token combination + //// 2- Ignore rules with any token combination + //// 3- Context rules with specific token combination + //// 4- Context rules with any token combination + //// 5- Non-context rules with specific token combination + //// 6- Non-context rules with any token combination + //// + //// The member rulesInsertionIndexBitmap is used to describe the number of rules + //// in each sub-bucket (above) hence can be used to know the index of where to insert + //// the next rule. It's a bitmap which contains 6 different sections each is given 5 bits. + //// + //// Example: + //// In order to insert a rule to the end of sub-bucket (3), we get the index by adding + //// the values in the bitmap segments 3rd, 2nd, and 1st. + this.rulesInsertionIndexBitmap = 0; + } + + public GetInsertionIndex(maskPosition: RulesPosition): number { + let index = 0; + + let pos = 0; + let indexBitmap = this.rulesInsertionIndexBitmap; + + while (pos <= maskPosition) { + index += (indexBitmap & Mask); + indexBitmap >>= MaskBitSize; + pos += MaskBitSize; + } + + return index; + } + + public IncreaseInsertionIndex(maskPosition: RulesPosition): void { + let value = (this.rulesInsertionIndexBitmap >> maskPosition) & Mask; + value++; + Debug.assert((value & Mask) == value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules."); + + let temp = this.rulesInsertionIndexBitmap & ~(Mask << maskPosition); + temp |= value << maskPosition; + + this.rulesInsertionIndexBitmap = temp; + } + } + + export class RulesBucket { + private rules: Rule[]; + + constructor() { + this.rules = []; + } + + public Rules(): Rule[] { + return this.rules; + } + + public AddRule(rule: Rule, specificTokens: boolean, constructionState: RulesBucketConstructionState[], rulesBucketIndex: number): void { + let position: RulesPosition; + + if (rule.Operation.Action == RuleAction.Ignore) { + position = specificTokens ? + RulesPosition.IgnoreRulesSpecific : + RulesPosition.IgnoreRulesAny; + } + else if (!rule.Operation.Context.IsAny()) { + position = specificTokens ? + RulesPosition.ContextRulesSpecific : + RulesPosition.ContextRulesAny; + } + else { + position = specificTokens ? + RulesPosition.NoContextRulesSpecific : + RulesPosition.NoContextRulesAny; + } + + let state = constructionState[rulesBucketIndex]; + if (state === undefined) { + state = constructionState[rulesBucketIndex] = new RulesBucketConstructionState(); + } + let index = state.GetInsertionIndex(position); + this.rules.splice(index, 0, rule); + state.IncreaseInsertionIndex(position); + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/rulesProvider.ts b/lib/typescript/services/formatting/rulesProvider.ts new file mode 100644 index 000000000..c3e8cb56c --- /dev/null +++ b/lib/typescript/services/formatting/rulesProvider.ts @@ -0,0 +1,103 @@ +/// + +/* @internal */ +module ts.formatting { + export class RulesProvider { + private globalRules: Rules; + private options: ts.FormatCodeOptions; + private activeRules: Rule[]; + private rulesMap: RulesMap; + + constructor() { + this.globalRules = new Rules(); + } + + public getRuleName(rule: Rule): string { + return this.globalRules.getRuleName(rule); + } + + public getRuleByName(name: string): Rule { + return this.globalRules[name]; + } + + public getRulesMap() { + return this.rulesMap; + } + + public ensureUpToDate(options: ts.FormatCodeOptions) { + if (this.options == null || !ts.compareDataObjects(this.options, options)) { + let activeRules = this.createActiveRules(options); + let rulesMap = RulesMap.create(activeRules); + + this.activeRules = activeRules; + this.rulesMap = rulesMap; + this.options = ts.clone(options); + } + } + + private createActiveRules(options: ts.FormatCodeOptions): Rule[] { + let rules = this.globalRules.HighPriorityCommonRules.slice(0); + + if (options.InsertSpaceAfterCommaDelimiter) { + rules.push(this.globalRules.SpaceAfterComma); + } + else { + rules.push(this.globalRules.NoSpaceAfterComma); + } + + if (options.InsertSpaceAfterFunctionKeywordForAnonymousFunctions) { + rules.push(this.globalRules.SpaceAfterAnonymousFunctionKeyword); + } + else { + rules.push(this.globalRules.NoSpaceAfterAnonymousFunctionKeyword); + } + + if (options.InsertSpaceAfterKeywordsInControlFlowStatements) { + rules.push(this.globalRules.SpaceAfterKeywordInControl); + } + else { + rules.push(this.globalRules.NoSpaceAfterKeywordInControl); + } + + if (options.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis) { + rules.push(this.globalRules.SpaceAfterOpenParen); + rules.push(this.globalRules.SpaceBeforeCloseParen); + rules.push(this.globalRules.NoSpaceBetweenParens); + } + else { + rules.push(this.globalRules.NoSpaceAfterOpenParen); + rules.push(this.globalRules.NoSpaceBeforeCloseParen); + rules.push(this.globalRules.NoSpaceBetweenParens); + } + + if (options.InsertSpaceAfterSemicolonInForStatements) { + rules.push(this.globalRules.SpaceAfterSemicolonInFor); + } + else { + rules.push(this.globalRules.NoSpaceAfterSemicolonInFor); + } + + if (options.InsertSpaceBeforeAndAfterBinaryOperators) { + rules.push(this.globalRules.SpaceBeforeBinaryOperator); + rules.push(this.globalRules.SpaceAfterBinaryOperator); + } + else { + rules.push(this.globalRules.NoSpaceBeforeBinaryOperator); + rules.push(this.globalRules.NoSpaceAfterBinaryOperator); + } + + if (options.PlaceOpenBraceOnNewLineForControlBlocks) { + rules.push(this.globalRules.NewLineBeforeOpenBraceInControl); + } + + if (options.PlaceOpenBraceOnNewLineForFunctions) { + rules.push(this.globalRules.NewLineBeforeOpenBraceInFunction); + rules.push(this.globalRules.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock); + } + + rules = rules.concat(this.globalRules.LowPriorityCommonRules); + + return rules; + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/smartIndenter.ts b/lib/typescript/services/formatting/smartIndenter.ts new file mode 100644 index 000000000..91d9f18a9 --- /dev/null +++ b/lib/typescript/services/formatting/smartIndenter.ts @@ -0,0 +1,404 @@ +/// + +/* @internal */ +module ts.formatting { + export module SmartIndenter { + + const enum Value { + Unknown = -1 + } + + export function getIndentation(position: number, sourceFile: SourceFile, options: EditorOptions): number { + if (position > sourceFile.text.length) { + return 0; // past EOF + } + + let precedingToken = findPrecedingToken(position, sourceFile); + if (!precedingToken) { + return 0; + } + + // no indentation in string \regex\template literals + let precedingTokenIsLiteral = + precedingToken.kind === SyntaxKind.StringLiteral || + precedingToken.kind === SyntaxKind.RegularExpressionLiteral || + precedingToken.kind === SyntaxKind.NoSubstitutionTemplateLiteral || + precedingToken.kind === SyntaxKind.TemplateHead || + precedingToken.kind === SyntaxKind.TemplateMiddle || + precedingToken.kind === SyntaxKind.TemplateTail; + if (precedingTokenIsLiteral && precedingToken.getStart(sourceFile) <= position && precedingToken.end > position) { + return 0; + } + + let lineAtPosition = sourceFile.getLineAndCharacterOfPosition(position).line; + + if (precedingToken.kind === SyntaxKind.CommaToken && precedingToken.parent.kind !== SyntaxKind.BinaryExpression) { + // previous token is comma that separates items in list - find the previous item and try to derive indentation from it + let actualIndentation = getActualIndentationForListItemBeforeComma(precedingToken, sourceFile, options); + if (actualIndentation !== Value.Unknown) { + return actualIndentation; + } + } + + // try to find node that can contribute to indentation and includes 'position' starting from 'precedingToken' + // if such node is found - compute initial indentation for 'position' inside this node + let previous: Node; + let current = precedingToken; + let currentStart: LineAndCharacter; + let indentationDelta: number; + + while (current) { + if (positionBelongsToNode(current, position, sourceFile) && shouldIndentChildNode(current.kind, previous ? previous.kind : SyntaxKind.Unknown)) { + currentStart = getStartLineAndCharacterForNode(current, sourceFile); + + if (nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile)) { + indentationDelta = 0; + } + else { + indentationDelta = lineAtPosition !== currentStart.line ? options.IndentSize : 0; + } + + break; + } + + // check if current node is a list item - if yes, take indentation from it + let actualIndentation = getActualIndentationForListItem(current, sourceFile, options); + if (actualIndentation !== Value.Unknown) { + return actualIndentation; + } + + previous = current; + current = current.parent; + } + + if (!current) { + // no parent was found - return 0 to be indented on the level of SourceFile + return 0; + } + + return getIndentationForNodeWorker(current, currentStart, /*ignoreActualIndentationRange*/ undefined, indentationDelta, sourceFile, options); + } + + export function getIndentationForNode(n: Node, ignoreActualIndentationRange: TextRange, sourceFile: SourceFile, options: FormatCodeOptions): number { + let start = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)); + return getIndentationForNodeWorker(n, start, ignoreActualIndentationRange, /*indentationDelta*/ 0, sourceFile, options); + } + + function getIndentationForNodeWorker( + current: Node, + currentStart: LineAndCharacter, + ignoreActualIndentationRange: TextRange, + indentationDelta: number, + sourceFile: SourceFile, + options: EditorOptions): number { + + let parent: Node = current.parent; + let parentStart: LineAndCharacter; + + // walk upwards and collect indentations for pairs of parent-child nodes + // indentation is not added if parent and child nodes start on the same line or if parent is IfStatement and child starts on the same line with 'else clause' + while (parent) { + let useActualIndentation = true; + if (ignoreActualIndentationRange) { + let start = current.getStart(sourceFile); + useActualIndentation = start < ignoreActualIndentationRange.pos || start > ignoreActualIndentationRange.end; + } + + if (useActualIndentation) { + // check if current node is a list item - if yes, take indentation from it + let actualIndentation = getActualIndentationForListItem(current, sourceFile, options); + if (actualIndentation !== Value.Unknown) { + return actualIndentation + indentationDelta; + } + } + parentStart = getParentStart(parent, current, sourceFile); + let parentAndChildShareLine = + parentStart.line === currentStart.line || + childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile); + + if (useActualIndentation) { + // try to fetch actual indentation for current node from source text + let actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options); + if (actualIndentation !== Value.Unknown) { + return actualIndentation + indentationDelta; + } + } + + // increase indentation if parent node wants its content to be indented and parent and child nodes don't start on the same line + if (shouldIndentChildNode(parent.kind, current.kind) && !parentAndChildShareLine) { + indentationDelta += options.IndentSize; + } + + current = parent; + currentStart = parentStart; + parent = current.parent; + } + + return indentationDelta; + } + + + function getParentStart(parent: Node, child: Node, sourceFile: SourceFile): LineAndCharacter { + let containingList = getContainingList(child, sourceFile); + if (containingList) { + return sourceFile.getLineAndCharacterOfPosition(containingList.pos); + } + + return sourceFile.getLineAndCharacterOfPosition(parent.getStart(sourceFile)); + } + + /* + * Function returns Value.Unknown if indentation cannot be determined + */ + function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: EditorOptions): number { + // previous token is comma that separates items in list - find the previous item and try to derive indentation from it + let commaItemInfo = findListItemInfo(commaToken); + if (commaItemInfo && commaItemInfo.listItemIndex > 0) { + return deriveActualIndentationFromList(commaItemInfo.list.getChildren(), commaItemInfo.listItemIndex - 1, sourceFile, options); + } + else { + // handle broken code gracefully + return Value.Unknown; + } + } + + /* + * Function returns Value.Unknown if actual indentation for node should not be used (i.e because node is nested expression) + */ + function getActualIndentationForNode(current: Node, + parent: Node, + currentLineAndChar: LineAndCharacter, + parentAndChildShareLine: boolean, + sourceFile: SourceFile, + options: EditorOptions): number { + + // actual indentation is used for statements\declarations if one of cases below is true: + // - parent is SourceFile - by default immediate children of SourceFile are not indented except when user indents them manually + // - parent and child are not on the same line + let useActualIndentation = + (isDeclaration(current) || isStatement(current)) && + (parent.kind === SyntaxKind.SourceFile || !parentAndChildShareLine); + + if (!useActualIndentation) { + return Value.Unknown; + } + + return findColumnForFirstNonWhitespaceCharacterInLine(currentLineAndChar, sourceFile, options); + } + + function nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken: Node, current: Node, lineAtPosition: number, sourceFile: SourceFile): boolean { + let nextToken = findNextToken(precedingToken, current); + if (!nextToken) { + return false; + } + + if (nextToken.kind === SyntaxKind.OpenBraceToken) { + // open braces are always indented at the parent level + return true; + } + else if (nextToken.kind === SyntaxKind.CloseBraceToken) { + // close braces are indented at the parent level if they are located on the same line with cursor + // this means that if new line will be added at $ position, this case will be indented + // class A { + // $ + // } + /// and this one - not + // class A { + // $} + + let nextTokenStartLine = getStartLineAndCharacterForNode(nextToken, sourceFile).line; + return lineAtPosition === nextTokenStartLine; + } + + return false; + } + + function getStartLineAndCharacterForNode(n: Node, sourceFile: SourceFile): LineAndCharacter { + return sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)); + } + + export function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFile): boolean { + if (parent.kind === SyntaxKind.IfStatement && (parent).elseStatement === child) { + let elseKeyword = findChildOfKind(parent, SyntaxKind.ElseKeyword, sourceFile); + Debug.assert(elseKeyword !== undefined); + + let elseKeywordStartLine = getStartLineAndCharacterForNode(elseKeyword, sourceFile).line; + return elseKeywordStartLine === childStartLine; + } + + return false; + } + + function getContainingList(node: Node, sourceFile: SourceFile): NodeArray { + if (node.parent) { + switch (node.parent.kind) { + case SyntaxKind.TypeReference: + if ((node.parent).typeArguments && + rangeContainsStartEnd((node.parent).typeArguments, node.getStart(sourceFile), node.getEnd())) { + return (node.parent).typeArguments; + } + break; + case SyntaxKind.ObjectLiteralExpression: + return (node.parent).properties; + case SyntaxKind.ArrayLiteralExpression: + return (node.parent).elements; + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: { + let start = node.getStart(sourceFile); + if ((node.parent).typeParameters && + rangeContainsStartEnd((node.parent).typeParameters, start, node.getEnd())) { + return (node.parent).typeParameters; + } + if (rangeContainsStartEnd((node.parent).parameters, start, node.getEnd())) { + return (node.parent).parameters; + } + break; + } + case SyntaxKind.NewExpression: + case SyntaxKind.CallExpression: { + let start = node.getStart(sourceFile); + if ((node.parent).typeArguments && + rangeContainsStartEnd((node.parent).typeArguments, start, node.getEnd())) { + return (node.parent).typeArguments; + } + if ((node.parent).arguments && + rangeContainsStartEnd((node.parent).arguments, start, node.getEnd())) { + return (node.parent).arguments; + } + break; + } + } + } + return undefined; + } + + function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorOptions): number { + let containingList = getContainingList(node, sourceFile); + return containingList ? getActualIndentationFromList(containingList) : Value.Unknown; + + function getActualIndentationFromList(list: Node[]): number { + let index = indexOf(list, node); + return index !== -1 ? deriveActualIndentationFromList(list, index, sourceFile, options) : Value.Unknown; + } + } + + function deriveActualIndentationFromList(list: Node[], index: number, sourceFile: SourceFile, options: EditorOptions): number { + Debug.assert(index >= 0 && index < list.length); + let node = list[index]; + + // walk toward the start of the list starting from current node and check if the line is the same for all items. + // if end line for item [i - 1] differs from the start line for item [i] - find column of the first non-whitespace character on the line of item [i] + let lineAndCharacter = getStartLineAndCharacterForNode(node, sourceFile); + for (let i = index - 1; i >= 0; --i) { + if (list[i].kind === SyntaxKind.CommaToken) { + continue; + } + // skip list items that ends on the same line with the current list element + let prevEndLine = sourceFile.getLineAndCharacterOfPosition(list[i].end).line; + if (prevEndLine !== lineAndCharacter.line) { + return findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter, sourceFile, options); + } + + lineAndCharacter = getStartLineAndCharacterForNode(list[i], sourceFile); + } + return Value.Unknown; + } + + function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter: LineAndCharacter, sourceFile: SourceFile, options: EditorOptions): number { + let lineStart = sourceFile.getPositionOfLineAndCharacter(lineAndCharacter.line, 0); + return findFirstNonWhitespaceColumn(lineStart, lineStart + lineAndCharacter.character, sourceFile, options); + } + + /* + Character is the actual index of the character since the beginning of the line. + Column - position of the character after expanding tabs to spaces + "0\t2$" + value of 'character' for '$' is 3 + value of 'column' for '$' is 6 (assuming that tab size is 4) + */ + export function findFirstNonWhitespaceCharacterAndColumn(startPos: number, endPos: number, sourceFile: SourceFile, options: EditorOptions) { + let character = 0; + let column = 0; + for (let pos = startPos; pos < endPos; ++pos) { + let ch = sourceFile.text.charCodeAt(pos); + if (!isWhiteSpace(ch)) { + break; + } + + if (ch === CharacterCodes.tab) { + column += options.TabSize + (column % options.TabSize); + } + else { + column++; + } + + character++; + } + return { column, character }; + } + + export function findFirstNonWhitespaceColumn(startPos: number, endPos: number, sourceFile: SourceFile, options: EditorOptions): number { + return findFirstNonWhitespaceCharacterAndColumn(startPos, endPos, sourceFile, options).column; + } + + function nodeContentIsAlwaysIndented(kind: SyntaxKind): boolean { + switch (kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.Block: + case SyntaxKind.ModuleBlock: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.TypeLiteral: + case SyntaxKind.TupleType: + case SyntaxKind.CaseBlock: + case SyntaxKind.DefaultClause: + case SyntaxKind.CaseClause: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + case SyntaxKind.VariableStatement: + case SyntaxKind.VariableDeclaration: + case SyntaxKind.ExportAssignment: + case SyntaxKind.ReturnStatement: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.ObjectBindingPattern: + return true; + } + return false; + } + + export function shouldIndentChildNode(parent: SyntaxKind, child: SyntaxKind): boolean { + if (nodeContentIsAlwaysIndented(parent)) { + return true; + } + switch (parent) { + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.ArrowFunction: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return child !== SyntaxKind.Block; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/formatting/tokenRange.ts b/lib/typescript/services/formatting/tokenRange.ts new file mode 100644 index 000000000..bb3b720bf --- /dev/null +++ b/lib/typescript/services/formatting/tokenRange.ts @@ -0,0 +1,126 @@ +/// + +/* @internal */ +module ts.formatting { + export module Shared { + export interface ITokenAccess { + GetTokens(): SyntaxKind[]; + Contains(token: SyntaxKind): boolean; + } + + export class TokenRangeAccess implements ITokenAccess { + private tokens: SyntaxKind[]; + + constructor(from: SyntaxKind, to: SyntaxKind, except: SyntaxKind[]) { + this.tokens = []; + for (let token = from; token <= to; token++) { + if (except.indexOf(token) < 0) { + this.tokens.push(token); + } + } + } + + public GetTokens(): SyntaxKind[] { + return this.tokens; + } + + public Contains(token: SyntaxKind): boolean { + return this.tokens.indexOf(token) >= 0; + } + } + + export class TokenValuesAccess implements ITokenAccess { + private tokens: SyntaxKind[]; + + constructor(tks: SyntaxKind[]) { + this.tokens = tks && tks.length ? tks : []; + } + + public GetTokens(): SyntaxKind[] { + return this.tokens; + } + + public Contains(token: SyntaxKind): boolean { + return this.tokens.indexOf(token) >= 0; + } + } + + export class TokenSingleValueAccess implements ITokenAccess { + constructor(public token: SyntaxKind) { + } + + public GetTokens(): SyntaxKind[] { + return [this.token]; + } + + public Contains(tokenValue: SyntaxKind): boolean { + return tokenValue == this.token; + } + } + + export class TokenAllAccess implements ITokenAccess { + public GetTokens(): SyntaxKind[] { + let result: SyntaxKind[] = []; + for (let token = SyntaxKind.FirstToken; token <= SyntaxKind.LastToken; token++) { + result.push(token); + } + return result; + } + + public Contains(tokenValue: SyntaxKind): boolean { + return true; + } + + public toString(): string { + return "[allTokens]"; + } + } + + export class TokenRange { + constructor(public tokenAccess: ITokenAccess) { + } + + static FromToken(token: SyntaxKind): TokenRange { + return new TokenRange(new TokenSingleValueAccess(token)); + } + + static FromTokens(tokens: SyntaxKind[]): TokenRange { + return new TokenRange(new TokenValuesAccess(tokens)); + } + + static FromRange(f: SyntaxKind, to: SyntaxKind, except: SyntaxKind[] = []): TokenRange { + return new TokenRange(new TokenRangeAccess(f, to, except)); + } + + static AllTokens(): TokenRange { + return new TokenRange(new TokenAllAccess()); + } + + public GetTokens(): SyntaxKind[] { + return this.tokenAccess.GetTokens(); + } + + public Contains(token: SyntaxKind): boolean { + return this.tokenAccess.Contains(token); + } + + public toString(): string { + return this.tokenAccess.toString(); + } + + static Any: TokenRange = TokenRange.AllTokens(); + static AnyIncludingMultilineComments = TokenRange.FromTokens(TokenRange.Any.GetTokens().concat([SyntaxKind.MultiLineCommentTrivia])); + static Keywords = TokenRange.FromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword); + static BinaryOperators = TokenRange.FromRange(SyntaxKind.FirstBinaryOperator, SyntaxKind.LastBinaryOperator); + static BinaryKeywordOperators = TokenRange.FromTokens([SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword, SyntaxKind.OfKeyword]); + static UnaryPrefixOperators = TokenRange.FromTokens([SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]); + static UnaryPrefixExpressions = TokenRange.FromTokens([SyntaxKind.NumericLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]); + static UnaryPreincrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]); + static UnaryPostincrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]); + static UnaryPredecrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]); + static UnaryPostdecrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]); + static Comments = TokenRange.FromTokens([SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]); + static TypeNames = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.SymbolKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]); + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/navigateTo.ts b/lib/typescript/services/navigateTo.ts new file mode 100644 index 000000000..6d399c5b0 --- /dev/null +++ b/lib/typescript/services/navigateTo.ts @@ -0,0 +1,194 @@ +/* @internal */ +module ts.NavigateTo { + type RawNavigateToItem = { name: string; fileName: string; matchKind: PatternMatchKind; isCaseSensitive: boolean; declaration: Declaration }; + + export function getNavigateToItems(program: Program, cancellationToken: CancellationTokenObject, searchValue: string, maxResultCount: number): NavigateToItem[] { + let patternMatcher = createPatternMatcher(searchValue); + let rawItems: RawNavigateToItem[] = []; + + // Search the declarations in all files and output matched NavigateToItem into array of NavigateToItem[] + forEach(program.getSourceFiles(), sourceFile => { + cancellationToken.throwIfCancellationRequested(); + + let nameToDeclarations = sourceFile.getNamedDeclarations(); + for (let name in nameToDeclarations) { + let declarations = getProperty(nameToDeclarations, name); + if (declarations) { + // First do a quick check to see if the name of the declaration matches the + // last portion of the (possibly) dotted name they're searching for. + let matches = patternMatcher.getMatchesForLastSegmentOfPattern(name); + + if (!matches) { + continue; + } + + for (let declaration of declarations) { + // It was a match! If the pattern has dots in it, then also see if the + // declaration container matches as well. + if (patternMatcher.patternContainsDots) { + let containers = getContainers(declaration); + if (!containers) { + return undefined; + } + + matches = patternMatcher.getMatches(containers, name); + + if (!matches) { + continue; + } + } + + let fileName = sourceFile.fileName; + let matchKind = bestMatchKind(matches); + rawItems.push({ name, fileName, matchKind, isCaseSensitive: allMatchesAreCaseSensitive(matches), declaration }); + } + } + } + }); + + rawItems.sort(compareNavigateToItems); + if (maxResultCount !== undefined) { + rawItems = rawItems.slice(0, maxResultCount); + } + + let items = map(rawItems, createNavigateToItem); + + return items; + + function allMatchesAreCaseSensitive(matches: PatternMatch[]): boolean { + Debug.assert(matches.length > 0); + + // This is a case sensitive match, only if all the submatches were case sensitive. + for (let match of matches) { + if (!match.isCaseSensitive) { + return false; + } + } + + return true; + } + + function getTextOfIdentifierOrLiteral(node: Node) { + if (node) { + if (node.kind === SyntaxKind.Identifier || + node.kind === SyntaxKind.StringLiteral || + node.kind === SyntaxKind.NumericLiteral) { + + return (node).text; + } + } + + return undefined; + } + + function tryAddSingleDeclarationName(declaration: Declaration, containers: string[]) { + if (declaration && declaration.name) { + let text = getTextOfIdentifierOrLiteral(declaration.name); + if (text !== undefined) { + containers.unshift(text); + } + else if (declaration.name.kind === SyntaxKind.ComputedPropertyName) { + return tryAddComputedPropertyName((declaration.name).expression, containers, /*includeLastPortion:*/ true); + } + else { + // Don't know how to add this. + return false + } + } + + return true; + } + + // Only added the names of computed properties if they're simple dotted expressions, like: + // + // [X.Y.Z]() { } + function tryAddComputedPropertyName(expression: Expression, containers: string[], includeLastPortion: boolean): boolean { + let text = getTextOfIdentifierOrLiteral(expression); + if (text !== undefined) { + if (includeLastPortion) { + containers.unshift(text); + } + return true; + } + + if (expression.kind === SyntaxKind.PropertyAccessExpression) { + let propertyAccess = expression; + if (includeLastPortion) { + containers.unshift(propertyAccess.name.text); + } + + return tryAddComputedPropertyName(propertyAccess.expression, containers, /*includeLastPortion:*/ true); + } + + return false; + } + + function getContainers(declaration: Declaration) { + let containers: string[] = []; + + // First, if we started with a computed property name, then add all but the last + // portion into the container array. + if (declaration.name.kind === SyntaxKind.ComputedPropertyName) { + if (!tryAddComputedPropertyName((declaration.name).expression, containers, /*includeLastPortion:*/ false)) { + return undefined; + } + } + + // Now, walk up our containers, adding all their names to the container array. + declaration = getContainerNode(declaration); + + while (declaration) { + if (!tryAddSingleDeclarationName(declaration, containers)) { + return undefined; + } + + declaration = getContainerNode(declaration); + } + + return containers; + } + + function bestMatchKind(matches: PatternMatch[]) { + Debug.assert(matches.length > 0); + let bestMatchKind = PatternMatchKind.camelCase; + + for (let match of matches) { + let kind = match.kind; + if (kind < bestMatchKind) { + bestMatchKind = kind; + } + } + + return bestMatchKind; + } + + // This means "compare in a case insensitive manner." + let baseSensitivity: Intl.CollatorOptions = { sensitivity: "base" }; + function compareNavigateToItems(i1: RawNavigateToItem, i2: RawNavigateToItem) { + // TODO(cyrusn): get the gamut of comparisons that VS already uses here. + // Right now we just sort by kind first, and then by name of the item. + // We first sort case insensitively. So "Aaa" will come before "bar". + // Then we sort case sensitively, so "aaa" will come before "Aaa". + return i1.matchKind - i2.matchKind || + i1.name.localeCompare(i2.name, undefined, baseSensitivity) || + i1.name.localeCompare(i2.name); + } + + function createNavigateToItem(rawItem: RawNavigateToItem): NavigateToItem { + let declaration = rawItem.declaration; + let container = getContainerNode(declaration); + return { + name: rawItem.name, + kind: getNodeKind(declaration), + kindModifiers: getNodeModifiers(declaration), + matchKind: PatternMatchKind[rawItem.matchKind], + isCaseSensitive: rawItem.isCaseSensitive, + fileName: rawItem.fileName, + textSpan: createTextSpanFromBounds(declaration.getStart(), declaration.getEnd()), + // TODO(jfreeman): What should be the containerName when the container has a computed name? + containerName: container && container.name ? (container.name).text : "", + containerKind: container && container.name ? getNodeKind(container) : "" + }; + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/navigationBar.ts b/lib/typescript/services/navigationBar.ts new file mode 100644 index 000000000..5e5f40802 --- /dev/null +++ b/lib/typescript/services/navigationBar.ts @@ -0,0 +1,537 @@ +/// + +/* @internal */ +module ts.NavigationBar { + export function getNavigationBarItems(sourceFile: SourceFile): ts.NavigationBarItem[] { + // If the source file has any child items, then it included in the tree + // and takes lexical ownership of all other top-level items. + let hasGlobalNode = false; + + return getItemsWorker(getTopLevelNodes(sourceFile), createTopLevelItem); + + function getIndent(node: Node): number { + // If we have a global node in the tree, + // then it adds an extra layer of depth to all subnodes. + let indent = hasGlobalNode ? 1 : 0; + + let current = node.parent; + while (current) { + switch (current.kind) { + case SyntaxKind.ModuleDeclaration: + // If we have a module declared as A.B.C, it is more "intuitive" + // to say it only has a single layer of depth + do { + current = current.parent; + } + while (current.kind === SyntaxKind.ModuleDeclaration); + + // fall through + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.FunctionDeclaration: + indent++; + } + + current = current.parent; + } + + return indent; + } + + function getChildNodes(nodes: Node[]): Node[] { + let childNodes: Node[] = []; + + function visit(node: Node) { + switch (node.kind) { + case SyntaxKind.VariableStatement: + forEach((node).declarationList.declarations, visit); + break; + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + forEach((node).elements, visit); + break; + + case SyntaxKind.ExportDeclaration: + // Handle named exports case e.g.: + // export {a, b as B} from "mod"; + if ((node).exportClause) { + forEach((node).exportClause.elements, visit); + } + break; + + case SyntaxKind.ImportDeclaration: + let importClause = (node).importClause; + if (importClause) { + // Handle default import case e.g.: + // import d from "mod"; + if (importClause.name) { + childNodes.push(importClause); + } + + // Handle named bindings in imports e.g.: + // import * as NS from "mod"; + // import {a, b as B} from "mod"; + if (importClause.namedBindings) { + if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + childNodes.push(importClause.namedBindings); + } + else { + forEach((importClause.namedBindings).elements, visit); + } + } + } + break; + + case SyntaxKind.BindingElement: + case SyntaxKind.VariableDeclaration: + if (isBindingPattern((node).name)) { + visit((node).name); + break; + } + // Fall through + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ExportSpecifier: + childNodes.push(node); + break; + } + } + + //for (let i = 0, n = nodes.length; i < n; i++) { + // let node = nodes[i]; + + // if (node.kind === SyntaxKind.ClassDeclaration || + // node.kind === SyntaxKind.EnumDeclaration || + // node.kind === SyntaxKind.InterfaceDeclaration || + // node.kind === SyntaxKind.ModuleDeclaration || + // node.kind === SyntaxKind.FunctionDeclaration) { + + // childNodes.push(node); + // } + // else if (node.kind === SyntaxKind.VariableStatement) { + // childNodes.push.apply(childNodes, (node).declarations); + // } + //} + forEach(nodes, visit); + return sortNodes(childNodes); + } + + function getTopLevelNodes(node: SourceFile): Node[] { + let topLevelNodes: Node[] = []; + topLevelNodes.push(node); + + addTopLevelNodes(node.statements, topLevelNodes); + + return topLevelNodes; + } + + function sortNodes(nodes: Node[]): Node[] { + return nodes.slice(0).sort((n1: Declaration, n2: Declaration) => { + if (n1.name && n2.name) { + return getPropertyNameForPropertyNameNode(n1.name).localeCompare(getPropertyNameForPropertyNameNode(n2.name)); + } + else if (n1.name) { + return 1; + } + else if (n2.name) { + return -1; + } + else { + return n1.kind - n2.kind; + } + }); + } + + function addTopLevelNodes(nodes: Node[], topLevelNodes: Node[]): void { + nodes = sortNodes(nodes); + + for (let node of nodes) { + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.InterfaceDeclaration: + topLevelNodes.push(node); + break; + + case SyntaxKind.ModuleDeclaration: + let moduleDeclaration = node; + topLevelNodes.push(node); + addTopLevelNodes((getInnermostModule(moduleDeclaration).body).statements, topLevelNodes); + break; + + case SyntaxKind.FunctionDeclaration: + let functionDeclaration = node; + if (isTopLevelFunctionDeclaration(functionDeclaration)) { + topLevelNodes.push(node); + addTopLevelNodes((functionDeclaration.body).statements, topLevelNodes); + } + break; + } + } + } + + function isTopLevelFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration) { + if (functionDeclaration.kind === SyntaxKind.FunctionDeclaration) { + // A function declaration is 'top level' if it contains any function declarations + // within it. + if (functionDeclaration.body && functionDeclaration.body.kind === SyntaxKind.Block) { + // Proper function declarations can only have identifier names + if (forEach((functionDeclaration.body).statements, + s => s.kind === SyntaxKind.FunctionDeclaration && !isEmpty((s).name.text))) { + + return true; + } + + // Or if it is not parented by another function. i.e all functions + // at module scope are 'top level'. + if (!isFunctionBlock(functionDeclaration.parent)) { + return true; + } + } + } + + return false; + } + + function getItemsWorker(nodes: Node[], createItem: (n: Node) => ts.NavigationBarItem): ts.NavigationBarItem[] { + let items: ts.NavigationBarItem[] = []; + + let keyToItem: Map = {}; + + for (let child of nodes) { + let item = createItem(child); + if (item !== undefined) { + if (item.text.length > 0) { + let key = item.text + "-" + item.kind + "-" + item.indent; + + let itemWithSameName = keyToItem[key]; + if (itemWithSameName) { + // We had an item with the same name. Merge these items together. + merge(itemWithSameName, item); + } + else { + keyToItem[key] = item; + items.push(item); + } + } + } + } + + return items; + } + + function merge(target: ts.NavigationBarItem, source: ts.NavigationBarItem) { + // First, add any spans in the source to the target. + target.spans.push.apply(target.spans, source.spans); + + if (source.childItems) { + if (!target.childItems) { + target.childItems = []; + } + + // Next, recursively merge or add any children in the source as appropriate. + outer: + for (let sourceChild of source.childItems) { + for (let targetChild of target.childItems) { + if (targetChild.text === sourceChild.text && targetChild.kind === sourceChild.kind) { + // Found a match. merge them. + merge(targetChild, sourceChild); + continue outer; + } + } + + // Didn't find a match, just add this child to the list. + target.childItems.push(sourceChild); + } + } + } + + function createChildItem(node: Node): ts.NavigationBarItem { + switch (node.kind) { + case SyntaxKind.Parameter: + if (isBindingPattern((node).name)) { + break; + } + if ((node.flags & NodeFlags.Modifier) === 0) { + return undefined; + } + return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberVariableElement); + + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberFunctionElement); + + case SyntaxKind.GetAccessor: + return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberGetAccessorElement); + + case SyntaxKind.SetAccessor: + return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberSetAccessorElement); + + case SyntaxKind.IndexSignature: + return createItem(node, "[]", ts.ScriptElementKind.indexSignatureElement); + + case SyntaxKind.EnumMember: + return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberVariableElement); + + case SyntaxKind.CallSignature: + return createItem(node, "()", ts.ScriptElementKind.callSignatureElement); + + case SyntaxKind.ConstructSignature: + return createItem(node, "new()", ts.ScriptElementKind.constructSignatureElement); + + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberVariableElement); + + case SyntaxKind.FunctionDeclaration: + return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.functionElement); + + case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: + let variableDeclarationNode: Node; + let name: Node; + + if (node.kind === SyntaxKind.BindingElement) { + name = (node).name; + variableDeclarationNode = node; + // binding elements are added only for variable declarations + // bubble up to the containing variable declaration + while (variableDeclarationNode && variableDeclarationNode.kind !== SyntaxKind.VariableDeclaration) { + variableDeclarationNode = variableDeclarationNode.parent; + } + Debug.assert(variableDeclarationNode !== undefined); + } + else { + Debug.assert(!isBindingPattern((node).name)); + variableDeclarationNode = node; + name = (node).name; + } + + if (isConst(variableDeclarationNode)) { + return createItem(node, getTextOfNode(name), ts.ScriptElementKind.constElement); + } + else if (isLet(variableDeclarationNode)) { + return createItem(node, getTextOfNode(name), ts.ScriptElementKind.letElement); + } + else { + return createItem(node, getTextOfNode(name), ts.ScriptElementKind.variableElement); + } + + case SyntaxKind.Constructor: + return createItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement); + + case SyntaxKind.ExportSpecifier: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportClause: + case SyntaxKind.NamespaceImport: + return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.alias); + } + + return undefined; + + function createItem(node: Node, name: string, scriptElementKind: string): NavigationBarItem { + return getNavigationBarItem(name, scriptElementKind, getNodeModifiers(node), [getNodeSpan(node)]); + } + } + + function isEmpty(text: string) { + return !text || text.trim() === ""; + } + + function getNavigationBarItem(text: string, kind: string, kindModifiers: string, spans: TextSpan[], childItems: NavigationBarItem[] = [], indent: number = 0): NavigationBarItem { + if (isEmpty(text)) { + return undefined; + } + + return { + text, + kind, + kindModifiers, + spans, + childItems, + indent, + bolded: false, + grayed: false + }; + } + + function createTopLevelItem(node: Node): ts.NavigationBarItem { + switch (node.kind) { + case SyntaxKind.SourceFile: + return createSourceFileItem(node); + + case SyntaxKind.ClassDeclaration: + return createClassItem(node); + + case SyntaxKind.EnumDeclaration: + return createEnumItem(node); + + case SyntaxKind.InterfaceDeclaration: + return createIterfaceItem(node); + + case SyntaxKind.ModuleDeclaration: + return createModuleItem(node); + + case SyntaxKind.FunctionDeclaration: + return createFunctionItem(node); + } + + return undefined; + + function getModuleName(moduleDeclaration: ModuleDeclaration): string { + // We want to maintain quotation marks. + if (moduleDeclaration.name.kind === SyntaxKind.StringLiteral) { + return getTextOfNode(moduleDeclaration.name); + } + + // Otherwise, we need to aggregate each identifier to build up the qualified name. + let result: string[] = []; + + result.push(moduleDeclaration.name.text); + + while (moduleDeclaration.body && moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) { + moduleDeclaration = moduleDeclaration.body; + + result.push(moduleDeclaration.name.text); + } + + return result.join("."); + } + + function createModuleItem(node: ModuleDeclaration): NavigationBarItem { + let moduleName = getModuleName(node); + + let childItems = getItemsWorker(getChildNodes((getInnermostModule(node).body).statements), createChildItem); + + return getNavigationBarItem(moduleName, + ts.ScriptElementKind.moduleElement, + getNodeModifiers(node), + [getNodeSpan(node)], + childItems, + getIndent(node)); + } + + function createFunctionItem(node: FunctionDeclaration) { + if (node.body && node.body.kind === SyntaxKind.Block) { + let childItems = getItemsWorker(sortNodes((node.body).statements), createChildItem); + + return getNavigationBarItem(!node.name ? "default": node.name.text , + ts.ScriptElementKind.functionElement, + getNodeModifiers(node), + [getNodeSpan(node)], + childItems, + getIndent(node)); + } + + return undefined; + } + + function createSourceFileItem(node: SourceFile): ts.NavigationBarItem { + let childItems = getItemsWorker(getChildNodes(node.statements), createChildItem); + + if (childItems === undefined || childItems.length === 0) { + return undefined; + } + + hasGlobalNode = true; + let rootName = isExternalModule(node) + ? "\"" + escapeString(getBaseFileName(removeFileExtension(normalizePath(node.fileName)))) + "\"" + : "" + + return getNavigationBarItem(rootName, + ts.ScriptElementKind.moduleElement, + ts.ScriptElementKindModifier.none, + [getNodeSpan(node)], + childItems); + } + + function createClassItem(node: ClassDeclaration): ts.NavigationBarItem { + let childItems: NavigationBarItem[]; + + if (node.members) { + let constructor = forEach(node.members, member => { + return member.kind === SyntaxKind.Constructor && member; + }); + + // Add the constructor parameters in as children of the class (for property parameters). + // Note that *all non-binding pattern named* parameters will be added to the nodes array, but parameters that + // are not properties will be filtered out later by createChildItem. + let nodes: Node[] = removeDynamicallyNamedProperties(node); + if (constructor) { + nodes.push.apply(nodes, filter(constructor.parameters, p => !isBindingPattern(p.name))); + } + + childItems = getItemsWorker(sortNodes(nodes), createChildItem); + } + + var nodeName = !node.name ? "default" : node.name.text; + + return getNavigationBarItem( + nodeName, + ts.ScriptElementKind.classElement, + getNodeModifiers(node), + [getNodeSpan(node)], + childItems, + getIndent(node)); + } + + function createEnumItem(node: EnumDeclaration): ts.NavigationBarItem { + let childItems = getItemsWorker(sortNodes(removeComputedProperties(node)), createChildItem); + return getNavigationBarItem( + node.name.text, + ts.ScriptElementKind.enumElement, + getNodeModifiers(node), + [getNodeSpan(node)], + childItems, + getIndent(node)); + } + + function createIterfaceItem(node: InterfaceDeclaration): ts.NavigationBarItem { + let childItems = getItemsWorker(sortNodes(removeDynamicallyNamedProperties(node)), createChildItem); + return getNavigationBarItem( + node.name.text, + ts.ScriptElementKind.interfaceElement, + getNodeModifiers(node), + [getNodeSpan(node)], + childItems, + getIndent(node)); + } + } + + function removeComputedProperties(node: EnumDeclaration): Declaration[] { + return filter(node.members, member => member.name === undefined || member.name.kind !== SyntaxKind.ComputedPropertyName); + } + + /** + * Like removeComputedProperties, but retains the properties with well known symbol names + */ + function removeDynamicallyNamedProperties(node: ClassDeclaration | InterfaceDeclaration): Declaration[]{ + return filter(node.members, member => !hasDynamicName(member)); + } + + function getInnermostModule(node: ModuleDeclaration): ModuleDeclaration { + while (node.body.kind === SyntaxKind.ModuleDeclaration) { + node = node.body; + } + + return node; + } + + function getNodeSpan(node: Node) { + return node.kind === SyntaxKind.SourceFile + ? createTextSpanFromBounds(node.getFullStart(), node.getEnd()) + : createTextSpanFromBounds(node.getStart(), node.getEnd()); + } + + function getTextOfNode(node: Node): string { + return getTextOfNodeFromSourceText(sourceFile.text, node); + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/outliningElementsCollector.ts b/lib/typescript/services/outliningElementsCollector.ts new file mode 100644 index 000000000..7c5ea3aa9 --- /dev/null +++ b/lib/typescript/services/outliningElementsCollector.ts @@ -0,0 +1,180 @@ +/* @internal */ +module ts { + export module OutliningElementsCollector { + export function collectElements(sourceFile: SourceFile): OutliningSpan[] { + let elements: OutliningSpan[] = []; + let collapseText = "..."; + + function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) { + if (hintSpanNode && startElement && endElement) { + let span: OutliningSpan = { + textSpan: createTextSpanFromBounds(startElement.pos, endElement.end), + hintSpan: createTextSpanFromBounds(hintSpanNode.getStart(), hintSpanNode.end), + bannerText: collapseText, + autoCollapse: autoCollapse + }; + elements.push(span); + } + } + + function addOutliningSpanComments(commentSpan: CommentRange, autoCollapse: boolean) { + if (commentSpan) { + let span: OutliningSpan = { + textSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end), + hintSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end), + bannerText: collapseText, + autoCollapse: autoCollapse + }; + elements.push(span); + } + } + + function addOutliningForLeadingCommentsForNode(n: Node) { + let comments = ts.getLeadingCommentRangesOfNode(n, sourceFile); + + if (comments) { + let firstSingleLineCommentStart = -1; + let lastSingleLineCommentEnd = -1; + let isFirstSingleLineComment = true; + let singleLineCommentCount = 0; + + for (let currentComment of comments) { + + // For single line comments, combine consecutive ones (2 or more) into + // a single span from the start of the first till the end of the last + if (currentComment.kind === SyntaxKind.SingleLineCommentTrivia) { + if (isFirstSingleLineComment) { + firstSingleLineCommentStart = currentComment.pos; + } + isFirstSingleLineComment = false; + lastSingleLineCommentEnd = currentComment.end; + singleLineCommentCount++; + } + else if (currentComment.kind === SyntaxKind.MultiLineCommentTrivia) { + combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); + addOutliningSpanComments(currentComment, /*autoCollapse*/ false); + + singleLineCommentCount = 0; + lastSingleLineCommentEnd = -1; + isFirstSingleLineComment = true; + } + } + + combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); + } + } + + function combineAndAddMultipleSingleLineComments(count: number, start: number, end: number) { + // Only outline spans of two or more consecutive single line comments + if (count > 1) { + let multipleSingleLineComments = { + pos: start, + end: end, + kind: SyntaxKind.SingleLineCommentTrivia + } + + addOutliningSpanComments(multipleSingleLineComments, /*autoCollapse*/ false); + } + } + + function autoCollapse(node: Node) { + return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction; + } + + let depth = 0; + let maxDepth = 20; + function walk(n: Node): void { + if (depth > maxDepth) { + return; + } + + if (isDeclaration(n)) { + addOutliningForLeadingCommentsForNode(n); + } + + switch (n.kind) { + case SyntaxKind.Block: + if (!isFunctionBlock(n)) { + let parent = n.parent; + let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); + let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); + + // Check if the block is standalone, or 'attached' to some parent statement. + // If the latter, we want to collaps the block, but consider its hint span + // to be the entire span of the parent. + if (parent.kind === SyntaxKind.DoStatement || + parent.kind === SyntaxKind.ForInStatement || + parent.kind === SyntaxKind.ForOfStatement || + parent.kind === SyntaxKind.ForStatement || + parent.kind === SyntaxKind.IfStatement || + parent.kind === SyntaxKind.WhileStatement || + parent.kind === SyntaxKind.WithStatement || + parent.kind === SyntaxKind.CatchClause) { + + addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n)); + break; + } + + if (parent.kind === SyntaxKind.TryStatement) { + // Could be the try-block, or the finally-block. + let tryStatement = parent; + if (tryStatement.tryBlock === n) { + addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n)); + break; + } + else if (tryStatement.finallyBlock === n) { + let finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile); + if (finallyKeyword) { + addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n)); + break; + } + } + + // fall through. + } + + // Block was a standalone block. In this case we want to only collapse + // the span of the block, independent of any parent span. + let span = createTextSpanFromBounds(n.getStart(), n.end); + elements.push({ + textSpan: span, + hintSpan: span, + bannerText: collapseText, + autoCollapse: autoCollapse(n) + }); + break; + } + // Fallthrough. + + case SyntaxKind.ModuleBlock: { + let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); + let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); + addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n)); + break; + } + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.CaseBlock: { + let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); + let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); + addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n)); + break; + } + case SyntaxKind.ArrayLiteralExpression: + let openBracket = findChildOfKind(n, SyntaxKind.OpenBracketToken, sourceFile); + let closeBracket = findChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile); + addOutliningSpan(n, openBracket, closeBracket, autoCollapse(n)); + break; + } + depth++; + forEachChild(n, walk); + depth--; + } + + walk(sourceFile); + return elements; + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/patternMatcher.ts b/lib/typescript/services/patternMatcher.ts new file mode 100644 index 000000000..e701a2e83 --- /dev/null +++ b/lib/typescript/services/patternMatcher.ts @@ -0,0 +1,810 @@ +/* @internal */ +module ts { + // Note(cyrusn): this enum is ordered from strongest match type to weakest match type. + export enum PatternMatchKind { + exact, + prefix, + substring, + camelCase + } + + // Information about a match made by the pattern matcher between a candidate and the + // search pattern. + export interface PatternMatch { + // What kind of match this was. Exact matches are better than prefix matches which are + // better than substring matches which are better than CamelCase matches. + kind: PatternMatchKind; + + // If this was a camel case match, how strong the match is. Higher number means + // it was a better match. + camelCaseWeight?: number; + + // If this was a match where all constituent parts of the candidate and search pattern + // matched case sensitively or case insensitively. Case sensitive matches of the kind + // are better matches than insensitive matches. + isCaseSensitive: boolean; + + // Whether or not this match occurred with the punctuation from the search pattern stripped + // out or not. Matches without the punctuation stripped are better than ones with punctuation + // stripped. + punctuationStripped: boolean; + } + + // The pattern matcher maintains an internal cache of information as it is used. Therefore, + // you should not keep it around forever and should get and release the matcher appropriately + // once you no longer need it. + export interface PatternMatcher { + // Used to match a candidate against the last segment of a possibly dotted pattern. This + // is useful as a quick check to prevent having to compute a container before calling + // "getMatches". + // + // For example, if the search pattern is "ts.c.SK" and the candidate is "SyntaxKind", then + // this will return a successful match, having only tested "SK" against "SyntaxKind". At + // that point a call can be made to 'getMatches("SyntaxKind", "ts.compiler")', with the + // work to create 'ts.compiler' only being done once the first match succeeded. + getMatchesForLastSegmentOfPattern(candidate: string): PatternMatch[]; + + // Fully checks a candidate, with an dotted container, against the search pattern. + // The candidate must match the last part of the search pattern, and the dotted container + // must match the preceding segments of the pattern. + getMatches(candidateContainers: string[], candidate: string): PatternMatch[]; + + // Whether or not the pattern contained dots or not. Clients can use this to determine + // If they should call getMatches, or if getMatchesForLastSegmentOfPattern is sufficient. + patternContainsDots: boolean; + } + + // First we break up the pattern given by dots. Each portion of the pattern between the + // dots is a 'Segment'. The 'Segment' contains information about the entire section of + // text between the dots, as well as information about any individual 'Words' that we + // can break the segment into. A 'Word' is simply a contiguous sequence of characters + // that can appear in a typescript identifier. So "GetKeyword" would be one word, while + // "Get Keyword" would be two words. Once we have the individual 'words', we break those + // into constituent 'character spans' of interest. For example, while 'UIElement' is one + // word, it make character spans corresponding to "U", "I" and "Element". These spans + // are then used when doing camel cased matches against candidate patterns. + interface Segment { + // Information about the entire piece of text between the dots. For example, if the + // text between the dots is 'GetKeyword', then TotalTextChunk.Text will be 'GetKeyword' and + // TotalTextChunk.CharacterSpans will correspond to 'Get', 'Keyword'. + totalTextChunk: TextChunk; + + // Information about the subwords compromising the total word. For example, if the + // text between the dots is 'GetFoo KeywordBar', then the subwords will be 'GetFoo' + // and 'KeywordBar'. Those individual words will have CharacterSpans of ('Get' and + // 'Foo') and('Keyword' and 'Bar') respectively. + subWordTextChunks: TextChunk[]; + } + + // Information about a chunk of text from the pattern. The chunk is a piece of text, with + // cached information about the character spans within in. Character spans are used for + // camel case matching. + interface TextChunk { + // The text of the chunk. This should be a contiguous sequence of character that could + // occur in a symbol name. + text: string; + + // The text of a chunk in lower case. Cached because it is needed often to check for + // case insensitive matches. + textLowerCase: string; + + // Whether or not this chunk is entirely lowercase. We have different rules when searching + // for something entirely lowercase or not. + isLowerCase: boolean; + + // The spans in this text chunk that we think are of interest and should be matched + // independently. For example, if the chunk is for "UIElement" the the spans of interest + // correspond to "U", "I" and "Element". If "UIElement" isn't found as an exaxt, prefix. + // or substring match, then the character spans will be used to attempt a camel case match. + characterSpans: TextSpan[]; + } + + function createPatternMatch(kind: PatternMatchKind, punctuationStripped: boolean, isCaseSensitive: boolean, camelCaseWeight?: number): PatternMatch { + return { + kind, + punctuationStripped, + isCaseSensitive, + camelCaseWeight + }; + } + + export function createPatternMatcher(pattern: string): PatternMatcher { + // We'll often see the same candidate string many times when searching (For example, when + // we see the name of a module that is used everywhere, or the name of an overload). As + // such, we cache the information we compute about the candidate for the life of this + // pattern matcher so we don't have to compute it multiple times. + let stringToWordSpans: Map = {}; + + pattern = pattern.trim(); + + let fullPatternSegment = createSegment(pattern); + let dotSeparatedSegments = pattern.split(".").map(p => createSegment(p.trim())); + let invalidPattern = dotSeparatedSegments.length === 0 || forEach(dotSeparatedSegments, segmentIsInvalid); + + return { + getMatches, + getMatchesForLastSegmentOfPattern, + patternContainsDots: dotSeparatedSegments.length > 1 + }; + + // Quick checks so we can bail out when asked to match a candidate. + function skipMatch(candidate: string) { + return invalidPattern || !candidate; + } + + function getMatchesForLastSegmentOfPattern(candidate: string): PatternMatch[] { + if (skipMatch(candidate)) { + return undefined; + } + + return matchSegment(candidate, lastOrUndefined(dotSeparatedSegments)); + } + + function getMatches(candidateContainers: string[], candidate: string): PatternMatch[] { + if (skipMatch(candidate)) { + return undefined; + } + + // First, check that the last part of the dot separated pattern matches the name of the + // candidate. If not, then there's no point in proceeding and doing the more + // expensive work. + let candidateMatch = matchSegment(candidate, lastOrUndefined(dotSeparatedSegments)); + if (!candidateMatch) { + return undefined; + } + + candidateContainers = candidateContainers || []; + + // -1 because the last part was checked against the name, and only the rest + // of the parts are checked against the container. + if (dotSeparatedSegments.length - 1 > candidateContainers.length) { + // There weren't enough container parts to match against the pattern parts. + // So this definitely doesn't match. + return undefined; + } + + // So far so good. Now break up the container for the candidate and check if all + // the dotted parts match up correctly. + let totalMatch = candidateMatch; + + for (let i = dotSeparatedSegments.length - 2, j = candidateContainers.length - 1; + i >= 0; + i--, j--) { + + let segment = dotSeparatedSegments[i]; + let containerName = candidateContainers[j]; + + let containerMatch = matchSegment(containerName, segment); + if (!containerMatch) { + // This container didn't match the pattern piece. So there's no match at all. + return undefined; + } + + addRange(totalMatch, containerMatch); + } + + // Success, this symbol's full name matched against the dotted name the user was asking + // about. + return totalMatch; + } + + function getWordSpans(word: string): TextSpan[] { + if (!hasProperty(stringToWordSpans, word)) { + stringToWordSpans[word] = breakIntoWordSpans(word); + } + + return stringToWordSpans[word]; + } + + function matchTextChunk(candidate: string, chunk: TextChunk, punctuationStripped: boolean): PatternMatch { + let index = indexOfIgnoringCase(candidate, chunk.textLowerCase); + if (index === 0) { + if (chunk.text.length === candidate.length) { + // a) Check if the part matches the candidate entirely, in an case insensitive or + // sensitive manner. If it does, return that there was an exact match. + return createPatternMatch(PatternMatchKind.exact, punctuationStripped, /*isCaseSensitive:*/ candidate === chunk.text); + } + else { + // b) Check if the part is a prefix of the candidate, in a case insensitive or sensitive + // manner. If it does, return that there was a prefix match. + return createPatternMatch(PatternMatchKind.prefix, punctuationStripped, /*isCaseSensitive:*/ startsWith(candidate, chunk.text)); + } + } + + let isLowercase = chunk.isLowerCase; + if (isLowercase) { + if (index > 0) { + // c) If the part is entirely lowercase, then check if it is contained anywhere in the + // candidate in a case insensitive manner. If so, return that there was a substring + // match. + // + // Note: We only have a substring match if the lowercase part is prefix match of some + // word part. That way we don't match something like 'Class' when the user types 'a'. + // But we would match 'FooAttribute' (since 'Attribute' starts with 'a'). + let wordSpans = getWordSpans(candidate); + for (let span of wordSpans) { + if (partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ true)) { + return createPatternMatch(PatternMatchKind.substring, punctuationStripped, + /*isCaseSensitive:*/ partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ false)); + } + } + } + } + else { + // d) If the part was not entirely lowercase, then check if it is contained in the + // candidate in a case *sensitive* manner. If so, return that there was a substring + // match. + if (candidate.indexOf(chunk.text) > 0) { + return createPatternMatch(PatternMatchKind.substring, punctuationStripped, /*isCaseSensitive:*/ true); + } + } + + if (!isLowercase) { + // e) If the part was not entirely lowercase, then attempt a camel cased match as well. + if (chunk.characterSpans.length > 0) { + let candidateParts = getWordSpans(candidate); + let camelCaseWeight = tryCamelCaseMatch(candidate, candidateParts, chunk, /*ignoreCase:*/ false); + if (camelCaseWeight !== undefined) { + return createPatternMatch(PatternMatchKind.camelCase, punctuationStripped, /*isCaseSensitive:*/ true, /*camelCaseWeight:*/ camelCaseWeight); + } + + camelCaseWeight = tryCamelCaseMatch(candidate, candidateParts, chunk, /*ignoreCase:*/ true); + if (camelCaseWeight !== undefined) { + return createPatternMatch(PatternMatchKind.camelCase, punctuationStripped, /*isCaseSensitive:*/ false, /*camelCaseWeight:*/ camelCaseWeight); + } + } + } + + if (isLowercase) { + // f) Is the pattern a substring of the candidate starting on one of the candidate's word boundaries? + + // We could check every character boundary start of the candidate for the pattern. However, that's + // an m * n operation in the wost case. Instead, find the first instance of the pattern + // substring, and see if it starts on a capital letter. It seems unlikely that the user will try to + // filter the list based on a substring that starts on a capital letter and also with a lowercase one. + // (Pattern: fogbar, Candidate: quuxfogbarFogBar). + if (chunk.text.length < candidate.length) { + if (index > 0 && isUpperCaseLetter(candidate.charCodeAt(index))) { + return createPatternMatch(PatternMatchKind.substring, punctuationStripped, /*isCaseSensitive:*/ false); + } + } + } + + return undefined; + } + + function containsSpaceOrAsterisk(text: string): boolean { + for (let i = 0; i < text.length; i++) { + let ch = text.charCodeAt(i); + if (ch === CharacterCodes.space || ch === CharacterCodes.asterisk) { + return true; + } + } + + return false; + } + + function matchSegment(candidate: string, segment: Segment): PatternMatch[] { + // First check if the segment matches as is. This is also useful if the segment contains + // characters we would normally strip when splitting into parts that we also may want to + // match in the candidate. For example if the segment is "@int" and the candidate is + // "@int", then that will show up as an exact match here. + // + // Note: if the segment contains a space or an asterisk then we must assume that it's a + // multi-word segment. + if (!containsSpaceOrAsterisk(segment.totalTextChunk.text)) { + let match = matchTextChunk(candidate, segment.totalTextChunk, /*punctuationStripped:*/ false); + if (match) { + return [match]; + } + } + + // The logic for pattern matching is now as follows: + // + // 1) Break the segment passed in into words. Breaking is rather simple and a + // good way to think about it that if gives you all the individual alphanumeric words + // of the pattern. + // + // 2) For each word try to match the word against the candidate value. + // + // 3) Matching is as follows: + // + // a) Check if the word matches the candidate entirely, in an case insensitive or + // sensitive manner. If it does, return that there was an exact match. + // + // b) Check if the word is a prefix of the candidate, in a case insensitive or + // sensitive manner. If it does, return that there was a prefix match. + // + // c) If the word is entirely lowercase, then check if it is contained anywhere in the + // candidate in a case insensitive manner. If so, return that there was a substring + // match. + // + // Note: We only have a substring match if the lowercase part is prefix match of + // some word part. That way we don't match something like 'Class' when the user + // types 'a'. But we would match 'FooAttribute' (since 'Attribute' starts with + // 'a'). + // + // d) If the word was not entirely lowercase, then check if it is contained in the + // candidate in a case *sensitive* manner. If so, return that there was a substring + // match. + // + // e) If the word was not entirely lowercase, then attempt a camel cased match as + // well. + // + // f) The word is all lower case. Is it a case insensitive substring of the candidate starting + // on a part boundary of the candidate? + // + // Only if all words have some sort of match is the pattern considered matched. + + let subWordTextChunks = segment.subWordTextChunks; + let matches: PatternMatch[] = undefined; + + for (let subWordTextChunk of subWordTextChunks) { + // Try to match the candidate with this word + let result = matchTextChunk(candidate, subWordTextChunk, /*punctuationStripped:*/ true); + if (!result) { + return undefined; + } + + matches = matches || []; + matches.push(result); + } + + return matches; + } + + function partStartsWith(candidate: string, candidateSpan: TextSpan, pattern: string, ignoreCase: boolean, patternSpan?: TextSpan): boolean { + let patternPartStart = patternSpan ? patternSpan.start : 0; + let patternPartLength = patternSpan ? patternSpan.length : pattern.length; + + if (patternPartLength > candidateSpan.length) { + // Pattern part is longer than the candidate part. There can never be a match. + return false; + } + + if (ignoreCase) { + for (let i = 0; i < patternPartLength; i++) { + let ch1 = pattern.charCodeAt(patternPartStart + i); + let ch2 = candidate.charCodeAt(candidateSpan.start + i); + if (toLowerCase(ch1) !== toLowerCase(ch2)) { + return false; + } + } + } + else { + for (let i = 0; i < patternPartLength; i++) { + let ch1 = pattern.charCodeAt(patternPartStart + i); + let ch2 = candidate.charCodeAt(candidateSpan.start + i); + if (ch1 !== ch2) { + return false; + } + } + } + + return true; + } + + function tryCamelCaseMatch(candidate: string, candidateParts: TextSpan[], chunk: TextChunk, ignoreCase: boolean): number { + let chunkCharacterSpans = chunk.characterSpans; + + // Note: we may have more pattern parts than candidate parts. This is because multiple + // pattern parts may match a candidate part. For example "SiUI" against "SimpleUI". + // We'll have 3 pattern parts Si/U/I against two candidate parts Simple/UI. However, U + // and I will both match in UI. + + let currentCandidate = 0; + let currentChunkSpan = 0; + let firstMatch: number = undefined; + let contiguous: boolean = undefined; + + while (true) { + // Let's consider our termination cases + if (currentChunkSpan === chunkCharacterSpans.length) { + // We did match! We shall assign a weight to this + let weight = 0; + + // Was this contiguous? + if (contiguous) { + weight += 1; + } + + // Did we start at the beginning of the candidate? + if (firstMatch === 0) { + weight += 2; + } + + return weight; + } + else if (currentCandidate === candidateParts.length) { + // No match, since we still have more of the pattern to hit + return undefined; + } + + let candidatePart = candidateParts[currentCandidate]; + let gotOneMatchThisCandidate = false; + + // Consider the case of matching SiUI against SimpleUIElement. The candidate parts + // will be Simple/UI/Element, and the pattern parts will be Si/U/I. We'll match 'Si' + // against 'Simple' first. Then we'll match 'U' against 'UI'. However, we want to + // still keep matching pattern parts against that candidate part. + for (; currentChunkSpan < chunkCharacterSpans.length; currentChunkSpan++) { + let chunkCharacterSpan = chunkCharacterSpans[currentChunkSpan]; + + if (gotOneMatchThisCandidate) { + // We've already gotten one pattern part match in this candidate. We will + // only continue trying to consumer pattern parts if the last part and this + // part are both upper case. + if (!isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan - 1].start)) || + !isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan].start))) { + break; + } + } + + if (!partStartsWith(candidate, candidatePart, chunk.text, ignoreCase, chunkCharacterSpan)) { + break; + } + + gotOneMatchThisCandidate = true; + + firstMatch = firstMatch === undefined ? currentCandidate : firstMatch; + + // If we were contiguous, then keep that value. If we weren't, then keep that + // value. If we don't know, then set the value to 'true' as an initial match is + // obviously contiguous. + contiguous = contiguous === undefined ? true : contiguous; + + candidatePart = createTextSpan(candidatePart.start + chunkCharacterSpan.length, candidatePart.length - chunkCharacterSpan.length); + } + + // Check if we matched anything at all. If we didn't, then we need to unset the + // contiguous bit if we currently had it set. + // If we haven't set the bit yet, then that means we haven't matched anything so + // far, and we don't want to change that. + if (!gotOneMatchThisCandidate && contiguous !== undefined) { + contiguous = false; + } + + // Move onto the next candidate. + currentCandidate++; + } + } + } + + // Helper function to compare two matches to determine which is better. Matches are first + // ordered by kind (so all prefix matches always beat all substring matches). Then, if the + // match is a camel case match, the relative weights of the match are used to determine + // which is better (with a greater weight being better). Then if the match is of the same + // type, then a case sensitive match is considered better than an insensitive one. + function patternMatchCompareTo(match1: PatternMatch, match2: PatternMatch): number { + return compareType(match1, match2) || + compareCamelCase(match1, match2) || + compareCase(match1, match2) || + comparePunctuation(match1, match2); + } + + function comparePunctuation(result1: PatternMatch, result2: PatternMatch) { + // Consider a match to be better if it was successful without stripping punctuation + // versus a match that had to strip punctuation to succeed. + if (result1.punctuationStripped !== result2.punctuationStripped) { + return result1.punctuationStripped ? 1 : -1; + } + + return 0; + } + + function compareCase(result1: PatternMatch, result2: PatternMatch) { + if (result1.isCaseSensitive !== result2.isCaseSensitive) { + return result1.isCaseSensitive ? -1 : 1; + } + + return 0; + } + + function compareType(result1: PatternMatch, result2: PatternMatch) { + return result1.kind - result2.kind; + } + + function compareCamelCase(result1: PatternMatch, result2: PatternMatch) { + if (result1.kind === PatternMatchKind.camelCase && result2.kind === PatternMatchKind.camelCase) { + // Swap the values here. If result1 has a higher weight, then we want it to come + // first. + return result2.camelCaseWeight - result1.camelCaseWeight; + } + + return 0; + } + + function createSegment(text: string): Segment { + return { + totalTextChunk: createTextChunk(text), + subWordTextChunks: breakPatternIntoTextChunks(text) + } + } + + // A segment is considered invalid if we couldn't find any words in it. + function segmentIsInvalid(segment: Segment) { + return segment.subWordTextChunks.length === 0; + } + + function isUpperCaseLetter(ch: number) { + // Fast check for the ascii range. + if (ch >= CharacterCodes.A && ch <= CharacterCodes.Z) { + return true; + } + + if (ch < CharacterCodes.maxAsciiCharacter || !isUnicodeIdentifierStart(ch, ScriptTarget.Latest)) { + return false; + } + + // TODO: find a way to determine this for any unicode characters in a + // non-allocating manner. + let str = String.fromCharCode(ch); + return str === str.toUpperCase(); + } + + function isLowerCaseLetter(ch: number) { + // Fast check for the ascii range. + if (ch >= CharacterCodes.a && ch <= CharacterCodes.z) { + return true; + } + + if (ch < CharacterCodes.maxAsciiCharacter || !isUnicodeIdentifierStart(ch, ScriptTarget.Latest)) { + return false; + } + + + // TODO: find a way to determine this for any unicode characters in a + // non-allocating manner. + let str = String.fromCharCode(ch); + return str === str.toLowerCase(); + } + + function containsUpperCaseLetter(string: string): boolean { + for (let i = 0, n = string.length; i < n; i++) { + if (isUpperCaseLetter(string.charCodeAt(i))) { + return true; + } + } + + return false; + } + + function startsWith(string: string, search: string) { + for (let i = 0, n = search.length; i < n; i++) { + if (string.charCodeAt(i) !== search.charCodeAt(i)) { + return false; + } + } + + return true; + } + + // Assumes 'value' is already lowercase. + function indexOfIgnoringCase(string: string, value: string): number { + for (let i = 0, n = string.length - value.length; i <= n; i++) { + if (startsWithIgnoringCase(string, value, i)) { + return i; + } + } + + return -1; + } + + // Assumes 'value' is already lowercase. + function startsWithIgnoringCase(string: string, value: string, start: number): boolean { + for (let i = 0, n = value.length; i < n; i++) { + let ch1 = toLowerCase(string.charCodeAt(i + start)); + let ch2 = value.charCodeAt(i); + + if (ch1 !== ch2) { + return false; + } + } + + return true; + } + + function toLowerCase(ch: number): number { + // Fast convert for the ascii range. + if (ch >= CharacterCodes.A && ch <= CharacterCodes.Z) { + return CharacterCodes.a + (ch - CharacterCodes.A); + } + + if (ch < CharacterCodes.maxAsciiCharacter) { + return ch; + } + + // TODO: find a way to compute this for any unicode characters in a + // non-allocating manner. + return String.fromCharCode(ch).toLowerCase().charCodeAt(0); + } + + function isDigit(ch: number) { + // TODO(cyrusn): Find a way to support this for unicode digits. + return ch >= CharacterCodes._0 && ch <= CharacterCodes._9; + } + + function isWordChar(ch: number) { + return isUpperCaseLetter(ch) || isLowerCaseLetter(ch) || isDigit(ch) || ch === CharacterCodes._ || ch === CharacterCodes.$; + } + + function breakPatternIntoTextChunks(pattern: string): TextChunk[] { + let result: TextChunk[] = []; + let wordStart = 0; + let wordLength = 0; + + for (let i = 0; i < pattern.length; i++) { + let ch = pattern.charCodeAt(i); + if (isWordChar(ch)) { + if (wordLength++ === 0) { + wordStart = i; + } + } + else { + if (wordLength > 0) { + result.push(createTextChunk(pattern.substr(wordStart, wordLength))); + wordLength = 0; + } + } + } + + if (wordLength > 0) { + result.push(createTextChunk(pattern.substr(wordStart, wordLength))); + } + + return result; + } + + function createTextChunk(text: string): TextChunk { + let textLowerCase = text.toLowerCase(); + return { + text, + textLowerCase, + isLowerCase: text === textLowerCase, + characterSpans: breakIntoCharacterSpans(text) + } + } + + /* @internal */ export function breakIntoCharacterSpans(identifier: string): TextSpan[] { + return breakIntoSpans(identifier, /*word:*/ false); + } + + /* @internal */ export function breakIntoWordSpans(identifier: string): TextSpan[] { + return breakIntoSpans(identifier, /*word:*/ true); + } + + function breakIntoSpans(identifier: string, word: boolean): TextSpan[] { + let result: TextSpan[] = []; + + let wordStart = 0; + for (let i = 1, n = identifier.length; i < n; i++) { + let lastIsDigit = isDigit(identifier.charCodeAt(i - 1)); + let currentIsDigit = isDigit(identifier.charCodeAt(i)); + + let hasTransitionFromLowerToUpper = transitionFromLowerToUpper(identifier, word, i); + let hasTransitionFromUpperToLower = transitionFromUpperToLower(identifier, word, i, wordStart); + + if (charIsPunctuation(identifier.charCodeAt(i - 1)) || + charIsPunctuation(identifier.charCodeAt(i)) || + lastIsDigit != currentIsDigit || + hasTransitionFromLowerToUpper || + hasTransitionFromUpperToLower) { + + if (!isAllPunctuation(identifier, wordStart, i)) { + result.push(createTextSpan(wordStart, i - wordStart)); + } + + wordStart = i; + } + } + + if (!isAllPunctuation(identifier, wordStart, identifier.length)) { + result.push(createTextSpan(wordStart, identifier.length - wordStart)); + } + + return result; + } + + function charIsPunctuation(ch: number) { + switch (ch) { + case CharacterCodes.exclamation: + case CharacterCodes.doubleQuote: + case CharacterCodes.hash: + case CharacterCodes.percent: + case CharacterCodes.ampersand: + case CharacterCodes.singleQuote: + case CharacterCodes.openParen: + case CharacterCodes.closeParen: + case CharacterCodes.asterisk: + case CharacterCodes.comma: + case CharacterCodes.minus: + case CharacterCodes.dot: + case CharacterCodes.slash: + case CharacterCodes.colon: + case CharacterCodes.semicolon: + case CharacterCodes.question: + case CharacterCodes.at: + case CharacterCodes.openBracket: + case CharacterCodes.backslash: + case CharacterCodes.closeBracket: + case CharacterCodes._: + case CharacterCodes.openBrace: + case CharacterCodes.closeBrace: + return true; + } + + return false; + } + + function isAllPunctuation(identifier: string, start: number, end: number): boolean { + for (let i = start; i < end; i++) { + let ch = identifier.charCodeAt(i); + + // We don't consider _ or $ as punctuation as there may be things with that name. + if (!charIsPunctuation(ch) || ch === CharacterCodes._ || ch === CharacterCodes.$) { + return false; + } + } + + return true; + } + + function transitionFromUpperToLower(identifier: string, word: boolean, index: number, wordStart: number): boolean { + if (word) { + // Cases this supports: + // 1) IDisposable -> I, Disposable + // 2) UIElement -> UI, Element + // 3) HTMLDocument -> HTML, Document + // + // etc. + if (index != wordStart && + index + 1 < identifier.length) { + let currentIsUpper = isUpperCaseLetter(identifier.charCodeAt(index)); + let nextIsLower = isLowerCaseLetter(identifier.charCodeAt(index + 1)); + + if (currentIsUpper && nextIsLower) { + // We have a transition from an upper to a lower letter here. But we only + // want to break if all the letters that preceded are uppercase. i.e. if we + // have "Foo" we don't want to break that into "F, oo". But if we have + // "IFoo" or "UIFoo", then we want to break that into "I, Foo" and "UI, + // Foo". i.e. the last uppercase letter belongs to the lowercase letters + // that follows. Note: this will make the following not split properly: + // "HELLOthere". However, these sorts of names do not show up in .Net + // programs. + for (let i = wordStart; i < index; i++) { + if (!isUpperCaseLetter(identifier.charCodeAt(i))) { + return false; + } + } + + return true; + } + } + } + + return false; + } + + function transitionFromLowerToUpper(identifier: string, word: boolean, index: number): boolean { + let lastIsUpper = isUpperCaseLetter(identifier.charCodeAt(index - 1)); + let currentIsUpper = isUpperCaseLetter(identifier.charCodeAt(index)); + + // See if the casing indicates we're starting a new word. Note: if we're breaking on + // words, then just seeing an upper case character isn't enough. Instead, it has to + // be uppercase and the previous character can't be uppercase. + // + // For example, breaking "AddMetadata" on words would make: Add Metadata + // + // on characters would be: A dd M etadata + // + // Break "AM" on words would be: AM + // + // on characters would be: A M + // + // We break the search string on characters. But we break the symbol name on words. + let transition = word + ? (currentIsUpper && !lastIsUpper) + : currentIsUpper; + return transition; + } +} \ No newline at end of file diff --git a/lib/typescript/services/services.ts b/lib/typescript/services/services.ts new file mode 100644 index 000000000..9742b07b5 --- /dev/null +++ b/lib/typescript/services/services.ts @@ -0,0 +1,6904 @@ +/// + +/// +/// +/// +/// +/// +/// +/// +/// +/// + +module ts { + /** The version of the language service API */ + export let servicesVersion = "0.4" + + export interface Node { + getSourceFile(): SourceFile; + getChildCount(sourceFile?: SourceFile): number; + getChildAt(index: number, sourceFile?: SourceFile): Node; + getChildren(sourceFile?: SourceFile): Node[]; + getStart(sourceFile?: SourceFile): number; + getFullStart(): number; + getEnd(): number; + getWidth(sourceFile?: SourceFile): number; + getFullWidth(): number; + getLeadingTriviaWidth(sourceFile?: SourceFile): number; + getFullText(sourceFile?: SourceFile): string; + getText(sourceFile?: SourceFile): string; + getFirstToken(sourceFile?: SourceFile): Node; + getLastToken(sourceFile?: SourceFile): Node; + } + + export interface Symbol { + getFlags(): SymbolFlags; + getName(): string; + getDeclarations(): Declaration[]; + getDocumentationComment(): SymbolDisplayPart[]; + } + + export interface Type { + getFlags(): TypeFlags; + getSymbol(): Symbol; + getProperties(): Symbol[]; + getProperty(propertyName: string): Symbol; + getApparentProperties(): Symbol[]; + getCallSignatures(): Signature[]; + getConstructSignatures(): Signature[]; + getStringIndexType(): Type; + getNumberIndexType(): Type; + } + + export interface Signature { + getDeclaration(): SignatureDeclaration; + getTypeParameters(): Type[]; + getParameters(): Symbol[]; + getReturnType(): Type; + getDocumentationComment(): SymbolDisplayPart[]; + } + + export interface SourceFile { + /* @internal */ version: string; + /* @internal */ scriptSnapshot: IScriptSnapshot; + /* @internal */ nameTable: Map; + + /* @internal */ getNamedDeclarations(): Map; + + getLineAndCharacterOfPosition(pos: number): LineAndCharacter; + getLineStarts(): number[]; + getPositionOfLineAndCharacter(line: number, character: number): number; + update(newText: string, textChangeRange: TextChangeRange): SourceFile; + } + + /** + * Represents an immutable snapshot of a script at a specified time.Once acquired, the + * snapshot is observably immutable. i.e. the same calls with the same parameters will return + * the same values. + */ + export interface IScriptSnapshot { + /** Gets a portion of the script snapshot specified by [start, end). */ + getText(start: number, end: number): string; + + /** Gets the length of this script snapshot. */ + getLength(): number; + + /** + * Gets the TextChangeRange that describe how the text changed between this text and + * an older version. This information is used by the incremental parser to determine + * what sections of the script need to be re-parsed. 'undefined' can be returned if the + * change range cannot be determined. However, in that case, incremental parsing will + * not happen and the entire document will be re - parsed. + */ + getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange; + } + + export module ScriptSnapshot { + class StringScriptSnapshot implements IScriptSnapshot { + private _lineStartPositions: number[] = undefined; + + constructor(private text: string) { + } + + public getText(start: number, end: number): string { + return this.text.substring(start, end); + } + + public getLength(): number { + return this.text.length; + } + + public getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange { + // Text-based snapshots do not support incremental parsing. Return undefined + // to signal that to the caller. + return undefined; + } + } + + export function fromString(text: string): IScriptSnapshot { + return new StringScriptSnapshot(text); + } + } + export interface PreProcessedFileInfo { + referencedFiles: FileReference[]; + importedFiles: FileReference[]; + isLibFile: boolean + } + + let scanner: Scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true); + + let emptyArray: any[] = []; + + function createNode(kind: SyntaxKind, pos: number, end: number, flags: NodeFlags, parent?: Node): NodeObject { + let node = new (getNodeConstructor(kind))(); + node.pos = pos; + node.end = end; + node.flags = flags; + node.parent = parent; + return node; + } + + class NodeObject implements Node { + public kind: SyntaxKind; + public pos: number; + public end: number; + public flags: NodeFlags; + public parent: Node; + private _children: Node[]; + + public getSourceFile(): SourceFile { + return getSourceFileOfNode(this); + } + + public getStart(sourceFile?: SourceFile): number { + return getTokenPosOfNode(this, sourceFile); + } + + public getFullStart(): number { + return this.pos; + } + + public getEnd(): number { + return this.end; + } + + public getWidth(sourceFile?: SourceFile): number { + return this.getEnd() - this.getStart(sourceFile); + } + + public getFullWidth(): number { + return this.end - this.getFullStart(); + } + + public getLeadingTriviaWidth(sourceFile?: SourceFile): number { + return this.getStart(sourceFile) - this.pos; + } + + public getFullText(sourceFile?: SourceFile): string { + return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end); + } + + public getText(sourceFile?: SourceFile): string { + return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd()); + } + + private addSyntheticNodes(nodes: Node[], pos: number, end: number): number { + scanner.setTextPos(pos); + while (pos < end) { + let token = scanner.scan(); + let textPos = scanner.getTextPos(); + nodes.push(createNode(token, pos, textPos, NodeFlags.Synthetic, this)); + pos = textPos; + } + return pos; + } + + private createSyntaxList(nodes: NodeArray): Node { + let list = createNode(SyntaxKind.SyntaxList, nodes.pos, nodes.end, NodeFlags.Synthetic, this); + list._children = []; + let pos = nodes.pos; + for (let node of nodes) { + if (pos < node.pos) { + pos = this.addSyntheticNodes(list._children, pos, node.pos); + } + list._children.push(node); + pos = node.end; + } + if (pos < nodes.end) { + this.addSyntheticNodes(list._children, pos, nodes.end); + } + return list; + } + + private createChildren(sourceFile?: SourceFile) { + let children: Node[]; + if (this.kind >= SyntaxKind.FirstNode) { + scanner.setText((sourceFile || this.getSourceFile()).text); + children = []; + let pos = this.pos; + let processNode = (node: Node) => { + if (pos < node.pos) { + pos = this.addSyntheticNodes(children, pos, node.pos); + } + children.push(node); + pos = node.end; + }; + let processNodes = (nodes: NodeArray) => { + if (pos < nodes.pos) { + pos = this.addSyntheticNodes(children, pos, nodes.pos); + } + children.push(this.createSyntaxList(>nodes)); + pos = nodes.end; + }; + forEachChild(this, processNode, processNodes); + if (pos < this.end) { + this.addSyntheticNodes(children, pos, this.end); + } + scanner.setText(undefined); + } + this._children = children || emptyArray; + } + + public getChildCount(sourceFile?: SourceFile): number { + if (!this._children) this.createChildren(sourceFile); + return this._children.length; + } + + public getChildAt(index: number, sourceFile?: SourceFile): Node { + if (!this._children) this.createChildren(sourceFile); + return this._children[index]; + } + + public getChildren(sourceFile?: SourceFile): Node[] { + if (!this._children) this.createChildren(sourceFile); + return this._children; + } + + public getFirstToken(sourceFile?: SourceFile): Node { + let children = this.getChildren(); + for (let child of children) { + if (child.kind < SyntaxKind.FirstNode) { + return child; + } + + return child.getFirstToken(sourceFile); + } + } + + public getLastToken(sourceFile?: SourceFile): Node { + let children = this.getChildren(sourceFile); + for (let i = children.length - 1; i >= 0; i--) { + let child = children[i]; + if (child.kind < SyntaxKind.FirstNode) { + return child; + } + + return child.getLastToken(sourceFile); + } + } + } + + class SymbolObject implements Symbol { + flags: SymbolFlags; + name: string; + declarations: Declaration[]; + + // Undefined is used to indicate the value has not been computed. If, after computing, the + // symbol has no doc comment, then the empty string will be returned. + documentationComment: SymbolDisplayPart[]; + + constructor(flags: SymbolFlags, name: string) { + this.flags = flags; + this.name = name; + } + + getFlags(): SymbolFlags { + return this.flags; + } + + getName(): string { + return this.name; + } + + getDeclarations(): Declaration[] { + return this.declarations; + } + + getDocumentationComment(): SymbolDisplayPart[] { + if (this.documentationComment === undefined) { + this.documentationComment = getJsDocCommentsFromDeclarations(this.declarations, this.name, !(this.flags & SymbolFlags.Property)); + } + + return this.documentationComment; + } + } + + function getJsDocCommentsFromDeclarations(declarations: Declaration[], name: string, canUseParsedParamTagComments: boolean) { + let documentationComment = []; + let docComments = getJsDocCommentsSeparatedByNewLines(); + ts.forEach(docComments, docComment => { + if (documentationComment.length) { + documentationComment.push(lineBreakPart()); + } + documentationComment.push(docComment); + }); + + return documentationComment; + + function getJsDocCommentsSeparatedByNewLines() { + let paramTag = "@param"; + let jsDocCommentParts: SymbolDisplayPart[] = []; + + ts.forEach(declarations, (declaration, indexOfDeclaration) => { + // Make sure we are collecting doc comment from declaration once, + // In case of union property there might be same declaration multiple times + // which only varies in type parameter + // Eg. let a: Array | Array; a.length + // The property length will have two declarations of property length coming + // from Array - Array and Array + if (indexOf(declarations, declaration) === indexOfDeclaration) { + let sourceFileOfDeclaration = getSourceFileOfNode(declaration); + // If it is parameter - try and get the jsDoc comment with @param tag from function declaration's jsDoc comments + if (canUseParsedParamTagComments && declaration.kind === SyntaxKind.Parameter) { + ts.forEach(getJsDocCommentTextRange(declaration.parent, sourceFileOfDeclaration), jsDocCommentTextRange => { + let cleanedParamJsDocComment = getCleanedParamJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration); + if (cleanedParamJsDocComment) { + jsDocCommentParts.push.apply(jsDocCommentParts, cleanedParamJsDocComment); + } + }); + } + + // If this is left side of dotted module declaration, there is no doc comments associated with this node + if (declaration.kind === SyntaxKind.ModuleDeclaration && (declaration).body.kind === SyntaxKind.ModuleDeclaration) { + return; + } + + // If this is dotted module name, get the doc comments from the parent + while (declaration.kind === SyntaxKind.ModuleDeclaration && declaration.parent.kind === SyntaxKind.ModuleDeclaration) { + declaration = declaration.parent; + } + + // Get the cleaned js doc comment text from the declaration + ts.forEach(getJsDocCommentTextRange( + declaration.kind === SyntaxKind.VariableDeclaration ? declaration.parent.parent : declaration, sourceFileOfDeclaration), jsDocCommentTextRange => { + let cleanedJsDocComment = getCleanedJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration); + if (cleanedJsDocComment) { + jsDocCommentParts.push.apply(jsDocCommentParts, cleanedJsDocComment); + } + }); + } + }); + + return jsDocCommentParts; + + function getJsDocCommentTextRange(node: Node, sourceFile: SourceFile): TextRange[] { + return ts.map(getJsDocComments(node, sourceFile), + jsDocComment => { + return { + pos: jsDocComment.pos + "/*".length, // Consume /* from the comment + end: jsDocComment.end - "*/".length // Trim off comment end indicator + }; + }); + } + + function consumeWhiteSpacesOnTheLine(pos: number, end: number, sourceFile: SourceFile, maxSpacesToRemove?: number) { + if (maxSpacesToRemove !== undefined) { + end = Math.min(end, pos + maxSpacesToRemove); + } + + for (; pos < end; pos++) { + let ch = sourceFile.text.charCodeAt(pos); + if (!isWhiteSpace(ch) || isLineBreak(ch)) { + // Either found lineBreak or non whiteSpace + return pos; + } + } + + return end; + } + + function consumeLineBreaks(pos: number, end: number, sourceFile: SourceFile) { + while (pos < end && isLineBreak(sourceFile.text.charCodeAt(pos))) { + pos++; + } + + return pos; + } + + function isName(pos: number, end: number, sourceFile: SourceFile, name: string) { + return pos + name.length < end && + sourceFile.text.substr(pos, name.length) === name && + (isWhiteSpace(sourceFile.text.charCodeAt(pos + name.length)) || + isLineBreak(sourceFile.text.charCodeAt(pos + name.length))); + } + + function isParamTag(pos: number, end: number, sourceFile: SourceFile) { + // If it is @param tag + return isName(pos, end, sourceFile, paramTag); + } + + function pushDocCommentLineText(docComments: SymbolDisplayPart[], text: string, blankLineCount: number) { + // Add the empty lines in between texts + while (blankLineCount--) { + docComments.push(textPart("")); + } + + docComments.push(textPart(text)); + } + + function getCleanedJsDocComment(pos: number, end: number, sourceFile: SourceFile) { + let spacesToRemoveAfterAsterisk: number; + let docComments: SymbolDisplayPart[] = []; + let blankLineCount = 0; + let isInParamTag = false; + + while (pos < end) { + let docCommentTextOfLine = ""; + // First consume leading white space + pos = consumeWhiteSpacesOnTheLine(pos, end, sourceFile); + + // If the comment starts with '*' consume the spaces on this line + if (pos < end && sourceFile.text.charCodeAt(pos) === CharacterCodes.asterisk) { + let lineStartPos = pos + 1; + pos = consumeWhiteSpacesOnTheLine(pos + 1, end, sourceFile, spacesToRemoveAfterAsterisk); + + // Set the spaces to remove after asterisk as margin if not already set + if (spacesToRemoveAfterAsterisk === undefined && pos < end && !isLineBreak(sourceFile.text.charCodeAt(pos))) { + spacesToRemoveAfterAsterisk = pos - lineStartPos; + } + } + else if (spacesToRemoveAfterAsterisk === undefined) { + spacesToRemoveAfterAsterisk = 0; + } + + // Analyse text on this line + while (pos < end && !isLineBreak(sourceFile.text.charCodeAt(pos))) { + let ch = sourceFile.text.charAt(pos); + if (ch === "@") { + // If it is @param tag + if (isParamTag(pos, end, sourceFile)) { + isInParamTag = true; + pos += paramTag.length; + continue; + } + else { + isInParamTag = false; + } + } + + // Add the ch to doc text if we arent in param tag + if (!isInParamTag) { + docCommentTextOfLine += ch; + } + + // Scan next character + pos++; + } + + // Continue with next line + pos = consumeLineBreaks(pos, end, sourceFile); + if (docCommentTextOfLine) { + pushDocCommentLineText(docComments, docCommentTextOfLine, blankLineCount); + blankLineCount = 0; + } + else if (!isInParamTag && docComments.length) { + // This is blank line when there is text already parsed + blankLineCount++; + } + } + + return docComments; + } + + function getCleanedParamJsDocComment(pos: number, end: number, sourceFile: SourceFile) { + let paramHelpStringMargin: number; + let paramDocComments: SymbolDisplayPart[] = []; + while (pos < end) { + if (isParamTag(pos, end, sourceFile)) { + let blankLineCount = 0; + let recordedParamTag = false; + // Consume leading spaces + pos = consumeWhiteSpaces(pos + paramTag.length); + if (pos >= end) { + break; + } + + // Ignore type expression + if (sourceFile.text.charCodeAt(pos) === CharacterCodes.openBrace) { + pos++; + for (let curlies = 1; pos < end; pos++) { + let charCode = sourceFile.text.charCodeAt(pos); + + // { character means we need to find another } to match the found one + if (charCode === CharacterCodes.openBrace) { + curlies++; + continue; + } + + // } char + if (charCode === CharacterCodes.closeBrace) { + curlies--; + if (curlies === 0) { + // We do not have any more } to match the type expression is ignored completely + pos++; + break; + } + else { + // there are more { to be matched with } + continue; + } + } + + // Found start of another tag + if (charCode === CharacterCodes.at) { + break; + } + } + + // Consume white spaces + pos = consumeWhiteSpaces(pos); + if (pos >= end) { + break; + } + } + + // Parameter name + if (isName(pos, end, sourceFile, name)) { + // Found the parameter we are looking for consume white spaces + pos = consumeWhiteSpaces(pos + name.length); + if (pos >= end) { + break; + } + + let paramHelpString = ""; + let firstLineParamHelpStringPos = pos; + while (pos < end) { + let ch = sourceFile.text.charCodeAt(pos); + + // at line break, set this comment line text and go to next line + if (isLineBreak(ch)) { + if (paramHelpString) { + pushDocCommentLineText(paramDocComments, paramHelpString, blankLineCount); + paramHelpString = ""; + blankLineCount = 0; + recordedParamTag = true; + } + else if (recordedParamTag) { + blankLineCount++; + } + + // Get the pos after cleaning start of the line + setPosForParamHelpStringOnNextLine(firstLineParamHelpStringPos); + continue; + } + + // Done scanning param help string - next tag found + if (ch === CharacterCodes.at) { + break; + } + + paramHelpString += sourceFile.text.charAt(pos); + + // Go to next character + pos++; + } + + // If there is param help text, add it top the doc comments + if (paramHelpString) { + pushDocCommentLineText(paramDocComments, paramHelpString, blankLineCount); + } + paramHelpStringMargin = undefined; + } + + // If this is the start of another tag, continue with the loop in seach of param tag with symbol name + if (sourceFile.text.charCodeAt(pos) === CharacterCodes.at) { + continue; + } + } + + // Next character + pos++; + } + + return paramDocComments; + + function consumeWhiteSpaces(pos: number) { + while (pos < end && isWhiteSpace(sourceFile.text.charCodeAt(pos))) { + pos++; + } + + return pos; + } + + function setPosForParamHelpStringOnNextLine(firstLineParamHelpStringPos: number) { + // Get the pos after consuming line breaks + pos = consumeLineBreaks(pos, end, sourceFile); + if (pos >= end) { + return; + } + + if (paramHelpStringMargin === undefined) { + paramHelpStringMargin = sourceFile.getLineAndCharacterOfPosition(firstLineParamHelpStringPos).character; + } + + // Now consume white spaces max + let startOfLinePos = pos; + pos = consumeWhiteSpacesOnTheLine(pos, end, sourceFile, paramHelpStringMargin); + if (pos >= end) { + return; + } + + let consumedSpaces = pos - startOfLinePos; + if (consumedSpaces < paramHelpStringMargin) { + let ch = sourceFile.text.charCodeAt(pos); + if (ch === CharacterCodes.asterisk) { + // Consume more spaces after asterisk + pos = consumeWhiteSpacesOnTheLine(pos + 1, end, sourceFile, paramHelpStringMargin - consumedSpaces - 1); + } + } + } + } + } + } + + class TypeObject implements Type { + checker: TypeChecker; + flags: TypeFlags; + id: number; + symbol: Symbol; + constructor(checker: TypeChecker, flags: TypeFlags) { + this.checker = checker; + this.flags = flags; + } + getFlags(): TypeFlags { + return this.flags; + } + getSymbol(): Symbol { + return this.symbol; + } + getProperties(): Symbol[] { + return this.checker.getPropertiesOfType(this); + } + getProperty(propertyName: string): Symbol { + return this.checker.getPropertyOfType(this, propertyName); + } + getApparentProperties(): Symbol[] { + return this.checker.getAugmentedPropertiesOfType(this); + } + getCallSignatures(): Signature[] { + return this.checker.getSignaturesOfType(this, SignatureKind.Call); + } + getConstructSignatures(): Signature[] { + return this.checker.getSignaturesOfType(this, SignatureKind.Construct); + } + getStringIndexType(): Type { + return this.checker.getIndexTypeOfType(this, IndexKind.String); + } + getNumberIndexType(): Type { + return this.checker.getIndexTypeOfType(this, IndexKind.Number); + } + } + + class SignatureObject implements Signature { + checker: TypeChecker; + declaration: SignatureDeclaration; + typeParameters: TypeParameter[]; + parameters: Symbol[]; + resolvedReturnType: Type; + minArgumentCount: number; + hasRestParameter: boolean; + hasStringLiterals: boolean; + + // Undefined is used to indicate the value has not been computed. If, after computing, the + // symbol has no doc comment, then the empty string will be returned. + documentationComment: SymbolDisplayPart[]; + + constructor(checker: TypeChecker) { + this.checker = checker; + } + getDeclaration(): SignatureDeclaration { + return this.declaration; + } + getTypeParameters(): Type[] { + return this.typeParameters; + } + getParameters(): Symbol[] { + return this.parameters; + } + getReturnType(): Type { + return this.checker.getReturnTypeOfSignature(this); + } + + getDocumentationComment(): SymbolDisplayPart[] { + if (this.documentationComment === undefined) { + this.documentationComment = this.declaration ? getJsDocCommentsFromDeclarations( + [this.declaration], + /*name*/ undefined, + /*canUseParsedParamTagComments*/ false) : []; + } + + return this.documentationComment; + } + } + + class SourceFileObject extends NodeObject implements SourceFile { + public _declarationBrand: any; + public fileName: string; + public text: string; + public scriptSnapshot: IScriptSnapshot; + public lineMap: number[]; + + public statements: NodeArray; + public endOfFileToken: Node; + + public amdDependencies: { name: string; path: string }[]; + public amdModuleName: string; + public referencedFiles: FileReference[]; + + public syntacticDiagnostics: Diagnostic[]; + public referenceDiagnostics: Diagnostic[]; + public parseDiagnostics: Diagnostic[]; + public bindDiagnostics: Diagnostic[]; + + public hasNoDefaultLib: boolean; + public externalModuleIndicator: Node; // The first node that causes this file to be an external module + public nodeCount: number; + public identifierCount: number; + public symbolCount: number; + public version: string; + public languageVersion: ScriptTarget; + public identifiers: Map; + public nameTable: Map; + + private namedDeclarations: Map; + + public update(newText: string, textChangeRange: TextChangeRange): SourceFile { + return updateSourceFile(this, newText, textChangeRange); + } + + public getLineAndCharacterOfPosition(position: number): LineAndCharacter { + return ts.getLineAndCharacterOfPosition(this, position); + } + + public getLineStarts(): number[] { + return getLineStarts(this); + } + + public getPositionOfLineAndCharacter(line: number, character: number): number { + return ts.getPositionOfLineAndCharacter(this, line, character); + } + + public getNamedDeclarations(): Map { + if (!this.namedDeclarations) { + this.namedDeclarations = this.computeNamedDeclarations(); + } + + return this.namedDeclarations; + } + + private computeNamedDeclarations(): Map { + let result: Map = {}; + + forEachChild(this, visit); + + return result; + + function addDeclaration(declaration: Declaration) { + let name = getDeclarationName(declaration); + if (name) { + let declarations = getDeclarations(name); + declarations.push(declaration); + } + } + + function getDeclarations(name: string) { + return getProperty(result, name) || (result[name] = []); + } + + function getDeclarationName(declaration: Declaration) { + if (declaration.name) { + let result = getTextOfIdentifierOrLiteral(declaration.name); + if (result !== undefined) { + return result; + } + + if (declaration.name.kind === SyntaxKind.ComputedPropertyName) { + let expr = (declaration.name).expression; + if (expr.kind === SyntaxKind.PropertyAccessExpression) { + return (expr).name.text; + } + + return getTextOfIdentifierOrLiteral(expr); + } + } + + return undefined; + } + + function getTextOfIdentifierOrLiteral(node: Node) { + if (node) { + if (node.kind === SyntaxKind.Identifier || + node.kind === SyntaxKind.StringLiteral || + node.kind === SyntaxKind.NumericLiteral) { + + return (node).text; + } + } + + return undefined; + } + + function visit(node: Node): void { + switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + let functionDeclaration = node; + let declarationName = getDeclarationName(functionDeclaration); + + if (declarationName) { + let declarations = getDeclarations(declarationName); + let lastDeclaration = lastOrUndefined(declarations); + + // Check whether this declaration belongs to an "overload group". + if (lastDeclaration && functionDeclaration.parent === lastDeclaration.parent && functionDeclaration.symbol === lastDeclaration.symbol) { + // Overwrite the last declaration if it was an overload + // and this one is an implementation. + if (functionDeclaration.body && !(lastDeclaration).body) { + declarations[declarations.length - 1] = functionDeclaration; + } + } + else { + declarations.push(functionDeclaration); + } + + forEachChild(node, visit); + } + break; + + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ExportSpecifier: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportClause: + case SyntaxKind.NamespaceImport: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.TypeLiteral: + addDeclaration(node); + // fall through + case SyntaxKind.Constructor: + case SyntaxKind.VariableStatement: + case SyntaxKind.VariableDeclarationList: + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.ModuleBlock: + forEachChild(node, visit); + break; + + case SyntaxKind.Block: + if (isFunctionBlock(node)) { + forEachChild(node, visit); + } + break; + + case SyntaxKind.Parameter: + // Only consider properties defined as constructor parameters + if (!(node.flags & NodeFlags.AccessibilityModifier)) { + break; + } + // fall through + case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: + if (isBindingPattern((node).name)) { + forEachChild((node).name, visit); + break; + } + case SyntaxKind.EnumMember: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + addDeclaration(node); + break; + + case SyntaxKind.ExportDeclaration: + // Handle named exports case e.g.: + // export {a, b as B} from "mod"; + if ((node).exportClause) { + forEach((node).exportClause.elements, visit); + } + break; + + case SyntaxKind.ImportDeclaration: + let importClause = (node).importClause; + if (importClause) { + // Handle default import case e.g.: + // import d from "mod"; + if (importClause.name) { + addDeclaration(importClause); + } + + // Handle named bindings in imports e.g.: + // import * as NS from "mod"; + // import {a, b as B} from "mod"; + if (importClause.namedBindings) { + if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + addDeclaration(importClause.namedBindings); + } + else { + forEach((importClause.namedBindings).elements, visit); + } + } + } + break; + } + } + } + } + + // + // Public interface of the host of a language service instance. + // + export interface LanguageServiceHost { + getCompilationSettings(): CompilerOptions; + getNewLine?(): string; + getScriptFileNames(): string[]; + getScriptVersion(fileName: string): string; + getScriptSnapshot(fileName: string): IScriptSnapshot; + getLocalizedDiagnosticMessages?(): any; + getCancellationToken?(): CancellationToken; + getCurrentDirectory(): string; + getDefaultLibFileName(options: CompilerOptions): string; + log? (s: string): void; + trace? (s: string): void; + error? (s: string): void; + } + + // + // Public services of a language service instance associated + // with a language service host instance + // + export interface LanguageService { + cleanupSemanticCache(): void; + + getSyntacticDiagnostics(fileName: string): Diagnostic[]; + getSemanticDiagnostics(fileName: string): Diagnostic[]; + getCompilerOptionsDiagnostics(): Diagnostic[]; + + getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + + getCompletionsAtPosition(fileName: string, position: number): CompletionInfo; + getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails; + + getQuickInfoAtPosition(fileName: string, position: number): QuickInfo; + + getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan; + + getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan; + + getSignatureHelpItems(fileName: string, position: number): SignatureHelpItems; + + getRenameInfo(fileName: string, position: number): RenameInfo; + findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[]; + + getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + findReferences(fileName: string, position: number): ReferencedSymbol[]; + getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[]; + + /** @deprecated */ + getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + + getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[]; + getNavigationBarItems(fileName: string): NavigationBarItem[]; + + getOutliningSpans(fileName: string): OutliningSpan[]; + getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[]; + getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[]; + getIndentationAtPosition(fileName: string, position: number, options: EditorOptions): number; + + getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions): TextChange[]; + getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions): TextChange[]; + getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextChange[]; + + getEmitOutput(fileName: string): EmitOutput; + + getProgram(): Program; + + getSourceFile(fileName: string): SourceFile; + + dispose(): void; + } + + export interface ClassifiedSpan { + textSpan: TextSpan; + classificationType: string; // ClassificationTypeNames + } + + export interface NavigationBarItem { + text: string; + kind: string; + kindModifiers: string; + spans: TextSpan[]; + childItems: NavigationBarItem[]; + indent: number; + bolded: boolean; + grayed: boolean; + } + + export interface TodoCommentDescriptor { + text: string; + priority: number; + } + + export interface TodoComment { + descriptor: TodoCommentDescriptor; + message: string; + position: number; + } + + export class TextChange { + span: TextSpan; + newText: string; + } + + export interface RenameLocation { + textSpan: TextSpan; + fileName: string; + } + + export interface ReferenceEntry { + textSpan: TextSpan; + fileName: string; + isWriteAccess: boolean; + } + + export interface DocumentHighlights { + fileName: string; + highlightSpans: HighlightSpan[]; + } + + export module HighlightSpanKind { + export const none = "none"; + export const definition = "definition"; + export const reference = "reference"; + export const writtenReference = "writtenReference"; + } + + export interface HighlightSpan { + textSpan: TextSpan; + kind: string; + } + + export interface NavigateToItem { + name: string; + kind: string; + kindModifiers: string; + matchKind: string; + isCaseSensitive: boolean; + fileName: string; + textSpan: TextSpan; + containerName: string; + containerKind: string; + } + + export interface EditorOptions { + IndentSize: number; + TabSize: number; + NewLineCharacter: string; + ConvertTabsToSpaces: boolean; + } + + export interface FormatCodeOptions extends EditorOptions { + InsertSpaceAfterCommaDelimiter: boolean; + InsertSpaceAfterSemicolonInForStatements: boolean; + InsertSpaceBeforeAndAfterBinaryOperators: boolean; + InsertSpaceAfterKeywordsInControlFlowStatements: boolean; + InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean; + InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean; + PlaceOpenBraceOnNewLineForFunctions: boolean; + PlaceOpenBraceOnNewLineForControlBlocks: boolean; + [s: string]: boolean | number| string; + } + + export interface DefinitionInfo { + fileName: string; + textSpan: TextSpan; + kind: string; + name: string; + containerKind: string; + containerName: string; + } + + export interface ReferencedSymbol { + definition: DefinitionInfo; + references: ReferenceEntry[]; + } + + export enum SymbolDisplayPartKind { + aliasName, + className, + enumName, + fieldName, + interfaceName, + keyword, + lineBreak, + numericLiteral, + stringLiteral, + localName, + methodName, + moduleName, + operator, + parameterName, + propertyName, + punctuation, + space, + text, + typeParameterName, + enumMemberName, + functionName, + regularExpressionLiteral, + } + + export interface SymbolDisplayPart { + text: string; + kind: string; + } + + export interface QuickInfo { + kind: string; + kindModifiers: string; + textSpan: TextSpan; + displayParts: SymbolDisplayPart[]; + documentation: SymbolDisplayPart[]; + } + + export interface RenameInfo { + canRename: boolean; + localizedErrorMessage: string; + displayName: string; + fullDisplayName: string; + kind: string; + kindModifiers: string; + triggerSpan: TextSpan; + } + + export interface SignatureHelpParameter { + name: string; + documentation: SymbolDisplayPart[]; + displayParts: SymbolDisplayPart[]; + isOptional: boolean; + } + + /** + * Represents a single signature to show in signature help. + * The id is used for subsequent calls into the language service to ask questions about the + * signature help item in the context of any documents that have been updated. i.e. after + * an edit has happened, while signature help is still active, the host can ask important + * questions like 'what parameter is the user currently contained within?'. + */ + export interface SignatureHelpItem { + isVariadic: boolean; + prefixDisplayParts: SymbolDisplayPart[]; + suffixDisplayParts: SymbolDisplayPart[]; + separatorDisplayParts: SymbolDisplayPart[]; + parameters: SignatureHelpParameter[]; + documentation: SymbolDisplayPart[]; + } + + /** + * Represents a set of signature help items, and the preferred item that should be selected. + */ + export interface SignatureHelpItems { + items: SignatureHelpItem[]; + applicableSpan: TextSpan; + selectedItemIndex: number; + argumentIndex: number; + argumentCount: number; + } + + export interface CompletionInfo { + isMemberCompletion: boolean; + isNewIdentifierLocation: boolean; // true when the current location also allows for a new identifier + entries: CompletionEntry[]; + } + + export interface CompletionEntry { + name: string; + kind: string; // see ScriptElementKind + kindModifiers: string; // see ScriptElementKindModifier, comma separated + sortText: string; + } + + export interface CompletionEntryDetails { + name: string; + kind: string; // see ScriptElementKind + kindModifiers: string; // see ScriptElementKindModifier, comma separated + displayParts: SymbolDisplayPart[]; + documentation: SymbolDisplayPart[]; + } + + export interface OutliningSpan { + /** The span of the document to actually collapse. */ + textSpan: TextSpan; + + /** The span of the document to display when the user hovers over the collapsed span. */ + hintSpan: TextSpan; + + /** The text to display in the editor for the collapsed region. */ + bannerText: string; + + /** + * Whether or not this region should be automatically collapsed when + * the 'Collapse to Definitions' command is invoked. + */ + autoCollapse: boolean; + } + + export interface EmitOutput { + outputFiles: OutputFile[]; + emitSkipped: boolean; + } + + export const enum OutputFileType { + JavaScript, + SourceMap, + Declaration + } + + export interface OutputFile { + name: string; + writeByteOrderMark: boolean; + text: string; + } + + export const enum EndOfLineState { + Start, + InMultiLineCommentTrivia, + InSingleQuoteStringLiteral, + InDoubleQuoteStringLiteral, + InTemplateHeadOrNoSubstitutionTemplate, + InTemplateMiddleOrTail, + InTemplateSubstitutionPosition, + } + + export enum TokenClass { + Punctuation, + Keyword, + Operator, + Comment, + Whitespace, + Identifier, + NumberLiteral, + StringLiteral, + RegExpLiteral, + } + + export interface ClassificationResult { + finalLexState: EndOfLineState; + entries: ClassificationInfo[]; + } + + export interface ClassificationInfo { + length: number; + classification: TokenClass; + } + + export interface Classifier { + /** + * Gives lexical classifications of tokens on a line without any syntactic context. + * For instance, a token consisting of the text 'string' can be either an identifier + * named 'string' or the keyword 'string', however, because this classifier is not aware, + * it relies on certain heuristics to give acceptable results. For classifications where + * speed trumps accuracy, this function is preferable; however, for true accuracy, the + * syntactic classifier is ideal. In fact, in certain editing scenarios, combining the + * lexical, syntactic, and semantic classifiers may issue the best user experience. + * + * @param text The text of a line to classify. + * @param lexState The state of the lexical classifier at the end of the previous line. + * @param syntacticClassifierAbsent Whether the client is *not* using a syntactic classifier. + * If there is no syntactic classifier (syntacticClassifierAbsent=true), + * certain heuristics may be used in its place; however, if there is a + * syntactic classifier (syntacticClassifierAbsent=false), certain + * classifications which may be incorrectly categorized will be given + * back as Identifiers in order to allow the syntactic classifier to + * subsume the classification. + */ + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; + } + + /** + * The document registry represents a store of SourceFile objects that can be shared between + * multiple LanguageService instances. A LanguageService instance holds on the SourceFile (AST) + * of files in the context. + * SourceFile objects account for most of the memory usage by the language service. Sharing + * the same DocumentRegistry instance between different instances of LanguageService allow + * for more efficient memory utilization since all projects will share at least the library + * file (lib.d.ts). + * + * A more advanced use of the document registry is to serialize sourceFile objects to disk + * and re-hydrate them when needed. + * + * To create a default DocumentRegistry, use createDocumentRegistry to create one, and pass it + * to all subsequent createLanguageService calls. + */ + export interface DocumentRegistry { + /** + * Request a stored SourceFile with a given fileName and compilationSettings. + * The first call to acquire will call createLanguageServiceSourceFile to generate + * the SourceFile if was not found in the registry. + * + * @param fileName The name of the file requested + * @param compilationSettings Some compilation settings like target affects the + * shape of a the resulting SourceFile. This allows the DocumentRegistry to store + * multiple copies of the same file for different compilation settings. + * @parm scriptSnapshot Text of the file. Only used if the file was not found + * in the registry and a new one was created. + * @parm version Current version of the file. Only used if the file was not found + * in the registry and a new one was created. + */ + acquireDocument( + fileName: string, + compilationSettings: CompilerOptions, + scriptSnapshot: IScriptSnapshot, + version: string): SourceFile; + + /** + * Request an updated version of an already existing SourceFile with a given fileName + * and compilationSettings. The update will in-turn call updateLanguageServiceSourceFile + * to get an updated SourceFile. + * + * @param fileName The name of the file requested + * @param compilationSettings Some compilation settings like target affects the + * shape of a the resulting SourceFile. This allows the DocumentRegistry to store + * multiple copies of the same file for different compilation settings. + * @param scriptSnapshot Text of the file. + * @param version Current version of the file. + */ + updateDocument( + fileName: string, + compilationSettings: CompilerOptions, + scriptSnapshot: IScriptSnapshot, + version: string): SourceFile; + + /** + * Informs the DocumentRegistry that a file is not needed any longer. + * + * Note: It is not allowed to call release on a SourceFile that was not acquired from + * this registry originally. + * + * @param fileName The name of the file to be released + * @param compilationSettings The compilation settings used to acquire the file + */ + releaseDocument(fileName: string, compilationSettings: CompilerOptions): void + } + + // TODO: move these to enums + export module ScriptElementKind { + export const unknown = ""; + export const warning = "warning"; + + // predefined type (void) or keyword (class) + export const keyword = "keyword"; + + // top level script node + export const scriptElement = "script"; + + // module foo {} + export const moduleElement = "module"; + + // class X {} + export const classElement = "class"; + + // interface Y {} + export const interfaceElement = "interface"; + + // type T = ... + export const typeElement = "type"; + + // enum E + export const enumElement = "enum"; + + // Inside module and script only + // let v = .. + export const variableElement = "var"; + + // Inside function + export const localVariableElement = "local var"; + + // Inside module and script only + // function f() { } + export const functionElement = "function"; + + // Inside function + export const localFunctionElement = "local function"; + + // class X { [public|private]* foo() {} } + export const memberFunctionElement = "method"; + + // class X { [public|private]* [get|set] foo:number; } + export const memberGetAccessorElement = "getter"; + export const memberSetAccessorElement = "setter"; + + // class X { [public|private]* foo:number; } + // interface Y { foo:number; } + export const memberVariableElement = "property"; + + // class X { constructor() { } } + export const constructorImplementationElement = "constructor"; + + // interface Y { ():number; } + export const callSignatureElement = "call"; + + // interface Y { []:number; } + export const indexSignatureElement = "index"; + + // interface Y { new():Y; } + export const constructSignatureElement = "construct"; + + // function foo(*Y*: string) + export const parameterElement = "parameter"; + + export const typeParameterElement = "type parameter"; + + export const primitiveType = "primitive type"; + + export const label = "label"; + + export const alias = "alias"; + + export const constElement = "const"; + + export const letElement = "let"; + } + + export module ScriptElementKindModifier { + export const none = ""; + export const publicMemberModifier = "public"; + export const privateMemberModifier = "private"; + export const protectedMemberModifier = "protected"; + export const exportedModifier = "export"; + export const ambientModifier = "declare"; + export const staticModifier = "static"; + } + + export class ClassificationTypeNames { + public static comment = "comment"; + public static identifier = "identifier"; + public static keyword = "keyword"; + public static numericLiteral = "number"; + public static operator = "operator"; + public static stringLiteral = "string"; + public static whiteSpace = "whitespace"; + public static text = "text"; + + public static punctuation = "punctuation"; + + public static className = "class name"; + public static enumName = "enum name"; + public static interfaceName = "interface name"; + public static moduleName = "module name"; + public static typeParameterName = "type parameter name"; + public static typeAlias = "type alias name"; + } + + /// Language Service + + interface FormattingOptions { + useTabs: boolean; + spacesPerTab: number; + indentSpaces: number; + newLineCharacter: string; + } + + // Information about a specific host file. + interface HostFileInformation { + hostFileName: string; + version: string; + scriptSnapshot: IScriptSnapshot; + } + + interface DocumentRegistryEntry { + sourceFile: SourceFile; + + // The number of language services that this source file is referenced in. When no more + // language services are referencing the file, then the file can be removed from the + // registry. + languageServiceRefCount: number; + owners: string[]; + } + + export interface DisplayPartsSymbolWriter extends SymbolWriter { + displayParts(): SymbolDisplayPart[]; + } + + export function displayPartsToString(displayParts: SymbolDisplayPart[]) { + if (displayParts) { + return map(displayParts, displayPart => displayPart.text).join(""); + } + + return ""; + } + + function isLocalVariableOrFunction(symbol: Symbol) { + if (symbol.parent) { + return false; // This is exported symbol + } + + return ts.forEach(symbol.declarations, declaration => { + // Function expressions are local + if (declaration.kind === SyntaxKind.FunctionExpression) { + return true; + } + + if (declaration.kind !== SyntaxKind.VariableDeclaration && declaration.kind !== SyntaxKind.FunctionDeclaration) { + return false; + } + + // If the parent is not sourceFile or module block it is local variable + for (let parent = declaration.parent; !isFunctionBlock(parent); parent = parent.parent) { + // Reached source file or module block + if (parent.kind === SyntaxKind.SourceFile || parent.kind === SyntaxKind.ModuleBlock) { + return false; + } + } + + // parent is in function block + return true; + }); + } + + export function getDefaultCompilerOptions(): CompilerOptions { + // Always default to "ScriptTarget.ES5" for the language service + return { + target: ScriptTarget.ES5, + module: ModuleKind.None, + }; + } + + export class OperationCanceledException { } + + export class CancellationTokenObject { + + public static None: CancellationTokenObject = new CancellationTokenObject(null) + + constructor(private cancellationToken: CancellationToken) { + } + + public isCancellationRequested() { + return this.cancellationToken && this.cancellationToken.isCancellationRequested(); + } + + public throwIfCancellationRequested(): void { + if (this.isCancellationRequested()) { + throw new OperationCanceledException(); + } + } + } + + // Cache host information about scrip Should be refreshed + // at each language service public entry point, since we don't know when + // set of scripts handled by the host changes. + class HostCache { + private fileNameToEntry: Map; + private _compilationSettings: CompilerOptions; + + constructor(private host: LanguageServiceHost) { + // script id => script index + this.fileNameToEntry = {}; + + // Initialize the list with the root file names + let rootFileNames = host.getScriptFileNames(); + for (let fileName of rootFileNames) { + this.createEntry(fileName); + } + + // store the compilation settings + this._compilationSettings = host.getCompilationSettings() || getDefaultCompilerOptions(); + } + + public compilationSettings() { + return this._compilationSettings; + } + + private createEntry(fileName: string) { + let entry: HostFileInformation; + let scriptSnapshot = this.host.getScriptSnapshot(fileName); + if (scriptSnapshot) { + entry = { + hostFileName: fileName, + version: this.host.getScriptVersion(fileName), + scriptSnapshot: scriptSnapshot + }; + } + + return this.fileNameToEntry[normalizeSlashes(fileName)] = entry; + } + + public getEntry(fileName: string): HostFileInformation { + return lookUp(this.fileNameToEntry, normalizeSlashes(fileName)); + } + + public contains(fileName: string): boolean { + return hasProperty(this.fileNameToEntry, normalizeSlashes(fileName)); + } + + public getOrCreateEntry(fileName: string): HostFileInformation { + if (this.contains(fileName)) { + return this.getEntry(fileName); + } + + return this.createEntry(fileName); + } + + public getRootFileNames(): string[] { + let fileNames: string[] = []; + + forEachKey(this.fileNameToEntry, key => { + if (hasProperty(this.fileNameToEntry, key) && this.fileNameToEntry[key]) + fileNames.push(key); + }); + + return fileNames; + } + + public getVersion(fileName: string): string { + let file = this.getEntry(fileName); + return file && file.version; + } + + public getScriptSnapshot(fileName: string): IScriptSnapshot { + let file = this.getEntry(fileName); + return file && file.scriptSnapshot; + } + } + + class SyntaxTreeCache { + // For our syntactic only features, we also keep a cache of the syntax tree for the + // currently edited file. + private currentFileName: string; + private currentFileVersion: string; + private currentFileScriptSnapshot: IScriptSnapshot; + private currentSourceFile: SourceFile; + + constructor(private host: LanguageServiceHost) { + } + + public getCurrentSourceFile(fileName: string): SourceFile { + let scriptSnapshot = this.host.getScriptSnapshot(fileName); + if (!scriptSnapshot) { + // The host does not know about this file. + throw new Error("Could not find file: '" + fileName + "'."); + } + + let version = this.host.getScriptVersion(fileName); + let sourceFile: SourceFile; + + if (this.currentFileName !== fileName) { + // This is a new file, just parse it + sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, ScriptTarget.Latest, version, /*setNodeParents:*/ true); + } + else if (this.currentFileVersion !== version) { + // This is the same file, just a newer version. Incrementally parse the file. + let editRange = scriptSnapshot.getChangeRange(this.currentFileScriptSnapshot); + sourceFile = updateLanguageServiceSourceFile(this.currentSourceFile, scriptSnapshot, version, editRange); + } + + if (sourceFile) { + // All done, ensure state is up to date + this.currentFileVersion = version; + this.currentFileName = fileName; + this.currentFileScriptSnapshot = scriptSnapshot; + this.currentSourceFile = sourceFile; + } + + return this.currentSourceFile; + } + } + + function setSourceFileFields(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string) { + sourceFile.version = version; + sourceFile.scriptSnapshot = scriptSnapshot; + } + + /* + * This function will compile source text from 'input' argument using specified compiler options. + * If not options are provided - it will use a set of default compiler options. + * Extra compiler options that will unconditionally be used bu this function are: + * - separateCompilation = true + * - allowNonTsExtensions = true + */ + export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[]): string { + let options = compilerOptions ? clone(compilerOptions) : getDefaultCompilerOptions(); + + options.separateCompilation = true; + + // Filename can be non-ts file. + options.allowNonTsExtensions = true; + + // Parse + var inputFileName = fileName || "module.ts"; + var sourceFile = createSourceFile(inputFileName, input, options.target); + + // Store syntactic diagnostics + if (diagnostics && sourceFile.parseDiagnostics) { + diagnostics.push(...sourceFile.parseDiagnostics); + } + + // Output + let outputText: string; + + // Create a compilerHost object to allow the compiler to read and write files + var compilerHost: CompilerHost = { + getSourceFile: (fileName, target) => fileName === inputFileName ? sourceFile : undefined, + writeFile: (name, text, writeByteOrderMark) => { + Debug.assert(outputText === undefined, "Unexpected multiple outputs for the file: " + name); + outputText = text; + }, + getDefaultLibFileName: () => "lib.d.ts", + useCaseSensitiveFileNames: () => false, + getCanonicalFileName: fileName => fileName, + getCurrentDirectory: () => "", + getNewLine: () => (sys && sys.newLine) || "\r\n" + }; + + var program = createProgram([inputFileName], options, compilerHost); + + if (diagnostics) { + diagnostics.push(...program.getGlobalDiagnostics()); + } + + // Emit + program.emit(); + + Debug.assert(outputText !== undefined, "Output generation failed"); + + return outputText; + } + + export function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, setNodeParents: boolean): SourceFile { + let sourceFile = createSourceFile(fileName, scriptSnapshot.getText(0, scriptSnapshot.getLength()), scriptTarget, setNodeParents); + setSourceFileFields(sourceFile, scriptSnapshot, version); + // after full parsing we can use table with interned strings as name table + sourceFile.nameTable = sourceFile.identifiers; + return sourceFile; + } + + export let disableIncrementalParsing = false; + + export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile { + // If we were given a text change range, and our version or open-ness changed, then + // incrementally parse this file. + if (textChangeRange) { + if (version !== sourceFile.version) { + // Once incremental parsing is ready, then just call into this function. + if (!disableIncrementalParsing) { + let newSourceFile = updateSourceFile(sourceFile, scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange, aggressiveChecks); + setSourceFileFields(newSourceFile, scriptSnapshot, version); + // after incremental parsing nameTable might not be up-to-date + // drop it so it can be lazily recreated later + newSourceFile.nameTable = undefined; + return newSourceFile; + } + } + } + + // Otherwise, just create a new source file. + return createLanguageServiceSourceFile(sourceFile.fileName, scriptSnapshot, sourceFile.languageVersion, version, /*setNodeParents:*/ true); + } + + export function createDocumentRegistry(): DocumentRegistry { + // Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have + // for those settings. + let buckets: Map> = {}; + + function getKeyFromCompilationSettings(settings: CompilerOptions): string { + return "_" + settings.target; // + "|" + settings.propagateEnumConstantoString() + } + + function getBucketForCompilationSettings(settings: CompilerOptions, createIfMissing: boolean): Map { + let key = getKeyFromCompilationSettings(settings); + let bucket = lookUp(buckets, key); + if (!bucket && createIfMissing) { + buckets[key] = bucket = {}; + } + return bucket; + } + + function reportStats() { + let bucketInfoArray = Object.keys(buckets).filter(name => name && name.charAt(0) === '_').map(name => { + let entries = lookUp(buckets, name); + let sourceFiles: { name: string; refCount: number; references: string[]; }[] = []; + for (let i in entries) { + let entry = entries[i]; + sourceFiles.push({ + name: i, + refCount: entry.languageServiceRefCount, + references: entry.owners.slice(0) + }); + } + sourceFiles.sort((x, y) => y.refCount - x.refCount); + return { + bucket: name, + sourceFiles + }; + }); + return JSON.stringify(bucketInfoArray, null, 2); + } + + function acquireDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string): SourceFile { + return acquireOrUpdateDocument(fileName, compilationSettings, scriptSnapshot, version, /*acquiring:*/ true); + } + + function updateDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string): SourceFile { + return acquireOrUpdateDocument(fileName, compilationSettings, scriptSnapshot, version, /*acquiring:*/ false); + } + + function acquireOrUpdateDocument( + fileName: string, + compilationSettings: CompilerOptions, + scriptSnapshot: IScriptSnapshot, + version: string, + acquiring: boolean): SourceFile { + + let bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); + let entry = lookUp(bucket, fileName); + if (!entry) { + Debug.assert(acquiring, "How could we be trying to update a document that the registry doesn't have?"); + + // Have never seen this file with these settings. Create a new source file for it. + let sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, compilationSettings.target, version, /*setNodeParents:*/ false); + + bucket[fileName] = entry = { + sourceFile: sourceFile, + languageServiceRefCount: 0, + owners: [] + }; + } + else { + // We have an entry for this file. However, it may be for a different version of + // the script snapshot. If so, update it appropriately. Otherwise, we can just + // return it as is. + if (entry.sourceFile.version !== version) { + entry.sourceFile = updateLanguageServiceSourceFile(entry.sourceFile, scriptSnapshot, version, + scriptSnapshot.getChangeRange(entry.sourceFile.scriptSnapshot)); + } + } + + // If we're acquiring, then this is the first time this LS is asking for this document. + // Increase our ref count so we know there's another LS using the document. If we're + // not acquiring, then that means the LS is 'updating' the file instead, and that means + // it has already acquired the document previously. As such, we do not need to increase + // the ref count. + if (acquiring) { + entry.languageServiceRefCount++; + } + + return entry.sourceFile; + } + + function releaseDocument(fileName: string, compilationSettings: CompilerOptions): void { + let bucket = getBucketForCompilationSettings(compilationSettings, false); + Debug.assert(bucket !== undefined); + + let entry = lookUp(bucket, fileName); + entry.languageServiceRefCount--; + + Debug.assert(entry.languageServiceRefCount >= 0); + if (entry.languageServiceRefCount === 0) { + delete bucket[fileName]; + } + } + + return { + acquireDocument, + updateDocument, + releaseDocument, + reportStats + }; + } + + export function preProcessFile(sourceText: string, readImportFiles = true): PreProcessedFileInfo { + let referencedFiles: FileReference[] = []; + let importedFiles: FileReference[] = []; + let isNoDefaultLib = false; + + function processTripleSlashDirectives(): void { + let commentRanges = getLeadingCommentRanges(sourceText, 0); + forEach(commentRanges, commentRange => { + let comment = sourceText.substring(commentRange.pos, commentRange.end); + let referencePathMatchResult = getFileReferenceFromReferencePath(comment, commentRange); + if (referencePathMatchResult) { + isNoDefaultLib = referencePathMatchResult.isNoDefaultLib; + let fileReference = referencePathMatchResult.fileReference; + if (fileReference) { + referencedFiles.push(fileReference); + } + } + }); + } + + function recordModuleName() { + let importPath = scanner.getTokenValue(); + let pos = scanner.getTokenPos(); + importedFiles.push({ + fileName: importPath, + pos: pos, + end: pos + importPath.length + }); + } + + function processImport(): void { + scanner.setText(sourceText); + let token = scanner.scan(); + // Look for: + // import "mod"; + // import d from "mod" + // import {a as A } from "mod"; + // import * as NS from "mod" + // import d, {a, b as B} from "mod" + // import i = require("mod"); + // + // export * from "mod" + // export {a as b} from "mod" + + while (token !== SyntaxKind.EndOfFileToken) { + if (token === SyntaxKind.ImportKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // import "mod"; + recordModuleName(); + continue; + } + else { + if (token === SyntaxKind.Identifier) { + token = scanner.scan(); + if (token === SyntaxKind.FromKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // import d from "mod"; + recordModuleName(); + continue + } + } + else if (token === SyntaxKind.EqualsToken) { + token = scanner.scan(); + if (token === SyntaxKind.RequireKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.OpenParenToken) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // import i = require("mod"); + recordModuleName(); + continue; + } + } + } + } + else if (token === SyntaxKind.CommaToken) { + // consume comma and keep going + token = scanner.scan(); + } + else { + // unknown syntax + continue; + } + } + + if (token === SyntaxKind.OpenBraceToken) { + token = scanner.scan(); + // consume "{ a as B, c, d as D}" clauses + while (token !== SyntaxKind.CloseBraceToken) { + token = scanner.scan(); + } + + if (token === SyntaxKind.CloseBraceToken) { + token = scanner.scan(); + if (token === SyntaxKind.FromKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // import {a as A} from "mod"; + // import d, {a, b as B} from "mod" + recordModuleName(); + } + } + } + } + else if (token === SyntaxKind.AsteriskToken) { + token = scanner.scan(); + if (token === SyntaxKind.AsKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.Identifier) { + token = scanner.scan(); + if (token === SyntaxKind.FromKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // import * as NS from "mod" + // import d, * as NS from "mod" + recordModuleName(); + } + } + } + } + } + } + } + else if (token === SyntaxKind.ExportKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.OpenBraceToken) { + token = scanner.scan(); + // consume "{ a as B, c, d as D}" clauses + while (token !== SyntaxKind.CloseBraceToken) { + token = scanner.scan(); + } + + if (token === SyntaxKind.CloseBraceToken) { + token = scanner.scan(); + if (token === SyntaxKind.FromKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // export {a as A} from "mod"; + // export {a, b as B} from "mod" + recordModuleName(); + } + } + } + } + else if (token === SyntaxKind.AsteriskToken) { + token = scanner.scan(); + if (token === SyntaxKind.FromKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // export * from "mod" + recordModuleName(); + } + } + } + } + token = scanner.scan(); + } + scanner.setText(undefined); + } + + if (readImportFiles) { + processImport(); + } + processTripleSlashDirectives(); + return { referencedFiles, importedFiles, isLibFile: isNoDefaultLib }; + } + + /// Helpers + function getTargetLabel(referenceNode: Node, labelName: string): Identifier { + while (referenceNode) { + if (referenceNode.kind === SyntaxKind.LabeledStatement && (referenceNode).label.text === labelName) { + return (referenceNode).label; + } + referenceNode = referenceNode.parent; + } + return undefined; + } + + function isJumpStatementTarget(node: Node): boolean { + return node.kind === SyntaxKind.Identifier && + (node.parent.kind === SyntaxKind.BreakStatement || node.parent.kind === SyntaxKind.ContinueStatement) && + (node.parent).label === node; + } + + function isLabelOfLabeledStatement(node: Node): boolean { + return node.kind === SyntaxKind.Identifier && + node.parent.kind === SyntaxKind.LabeledStatement && + (node.parent).label === node; + } + + /** + * Whether or not a 'node' is preceded by a label of the given string. + * Note: 'node' cannot be a SourceFile. + */ + function isLabeledBy(node: Node, labelName: string) { + for (let owner = node.parent; owner.kind === SyntaxKind.LabeledStatement; owner = owner.parent) { + if ((owner).label.text === labelName) { + return true; + } + } + + return false; + } + + function isLabelName(node: Node): boolean { + return isLabelOfLabeledStatement(node) || isJumpStatementTarget(node); + } + + function isRightSideOfQualifiedName(node: Node) { + return node.parent.kind === SyntaxKind.QualifiedName && (node.parent).right === node; + } + + function isRightSideOfPropertyAccess(node: Node) { + return node && node.parent && node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent).name === node; + } + + function isCallExpressionTarget(node: Node): boolean { + if (isRightSideOfPropertyAccess(node)) { + node = node.parent; + } + return node && node.parent && node.parent.kind === SyntaxKind.CallExpression && (node.parent).expression === node; + } + + function isNewExpressionTarget(node: Node): boolean { + if (isRightSideOfPropertyAccess(node)) { + node = node.parent; + } + return node && node.parent && node.parent.kind === SyntaxKind.NewExpression && (node.parent).expression === node; + } + + function isNameOfModuleDeclaration(node: Node) { + return node.parent.kind === SyntaxKind.ModuleDeclaration && (node.parent).name === node; + } + + function isNameOfFunctionDeclaration(node: Node): boolean { + return node.kind === SyntaxKind.Identifier && + isFunctionLike(node.parent) && (node.parent).name === node; + } + + /** Returns true if node is a name of an object literal property, e.g. "a" in x = { "a": 1 } */ + function isNameOfPropertyAssignment(node: Node): boolean { + return (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NumericLiteral) && + (node.parent.kind === SyntaxKind.PropertyAssignment || node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) && (node.parent).name === node; + } + + function isLiteralNameOfPropertyDeclarationOrIndexAccess(node: Node): boolean { + if (node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NumericLiteral) { + switch (node.parent.kind) { + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.EnumMember: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.ModuleDeclaration: + return (node.parent).name === node; + case SyntaxKind.ElementAccessExpression: + return (node.parent).argumentExpression === node; + } + } + + return false; + } + + function isNameOfExternalModuleImportOrDeclaration(node: Node): boolean { + if (node.kind === SyntaxKind.StringLiteral) { + return isNameOfModuleDeclaration(node) || + (isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node); + } + + return false; + } + + /** Returns true if the position is within a comment */ + function isInsideComment(sourceFile: SourceFile, token: Node, position: number): boolean { + // The position has to be: 1. in the leading trivia (before token.getStart()), and 2. within a comment + return position <= token.getStart(sourceFile) && + (isInsideCommentRange(getTrailingCommentRanges(sourceFile.text, token.getFullStart())) || + isInsideCommentRange(getLeadingCommentRanges(sourceFile.text, token.getFullStart()))); + + function isInsideCommentRange(comments: CommentRange[]): boolean { + return forEach(comments, comment => { + // either we are 1. completely inside the comment, or 2. at the end of the comment + if (comment.pos < position && position < comment.end) { + return true; + } + else if (position === comment.end) { + let text = sourceFile.text; + let width = comment.end - comment.pos; + // is single line comment or just /* + if (width <= 2 || text.charCodeAt(comment.pos + 1) === CharacterCodes.slash) { + return true; + } + else { + // is unterminated multi-line comment + return !(text.charCodeAt(comment.end - 1) === CharacterCodes.slash && + text.charCodeAt(comment.end - 2) === CharacterCodes.asterisk); + } + } + return false; + }); + } + } + + const enum SemanticMeaning { + None = 0x0, + Value = 0x1, + Type = 0x2, + Namespace = 0x4, + All = Value | Type | Namespace + } + + const enum BreakContinueSearchType { + None = 0x0, + Unlabeled = 0x1, + Labeled = 0x2, + All = Unlabeled | Labeled + } + + // A cache of completion entries for keywords, these do not change between sessions + let keywordCompletions: CompletionEntry[] = []; + for (let i = SyntaxKind.FirstKeyword; i <= SyntaxKind.LastKeyword; i++) { + keywordCompletions.push({ + name: tokenToString(i), + kind: ScriptElementKind.keyword, + kindModifiers: ScriptElementKindModifier.none, + sortText: "0" + }); + } + + /* @internal */ export function getContainerNode(node: Node): Declaration { + while (true) { + node = node.parent; + if (!node) { + return undefined; + } + switch (node.kind) { + case SyntaxKind.SourceFile: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ModuleDeclaration: + return node; + } + } + } + + /* @internal */ export function getNodeKind(node: Node): string { + switch (node.kind) { + case SyntaxKind.ModuleDeclaration: return ScriptElementKind.moduleElement; + case SyntaxKind.ClassDeclaration: return ScriptElementKind.classElement; + case SyntaxKind.InterfaceDeclaration: return ScriptElementKind.interfaceElement; + case SyntaxKind.TypeAliasDeclaration: return ScriptElementKind.typeElement; + case SyntaxKind.EnumDeclaration: return ScriptElementKind.enumElement; + case SyntaxKind.VariableDeclaration: + return isConst(node) + ? ScriptElementKind.constElement + : isLet(node) + ? ScriptElementKind.letElement + : ScriptElementKind.variableElement; + case SyntaxKind.FunctionDeclaration: return ScriptElementKind.functionElement; + case SyntaxKind.GetAccessor: return ScriptElementKind.memberGetAccessorElement; + case SyntaxKind.SetAccessor: return ScriptElementKind.memberSetAccessorElement; + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + return ScriptElementKind.memberFunctionElement; + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + return ScriptElementKind.memberVariableElement; + case SyntaxKind.IndexSignature: return ScriptElementKind.indexSignatureElement; + case SyntaxKind.ConstructSignature: return ScriptElementKind.constructSignatureElement; + case SyntaxKind.CallSignature: return ScriptElementKind.callSignatureElement; + case SyntaxKind.Constructor: return ScriptElementKind.constructorImplementationElement; + case SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement; + case SyntaxKind.EnumMember: return ScriptElementKind.variableElement; + case SyntaxKind.Parameter: return (node.flags & NodeFlags.AccessibilityModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement; + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ImportClause: + case SyntaxKind.ExportSpecifier: + case SyntaxKind.NamespaceImport: + return ScriptElementKind.alias; + } + return ScriptElementKind.unknown; + } + + export function createLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry = createDocumentRegistry()): LanguageService { + let syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); + let ruleProvider: formatting.RulesProvider; + let program: Program; + + let useCaseSensitivefileNames = false; + let cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken()); + + // Check if the localized messages json is set, otherwise query the host for it + if (!localizedDiagnosticMessages && host.getLocalizedDiagnosticMessages) { + localizedDiagnosticMessages = host.getLocalizedDiagnosticMessages(); + } + + function log(message: string) { + if (host.log) { + host.log(message); + } + } + + function getCanonicalFileName(fileName: string) { + return useCaseSensitivefileNames ? fileName : fileName.toLowerCase(); + } + + function getValidSourceFile(fileName: string): SourceFile { + fileName = normalizeSlashes(fileName); + let sourceFile = program.getSourceFile(getCanonicalFileName(fileName)); + if (!sourceFile) { + throw new Error("Could not find file: '" + fileName + "'."); + } + return sourceFile; + } + + function getRuleProvider(options: FormatCodeOptions) { + // Ensure rules are initialized and up to date wrt to formatting options + if (!ruleProvider) { + ruleProvider = new formatting.RulesProvider(); + } + + ruleProvider.ensureUpToDate(options); + return ruleProvider; + } + + function synchronizeHostData(): void { + // Get a fresh cache of the host information + let hostCache = new HostCache(host); + + // If the program is already up-to-date, we can reuse it + if (programUpToDate()) { + return; + } + + // IMPORTANT - It is critical from this moment onward that we do not check + // cancellation tokens. We are about to mutate source files from a previous program + // instance. If we cancel midway through, we may end up in an inconsistent state where + // the program points to old source files that have been invalidated because of + // incremental parsing. + + let oldSettings = program && program.getCompilerOptions(); + let newSettings = hostCache.compilationSettings(); + let changesInCompilationSettingsAffectSyntax = oldSettings && oldSettings.target !== newSettings.target; + + // Now create a new compiler + let newProgram = createProgram(hostCache.getRootFileNames(), newSettings, { + getSourceFile: getOrCreateSourceFile, + getCancellationToken: () => cancellationToken, + getCanonicalFileName: (fileName) => useCaseSensitivefileNames ? fileName : fileName.toLowerCase(), + useCaseSensitiveFileNames: () => useCaseSensitivefileNames, + getNewLine: () => host.getNewLine ? host.getNewLine() : "\r\n", + getDefaultLibFileName: (options) => host.getDefaultLibFileName(options), + writeFile: (fileName, data, writeByteOrderMark) => { }, + getCurrentDirectory: () => host.getCurrentDirectory() + }); + + // Release any files we have acquired in the old program but are + // not part of the new program. + if (program) { + let oldSourceFiles = program.getSourceFiles(); + for (let oldSourceFile of oldSourceFiles) { + let fileName = oldSourceFile.fileName; + if (!newProgram.getSourceFile(fileName) || changesInCompilationSettingsAffectSyntax) { + documentRegistry.releaseDocument(fileName, oldSettings); + } + } + } + + program = newProgram; + + // Make sure all the nodes in the program are both bound, and have their parent + // pointers set property. + program.getTypeChecker(); + return; + + function getOrCreateSourceFile(fileName: string): SourceFile { + // The program is asking for this file, check first if the host can locate it. + // If the host can not locate the file, then it does not exist. return undefined + // to the program to allow reporting of errors for missing files. + let hostFileInformation = hostCache.getOrCreateEntry(fileName); + if (!hostFileInformation) { + return undefined; + } + + // Check if the language version has changed since we last created a program; if they are the same, + // it is safe to reuse the souceFiles; if not, then the shape of the AST can change, and the oldSourceFile + // can not be reused. we have to dump all syntax trees and create new ones. + if (!changesInCompilationSettingsAffectSyntax) { + // Check if the old program had this file already + let oldSourceFile = program && program.getSourceFile(fileName); + if (oldSourceFile) { + // We already had a source file for this file name. Go to the registry to + // ensure that we get the right up to date version of it. We need this to + // address the following 'race'. Specifically, say we have the following: + // + // LS1 + // \ + // DocumentRegistry + // / + // LS2 + // + // Each LS has a reference to file 'foo.ts' at version 1. LS2 then updates + // it's version of 'foo.ts' to version 2. This will cause LS2 and the + // DocumentRegistry to have version 2 of the document. HOwever, LS1 will + // have version 1. And *importantly* this source file will be *corrupt*. + // The act of creating version 2 of the file irrevocably damages the version + // 1 file. + // + // So, later when we call into LS1, we need to make sure that it doesn't use + // it's source file any more, and instead defers to DocumentRegistry to get + // either version 1, version 2 (or some other version) depending on what the + // host says should be used. + return documentRegistry.updateDocument(fileName, newSettings, hostFileInformation.scriptSnapshot, hostFileInformation.version); + } + + // We didn't already have the file. Fall through and acquire it from the registry. + } + + // Could not find this file in the old program, create a new SourceFile for it. + return documentRegistry.acquireDocument(fileName, newSettings, hostFileInformation.scriptSnapshot, hostFileInformation.version); + } + + function sourceFileUpToDate(sourceFile: SourceFile): boolean { + return sourceFile && sourceFile.version === hostCache.getVersion(sourceFile.fileName); + } + + function programUpToDate(): boolean { + // If we haven't create a program yet, then it is not up-to-date + if (!program) { + return false; + } + + // If number of files in the program do not match, it is not up-to-date + let rootFileNames = hostCache.getRootFileNames(); + if (program.getSourceFiles().length !== rootFileNames.length) { + return false; + } + + // If any file is not up-to-date, then the whole program is not up-to-date + for (let fileName of rootFileNames) { + if (!sourceFileUpToDate(program.getSourceFile(fileName))) { + return false; + } + } + + // If the compilation settings do no match, then the program is not up-to-date + return compareDataObjects(program.getCompilerOptions(), hostCache.compilationSettings()); + } + } + + function getProgram(): Program { + synchronizeHostData(); + + return program; + } + + function cleanupSemanticCache(): void { + // TODO: Should we jettison the program (or it's type checker) here? + } + + function dispose(): void { + if (program) { + forEach(program.getSourceFiles(), f => + documentRegistry.releaseDocument(f.fileName, program.getCompilerOptions())); + } + } + + /// Diagnostics + function getSyntacticDiagnostics(fileName: string) { + synchronizeHostData(); + + return program.getSyntacticDiagnostics(getValidSourceFile(fileName)); + } + + /** + * getSemanticDiagnostiscs return array of Diagnostics. If '-d' is not enabled, only report semantic errors + * If '-d' enabled, report both semantic and emitter errors + */ + function getSemanticDiagnostics(fileName: string): Diagnostic[] { + synchronizeHostData(); + + let targetSourceFile = getValidSourceFile(fileName); + + // For JavaScript files, we don't want to report the normal typescript semantic errors. + // Instead, we just report errors for using TypeScript-only constructs from within a + // JavaScript file. + if (isJavaScript(fileName)) { + return getJavaScriptSemanticDiagnostics(targetSourceFile); + } + + // Only perform the action per file regardless of '-out' flag as LanguageServiceHost is expected to call this function per file. + // Therefore only get diagnostics for given file. + + let semanticDiagnostics = program.getSemanticDiagnostics(targetSourceFile); + if (!program.getCompilerOptions().declaration) { + return semanticDiagnostics; + } + + // If '-d' is enabled, check for emitter error. One example of emitter error is export class implements non-export interface + let declarationDiagnostics = program.getDeclarationDiagnostics(targetSourceFile); + return concatenate(semanticDiagnostics, declarationDiagnostics); + } + + function getJavaScriptSemanticDiagnostics(sourceFile: SourceFile): Diagnostic[] { + let diagnostics: Diagnostic[] = []; + walk(sourceFile); + + return diagnostics; + + function walk(node: Node): boolean { + if (!node) { + return false; + } + + switch (node.kind) { + case SyntaxKind.ImportEqualsDeclaration: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_a_ts_file)); + return true; + case SyntaxKind.ExportAssignment: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_a_ts_file)); + return true; + case SyntaxKind.ClassDeclaration: + let classDeclaration = node; + if (checkModifiers(classDeclaration.modifiers) || + checkTypeParameters(classDeclaration.typeParameters)) { + return true; + } + break; + case SyntaxKind.HeritageClause: + let heritageClause = node; + if (heritageClause.token === SyntaxKind.ImplementsKeyword) { + diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_a_ts_file)); + return true; + } + break; + case SyntaxKind.InterfaceDeclaration: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.interface_declarations_can_only_be_used_in_a_ts_file)); + return true; + case SyntaxKind.ModuleDeclaration: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.module_declarations_can_only_be_used_in_a_ts_file)); + return true; + case SyntaxKind.TypeAliasDeclaration: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.type_aliases_can_only_be_used_in_a_ts_file)); + return true; + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionDeclaration: + let functionDeclaration = node; + if (checkModifiers(functionDeclaration.modifiers) || + checkTypeParameters(functionDeclaration.typeParameters) || + checkTypeAnnotation(functionDeclaration.type)) { + return true; + } + break; + case SyntaxKind.VariableStatement: + let variableStatement = node; + if (checkModifiers(variableStatement.modifiers)) { + return true; + } + break; + case SyntaxKind.VariableDeclaration: + let variableDeclaration = node; + if (checkTypeAnnotation(variableDeclaration.type)) { + return true; + } + break; + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + let expression = node; + if (expression.typeArguments && expression.typeArguments.length > 0) { + let start = expression.typeArguments.pos; + diagnostics.push(createFileDiagnostic(sourceFile, start, expression.typeArguments.end - start, + Diagnostics.type_arguments_can_only_be_used_in_a_ts_file)); + return true; + } + break; + case SyntaxKind.Parameter: + let parameter = node; + if (parameter.modifiers) { + let start = parameter.modifiers.pos; + diagnostics.push(createFileDiagnostic(sourceFile, start, parameter.modifiers.end - start, + Diagnostics.parameter_modifiers_can_only_be_used_in_a_ts_file)); + return true; + } + if (parameter.questionToken) { + diagnostics.push(createDiagnosticForNode(parameter.questionToken, Diagnostics.can_only_be_used_in_a_ts_file)); + return true; + } + if (parameter.type) { + diagnostics.push(createDiagnosticForNode(parameter.type, Diagnostics.types_can_only_be_used_in_a_ts_file)); + return true; + } + break; + case SyntaxKind.PropertyDeclaration: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.property_declarations_can_only_be_used_in_a_ts_file)); + return true; + case SyntaxKind.EnumDeclaration: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file)); + return true; + case SyntaxKind.TypeAssertionExpression: + let typeAssertionExpression = node; + diagnostics.push(createDiagnosticForNode(typeAssertionExpression.type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file)); + return true; + case SyntaxKind.Decorator: + diagnostics.push(createDiagnosticForNode(node, Diagnostics.decorators_can_only_be_used_in_a_ts_file)); + return true; + } + + return forEachChild(node, walk); + } + + function checkTypeParameters(typeParameters: NodeArray): boolean { + if (typeParameters) { + let start = typeParameters.pos; + diagnostics.push(createFileDiagnostic(sourceFile, start, typeParameters.end - start, Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file)); + return true; + } + return false; + } + + function checkTypeAnnotation(type: TypeNode): boolean { + if (type) { + diagnostics.push(createDiagnosticForNode(type, Diagnostics.types_can_only_be_used_in_a_ts_file)); + return true; + } + + return false; + } + + function checkModifiers(modifiers: ModifiersArray): boolean { + if (modifiers) { + for (let modifier of modifiers) { + switch (modifier.kind) { + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.DeclareKeyword: + diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind))); + return true; + + // These are all legal modifiers. + case SyntaxKind.StaticKeyword: + case SyntaxKind.ExportKeyword: + case SyntaxKind.ConstKeyword: + case SyntaxKind.DefaultKeyword: + } + } + } + + return false; + } + } + + function getCompilerOptionsDiagnostics() { + synchronizeHostData(); + return program.getGlobalDiagnostics(); + } + + /// Completion + function getCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean): string { + let displayName = symbol.getName(); + if (displayName) { + // If this is the default export, get the name of the declaration if it exists + if (displayName === "default") { + let localSymbol = getLocalSymbolForExportDefault(symbol); + if (localSymbol && localSymbol.name) { + displayName = symbol.valueDeclaration.localSymbol.name; + } + } + + let firstCharCode = displayName.charCodeAt(0); + // First check of the displayName is not external module; if it is an external module, it is not valid entry + if ((symbol.flags & SymbolFlags.Namespace) && (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) { + // If the symbol is external module, don't show it in the completion list + // (i.e declare module "http" { let x; } | // <= request completion here, "http" should not be there) + return undefined; + } + } + + return getCompletionEntryDisplayName(displayName, target, performCharacterChecks); + } + + function getCompletionEntryDisplayName(displayName: string, target: ScriptTarget, performCharacterChecks: boolean): string { + if (!displayName) { + return undefined; + } + + let firstCharCode = displayName.charCodeAt(0); + if (displayName.length >= 2 && + firstCharCode === displayName.charCodeAt(displayName.length - 1) && + (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) { + // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an + // invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name. + displayName = displayName.substring(1, displayName.length - 1); + } + + if (!displayName) { + return undefined; + } + + if (performCharacterChecks) { + if (!isIdentifierStart(displayName.charCodeAt(0), target)) { + return undefined; + } + + for (let i = 1, n = displayName.length; i < n; i++) { + if (!isIdentifierPart(displayName.charCodeAt(i), target)) { + return undefined; + } + } + } + + return unescapeIdentifier(displayName); + } + + function getCompletionData(fileName: string, position: number) { + let typeChecker = program.getTypeChecker(); + let syntacticStart = new Date().getTime(); + let sourceFile = getValidSourceFile(fileName); + + let start = new Date().getTime(); + let currentToken = getTokenAtPosition(sourceFile, position); + log("getCompletionData: Get current token: " + (new Date().getTime() - start)); + + start = new Date().getTime(); + // Completion not allowed inside comments, bail out if this is the case + let insideComment = isInsideComment(sourceFile, currentToken, position); + log("getCompletionData: Is inside comment: " + (new Date().getTime() - start)); + + if (insideComment) { + log("Returning an empty list because completion was inside a comment."); + return undefined; + } + + start = new Date().getTime(); + let previousToken = findPrecedingToken(position, sourceFile); + log("getCompletionData: Get previous token 1: " + (new Date().getTime() - start)); + + // The decision to provide completion depends on the contextToken, which is determined through the previousToken. + // Note: 'previousToken' (and thus 'contextToken') can be undefined if we are the beginning of the file + let contextToken = previousToken; + + // Check if the caret is at the end of an identifier; this is a partial identifier that we want to complete: e.g. a.toS| + // Skip this partial identifier and adjust the contextToken to the token that precedes it. + if (contextToken && position <= contextToken.end && isWord(contextToken.kind)) { + let start = new Date().getTime(); + contextToken = findPrecedingToken(contextToken.getFullStart(), sourceFile); + log("getCompletionData: Get previous token 2: " + (new Date().getTime() - start)); + } + + // Check if this is a valid completion location + if (contextToken && isCompletionListBlocker(contextToken)) { + log("Returning an empty list because completion was requested in an invalid position."); + return undefined; + } + + // Find the node where completion is requested on, in the case of a completion after + // a dot, it is the member access expression other wise, it is a request for all + // visible symbols in the scope, and the node is the current location. + let node = currentToken; + let isRightOfDot = false; + if (contextToken && contextToken.kind === SyntaxKind.DotToken && contextToken.parent.kind === SyntaxKind.PropertyAccessExpression) { + node = (contextToken.parent).expression; + isRightOfDot = true; + } + else if (contextToken && contextToken.kind === SyntaxKind.DotToken && contextToken.parent.kind === SyntaxKind.QualifiedName) { + node = (contextToken.parent).left; + isRightOfDot = true; + } + + let location = getTouchingPropertyName(sourceFile, position); + var target = program.getCompilerOptions().target; + + let semanticStart = new Date().getTime(); + let isMemberCompletion: boolean; + let isNewIdentifierLocation: boolean; + let symbols: Symbol[] = []; + + if (isRightOfDot) { + getTypeScriptMemberSymbols(); + } + else { + // For JavaScript or TypeScript, if we're not after a dot, then just try to get the + // global symbols in scope. These results should be valid for either language as + // the set of symbols that can be referenced from this location. + if (!tryGetGlobalSymbols()) { + return undefined; + } + } + + log("getCompletionData: Semantic work: " + (new Date().getTime() - semanticStart)); + + return { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot }; + + function getTypeScriptMemberSymbols(): void { + // Right of dot member completion list + isMemberCompletion = true; + isNewIdentifierLocation = false; + + if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression) { + let symbol = typeChecker.getSymbolAtLocation(node); + + // This is an alias, follow what it aliases + if (symbol && symbol.flags & SymbolFlags.Alias) { + symbol = typeChecker.getAliasedSymbol(symbol); + } + + if (symbol && symbol.flags & SymbolFlags.HasExports) { + // Extract module or enum members + let exportedSymbols = typeChecker.getExportsOfModule(symbol); + forEach(exportedSymbols, symbol => { + if (typeChecker.isValidPropertyAccess((node.parent), symbol.name)) { + symbols.push(symbol); + } + }); + } + } + + let type = typeChecker.getTypeAtLocation(node); + if (type) { + // Filter private properties + forEach(type.getApparentProperties(), symbol => { + if (typeChecker.isValidPropertyAccess((node.parent), symbol.name)) { + symbols.push(symbol); + } + }); + } + } + + function tryGetGlobalSymbols(): boolean { + let containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(contextToken); + if (containingObjectLiteral) { + // Object literal expression, look up possible property names from contextual type + isMemberCompletion = true; + isNewIdentifierLocation = true; + + let contextualType = typeChecker.getContextualType(containingObjectLiteral); + if (!contextualType) { + return false; + } + + let contextualTypeMembers = typeChecker.getPropertiesOfType(contextualType); + if (contextualTypeMembers && contextualTypeMembers.length > 0) { + // Add filtered items to the completion list + symbols = filterContextualMembersList(contextualTypeMembers, containingObjectLiteral.properties); + } + } + else if (getAncestor(contextToken, SyntaxKind.ImportClause)) { + // cursor is in import clause + // try to show exported member for imported module + isMemberCompletion = true; + isNewIdentifierLocation = true; + if (showCompletionsInImportsClause(contextToken)) { + let importDeclaration = getAncestor(contextToken, SyntaxKind.ImportDeclaration); + Debug.assert(importDeclaration !== undefined); + + let exports: Symbol[]; + if (importDeclaration.moduleSpecifier) { + let moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importDeclaration.moduleSpecifier); + if (moduleSpecifierSymbol) { + exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol); + } + } + + //let exports = typeInfoResolver.getExportsOfImportDeclaration(importDeclaration); + symbols = exports ? filterModuleExports(exports, importDeclaration) : emptyArray; + } + } + else { + // Get all entities in the current scope. + isMemberCompletion = false; + isNewIdentifierLocation = isNewIdentifierDefinitionLocation(contextToken); + + if (previousToken !== contextToken) { + Debug.assert(!!previousToken, "Expected 'contextToken' to be defined when different from 'previousToken'."); + } + // We need to find the node that will give us an appropriate scope to begin + // aggregating completion candidates. This is achieved in 'getScopeNode' + // by finding the first node that encompasses a position, accounting for whether a node + // is "complete" to decide whether a position belongs to the node. + // + // However, at the end of an identifier, we are interested in the scope of the identifier + // itself, but fall outside of the identifier. For instance: + // + // xyz => x$ + // + // the cursor is outside of both the 'x' and the arrow function 'xyz => x', + // so 'xyz' is not returned in our results. + // + // We define 'adjustedPosition' so that we may appropriately account for + // being at the end of an identifier. The intention is that if requesting completion + // at the end of an identifier, it should be effectively equivalent to requesting completion + // anywhere inside/at the beginning of the identifier. So in the previous case, the + // 'adjustedPosition' will work as if requesting completion in the following: + // + // xyz => $x + // + // If previousToken !== contextToken, then + // - 'contextToken' was adjusted to the token prior to 'previousToken' + // because we were at the end of an identifier. + // - 'previousToken' is defined. + let adjustedPosition = previousToken !== contextToken ? + previousToken.getStart() : + position; + + let scopeNode = getScopeNode(contextToken, adjustedPosition, sourceFile) || sourceFile; + + /// TODO filter meaning based on the current context + let symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Alias; + symbols = typeChecker.getSymbolsInScope(scopeNode, symbolMeanings); + } + + return true; + } + + /** + * Finds the first node that "embraces" the position, so that one may + * accurately aggregate locals from the closest containing scope. + */ + function getScopeNode(initialToken: Node, position: number, sourceFile: SourceFile) { + var scope = initialToken; + while (scope && !positionBelongsToNode(scope, position, sourceFile)) { + scope = scope.parent; + } + return scope; + } + + function isCompletionListBlocker(previousToken: Node): boolean { + let start = new Date().getTime(); + let result = isInStringOrRegularExpressionOrTemplateLiteral(previousToken) || + isIdentifierDefinitionLocation(previousToken) || + isRightOfIllegalDot(previousToken); + log("getCompletionsAtPosition: isCompletionListBlocker: " + (new Date().getTime() - start)); + return result; + } + + function showCompletionsInImportsClause(node: Node): boolean { + if (node) { + // import {| + // import {a,| + if (node.kind === SyntaxKind.OpenBraceToken || node.kind === SyntaxKind.CommaToken) { + return node.parent.kind === SyntaxKind.NamedImports; + } + } + + return false; + } + + function isNewIdentifierDefinitionLocation(previousToken: Node): boolean { + if (previousToken) { + let containingNodeKind = previousToken.parent.kind; + switch (previousToken.kind) { + case SyntaxKind.CommaToken: + return containingNodeKind === SyntaxKind.CallExpression // func( a, | + || containingNodeKind === SyntaxKind.Constructor // constructor( a, | public, protected, private keywords are allowed here, so show completion + || containingNodeKind === SyntaxKind.NewExpression // new C(a, | + || containingNodeKind === SyntaxKind.ArrayLiteralExpression // [a, | + || containingNodeKind === SyntaxKind.BinaryExpression; // let x = (a, | + + + case SyntaxKind.OpenParenToken: + return containingNodeKind === SyntaxKind.CallExpression // func( | + || containingNodeKind === SyntaxKind.Constructor // constructor( | + || containingNodeKind === SyntaxKind.NewExpression // new C(a| + || containingNodeKind === SyntaxKind.ParenthesizedExpression; // let x = (a| + + case SyntaxKind.OpenBracketToken: + return containingNodeKind === SyntaxKind.ArrayLiteralExpression; // [ | + + case SyntaxKind.ModuleKeyword: // module | + return true; + + case SyntaxKind.DotToken: + return containingNodeKind === SyntaxKind.ModuleDeclaration; // module A.| + + case SyntaxKind.OpenBraceToken: + return containingNodeKind === SyntaxKind.ClassDeclaration; // class A{ | + + case SyntaxKind.EqualsToken: + return containingNodeKind === SyntaxKind.VariableDeclaration // let x = a| + || containingNodeKind === SyntaxKind.BinaryExpression; // x = a| + + case SyntaxKind.TemplateHead: + return containingNodeKind === SyntaxKind.TemplateExpression; // `aa ${| + + case SyntaxKind.TemplateMiddle: + return containingNodeKind === SyntaxKind.TemplateSpan; // `aa ${10} dd ${| + + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + return containingNodeKind === SyntaxKind.PropertyDeclaration; // class A{ public | + } + + // Previous token may have been a keyword that was converted to an identifier. + switch (previousToken.getText()) { + case "public": + case "protected": + case "private": + return true; + } + } + + return false; + } + + function isInStringOrRegularExpressionOrTemplateLiteral(previousToken: Node): boolean { + if (previousToken.kind === SyntaxKind.StringLiteral + || previousToken.kind === SyntaxKind.RegularExpressionLiteral + || isTemplateLiteralKind(previousToken.kind)) { + // The position has to be either: 1. entirely within the token text, or + // 2. at the end position of an unterminated token. + let start = previousToken.getStart(); + let end = previousToken.getEnd(); + + if (start < position && position < end) { + return true; + } + else if (position === end) { + return !!(previousToken).isUnterminated; + } + } + + return false; + } + + function getContainingObjectLiteralApplicableForCompletion(previousToken: Node): ObjectLiteralExpression { + // The locations in an object literal expression that are applicable for completion are property name definition locations. + + if (previousToken) { + let parent = previousToken.parent; + + switch (previousToken.kind) { + case SyntaxKind.OpenBraceToken: // let x = { | + case SyntaxKind.CommaToken: // let x = { a: 0, | + if (parent && parent.kind === SyntaxKind.ObjectLiteralExpression) { + return parent; + } + break; + } + } + + return undefined; + } + + function isFunction(kind: SyntaxKind): boolean { + switch (kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + return true; + } + return false; + } + + function isIdentifierDefinitionLocation(previousToken: Node): boolean { + if (previousToken) { + let containingNodeKind = previousToken.parent.kind; + switch (previousToken.kind) { + case SyntaxKind.CommaToken: + return containingNodeKind === SyntaxKind.VariableDeclaration || + containingNodeKind === SyntaxKind.VariableDeclarationList || + containingNodeKind === SyntaxKind.VariableStatement || + containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { foo, | + isFunction(containingNodeKind) || + containingNodeKind === SyntaxKind.ClassDeclaration || // class A = {}; + + if (!importDeclaration.importClause) { + return exports; + } + + if (importDeclaration.importClause.namedBindings && + importDeclaration.importClause.namedBindings.kind === SyntaxKind.NamedImports) { + + forEach((importDeclaration.importClause.namedBindings).elements, el => { + let name = el.propertyName || el.name; + exisingImports[name.text] = true; + }); + } + + if (isEmpty(exisingImports)) { + return exports; + } + return filter(exports, e => !lookUp(exisingImports, e.name)); + } + + function filterContextualMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] { + if (!existingMembers || existingMembers.length === 0) { + return contextualMemberSymbols; + } + + let existingMemberNames: Map = {}; + forEach(existingMembers, m => { + if (m.kind !== SyntaxKind.PropertyAssignment && m.kind !== SyntaxKind.ShorthandPropertyAssignment) { + // Ignore omitted expressions for missing members in the object literal + return; + } + + if (m.getStart() <= position && position <= m.getEnd()) { + // If this is the current item we are editing right now, do not filter it out + return; + } + + // TODO(jfreeman): Account for computed property name + existingMemberNames[(m.name).text] = true; + }); + + let filteredMembers: Symbol[] = []; + forEach(contextualMemberSymbols, s => { + if (!existingMemberNames[s.name]) { + filteredMembers.push(s); + } + }); + + return filteredMembers; + } + } + + function getCompletionsAtPosition(fileName: string, position: number): CompletionInfo { + synchronizeHostData(); + + let completionData = getCompletionData(fileName, position); + if (!completionData) { + return undefined; + } + + let { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot } = completionData; + + let entries: CompletionEntry[]; + if (isRightOfDot && isJavaScript(fileName)) { + entries = getCompletionEntriesFromSymbols(symbols); + addRange(entries, getJavaScriptCompletionEntries()); + } + else { + if (!symbols || symbols.length === 0) { + return undefined; + } + + entries = getCompletionEntriesFromSymbols(symbols); + } + + // Add keywords if this is not a member completion list + if (!isMemberCompletion) { + addRange(entries, keywordCompletions); + } + + return { isMemberCompletion, isNewIdentifierLocation, entries }; + + function getJavaScriptCompletionEntries(): CompletionEntry[] { + let entries: CompletionEntry[] = []; + let allNames: Map = {}; + let target = program.getCompilerOptions().target; + + for (let sourceFile of program.getSourceFiles()) { + let nameTable = getNameTable(sourceFile); + for (let name in nameTable) { + if (!allNames[name]) { + allNames[name] = name; + let displayName = getCompletionEntryDisplayName(name, target, /*performCharacterChecks:*/ true); + if (displayName) { + let entry = { + name: displayName, + kind: ScriptElementKind.warning, + kindModifiers: "", + sortText: "1" + }; + entries.push(entry); + } + } + } + } + + return entries; + } + + function createCompletionEntry(symbol: Symbol, location: Node): CompletionEntry { + // Try to get a valid display name for this symbol, if we could not find one, then ignore it. + // We would like to only show things that can be added after a dot, so for instance numeric properties can + // not be accessed with a dot (a.1 <- invalid) + let displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, /*performCharacterChecks:*/ true); + if (!displayName) { + return undefined; + } + + // TODO(drosen): Right now we just permit *all* semantic meanings when calling + // 'getSymbolKind' which is permissible given that it is backwards compatible; but + // really we should consider passing the meaning for the node so that we don't report + // that a suggestion for a value is an interface. We COULD also just do what + // 'getSymbolModifiers' does, which is to use the first declaration. + + // Use a 'sortText' of 0' so that all symbol completion entries come before any other + // entries (like JavaScript identifier entries). + return { + name: displayName, + kind: getSymbolKind(symbol, location), + kindModifiers: getSymbolModifiers(symbol), + sortText: "0", + }; + } + + function getCompletionEntriesFromSymbols(symbols: Symbol[]): CompletionEntry[] { + let start = new Date().getTime(); + var entries: CompletionEntry[] = []; + + if (symbols) { + var nameToSymbol: Map = {}; + for (let symbol of symbols) { + let entry = createCompletionEntry(symbol, location); + if (entry) { + let id = escapeIdentifier(entry.name); + if (!lookUp(nameToSymbol, id)) { + entries.push(entry); + nameToSymbol[id] = symbol; + } + } + } + } + + log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (new Date().getTime() - start)); + return entries; + } + } + + function getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails { + synchronizeHostData(); + + // Compute all the completion symbols again. + let completionData = getCompletionData(fileName, position); + if (completionData) { + let { symbols, location } = completionData; + + // Find the symbol with the matching entry name. + let target = program.getCompilerOptions().target; + // We don't need to perform character checks here because we're only comparing the + // name against 'entryName' (which is known to be good), not building a new + // completion entry. + let symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, target, /*performCharacterChecks:*/ false) === entryName ? s : undefined); + + if (symbol) { + let displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getValidSourceFile(fileName), location, location, SemanticMeaning.All); + return { + name: entryName, + kind: displayPartsDocumentationsAndSymbolKind.symbolKind, + kindModifiers: getSymbolModifiers(symbol), + displayParts: displayPartsDocumentationsAndSymbolKind.displayParts, + documentation: displayPartsDocumentationsAndSymbolKind.documentation + }; + } + } + + // Didn't find a symbol with this name. See if we can find a keyword instead. + let keywordCompletion = forEach(keywordCompletions, c => c.name === entryName); + if (keywordCompletion) { + return { + name: entryName, + kind: ScriptElementKind.keyword, + kindModifiers: ScriptElementKindModifier.none, + displayParts: [displayPart(entryName, SymbolDisplayPartKind.keyword)], + documentation: undefined + }; + } + + return undefined; + } + + // TODO(drosen): use contextual SemanticMeaning. + function getSymbolKind(symbol: Symbol, location: Node): string { + let flags = symbol.getFlags(); + + if (flags & SymbolFlags.Class) return ScriptElementKind.classElement; + if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement; + if (flags & SymbolFlags.TypeAlias) return ScriptElementKind.typeElement; + if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement; + if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; + + let result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, location); + if (result === ScriptElementKind.unknown) { + if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; + if (flags & SymbolFlags.EnumMember) return ScriptElementKind.variableElement; + if (flags & SymbolFlags.Alias) return ScriptElementKind.alias; + if (flags & SymbolFlags.Module) return ScriptElementKind.moduleElement; + } + + return result; + } + + function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags, location: Node) { + let typeChecker = program.getTypeChecker(); + + if (typeChecker.isUndefinedSymbol(symbol)) { + return ScriptElementKind.variableElement; + } + if (typeChecker.isArgumentsSymbol(symbol)) { + return ScriptElementKind.localVariableElement; + } + if (flags & SymbolFlags.Variable) { + if (isFirstDeclarationOfSymbolParameter(symbol)) { + return ScriptElementKind.parameterElement; + } + else if (symbol.valueDeclaration && isConst(symbol.valueDeclaration)) { + return ScriptElementKind.constElement; + } + else if (forEach(symbol.declarations, isLet)) { + return ScriptElementKind.letElement; + } + return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localVariableElement : ScriptElementKind.variableElement; + } + if (flags & SymbolFlags.Function) return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localFunctionElement : ScriptElementKind.functionElement; + if (flags & SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement; + if (flags & SymbolFlags.SetAccessor) return ScriptElementKind.memberSetAccessorElement; + if (flags & SymbolFlags.Method) return ScriptElementKind.memberFunctionElement; + if (flags & SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement; + + if (flags & SymbolFlags.Property) { + if (flags & SymbolFlags.UnionProperty) { + // If union property is result of union of non method (property/accessors/variables), it is labeled as property + let unionPropertyKind = forEach(typeChecker.getRootSymbols(symbol), rootSymbol => { + let rootSymbolFlags = rootSymbol.getFlags(); + if (rootSymbolFlags & (SymbolFlags.PropertyOrAccessor | SymbolFlags.Variable)) { + return ScriptElementKind.memberVariableElement; + } + Debug.assert(!!(rootSymbolFlags & SymbolFlags.Method)); + }); + if (!unionPropertyKind) { + // If this was union of all methods, + //make sure it has call signatures before we can label it as method + let typeOfUnionProperty = typeChecker.getTypeOfSymbolAtLocation(symbol, location); + if (typeOfUnionProperty.getCallSignatures().length) { + return ScriptElementKind.memberFunctionElement; + } + return ScriptElementKind.memberVariableElement; + } + return unionPropertyKind; + } + return ScriptElementKind.memberVariableElement; + } + + return ScriptElementKind.unknown; + } + + function getTypeKind(type: Type): string { + let flags = type.getFlags(); + + if (flags & TypeFlags.Enum) return ScriptElementKind.enumElement; + if (flags & TypeFlags.Class) return ScriptElementKind.classElement; + if (flags & TypeFlags.Interface) return ScriptElementKind.interfaceElement; + if (flags & TypeFlags.TypeParameter) return ScriptElementKind.typeParameterElement; + if (flags & TypeFlags.Intrinsic) return ScriptElementKind.primitiveType; + if (flags & TypeFlags.StringLiteral) return ScriptElementKind.primitiveType; + + return ScriptElementKind.unknown; + } + + function getSymbolModifiers(symbol: Symbol): string { + return symbol && symbol.declarations && symbol.declarations.length > 0 + ? getNodeModifiers(symbol.declarations[0]) + : ScriptElementKindModifier.none; + } + + // TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location + function getSymbolDisplayPartsDocumentationAndSymbolKind(symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node, + location: Node, semanticMeaning = getMeaningFromLocation(location)) { + + let typeChecker = program.getTypeChecker(); + + let displayParts: SymbolDisplayPart[] = []; + let documentation: SymbolDisplayPart[]; + let symbolFlags = symbol.flags; + let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags, location); + let hasAddedSymbolInfo: boolean; + let type: Type; + + // Class at constructor site need to be shown as constructor apart from property,method, vars + if (symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Class || symbolFlags & SymbolFlags.Alias) { + // If it is accessor they are allowed only if location is at name of the accessor + if (symbolKind === ScriptElementKind.memberGetAccessorElement || symbolKind === ScriptElementKind.memberSetAccessorElement) { + symbolKind = ScriptElementKind.memberVariableElement; + } + + let signature: Signature; + type = typeChecker.getTypeOfSymbolAtLocation(symbol, location); + if (type) { + if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) { + let right = (location.parent).name; + // Either the location is on the right of a property access, or on the left and the right is missing + if (right === location || (right && right.getFullWidth() === 0)) { + location = location.parent; + } + } + + // try get the call/construct signature from the type if it matches + let callExpression: CallExpression; + if (location.kind === SyntaxKind.CallExpression || location.kind === SyntaxKind.NewExpression) { + callExpression = location; + } + else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) { + callExpression = location.parent; + } + + if (callExpression) { + let candidateSignatures: Signature[] = []; + signature = typeChecker.getResolvedSignature(callExpression, candidateSignatures); + if (!signature && candidateSignatures.length) { + // Use the first candidate: + signature = candidateSignatures[0]; + } + + let useConstructSignatures = callExpression.kind === SyntaxKind.NewExpression || callExpression.expression.kind === SyntaxKind.SuperKeyword; + let allSignatures = useConstructSignatures ? type.getConstructSignatures() : type.getCallSignatures(); + + if (!contains(allSignatures, signature.target || signature)) { + // Get the first signature if there + signature = allSignatures.length ? allSignatures[0] : undefined; + } + + if (signature) { + if (useConstructSignatures && (symbolFlags & SymbolFlags.Class)) { + // Constructor + symbolKind = ScriptElementKind.constructorImplementationElement; + addPrefixForAnyFunctionOrVar(type.symbol, symbolKind); + } + else if (symbolFlags & SymbolFlags.Alias) { + symbolKind = ScriptElementKind.alias; + pushTypePart(symbolKind); + displayParts.push(spacePart()); + if (useConstructSignatures) { + displayParts.push(keywordPart(SyntaxKind.NewKeyword)); + displayParts.push(spacePart()); + } + addFullSymbolName(symbol); + } + else { + addPrefixForAnyFunctionOrVar(symbol, symbolKind); + } + + switch (symbolKind) { + case ScriptElementKind.memberVariableElement: + case ScriptElementKind.variableElement: + case ScriptElementKind.constElement: + case ScriptElementKind.letElement: + case ScriptElementKind.parameterElement: + case ScriptElementKind.localVariableElement: + // If it is call or construct signature of lambda's write type name + displayParts.push(punctuationPart(SyntaxKind.ColonToken)); + displayParts.push(spacePart()); + if (useConstructSignatures) { + displayParts.push(keywordPart(SyntaxKind.NewKeyword)); + displayParts.push(spacePart()); + } + if (!(type.flags & TypeFlags.Anonymous)) { + displayParts.push.apply(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); + } + addSignatureDisplayParts(signature, allSignatures, TypeFormatFlags.WriteArrowStyleSignature); + break; + + default: + // Just signature + addSignatureDisplayParts(signature, allSignatures); + } + hasAddedSymbolInfo = true; + } + } + else if ((isNameOfFunctionDeclaration(location) && !(symbol.flags & SymbolFlags.Accessor)) || // name of function declaration + (location.kind === SyntaxKind.ConstructorKeyword && location.parent.kind === SyntaxKind.Constructor)) { // At constructor keyword of constructor declaration + // get the signature from the declaration and write it + let functionDeclaration = location.parent; + let allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getConstructSignatures() : type.getCallSignatures(); + if (!typeChecker.isImplementationOfOverload(functionDeclaration)) { + signature = typeChecker.getSignatureFromDeclaration(functionDeclaration); + } + else { + signature = allSignatures[0]; + } + + if (functionDeclaration.kind === SyntaxKind.Constructor) { + // show (constructor) Type(...) signature + symbolKind = ScriptElementKind.constructorImplementationElement; + addPrefixForAnyFunctionOrVar(type.symbol, symbolKind); + } + else { + // (function/method) symbol(..signature) + addPrefixForAnyFunctionOrVar(functionDeclaration.kind === SyntaxKind.CallSignature && + !(type.symbol.flags & SymbolFlags.TypeLiteral || type.symbol.flags & SymbolFlags.ObjectLiteral) ? type.symbol : symbol, symbolKind); + } + + addSignatureDisplayParts(signature, allSignatures); + hasAddedSymbolInfo = true; + } + } + } + if (symbolFlags & SymbolFlags.Class && !hasAddedSymbolInfo) { + displayParts.push(keywordPart(SyntaxKind.ClassKeyword)); + displayParts.push(spacePart()); + addFullSymbolName(symbol); + writeTypeParametersOfSymbol(symbol, sourceFile); + } + if ((symbolFlags & SymbolFlags.Interface) && (semanticMeaning & SemanticMeaning.Type)) { + addNewLineIfDisplayPartsExist(); + displayParts.push(keywordPart(SyntaxKind.InterfaceKeyword)); + displayParts.push(spacePart()); + addFullSymbolName(symbol); + writeTypeParametersOfSymbol(symbol, sourceFile); + } + if (symbolFlags & SymbolFlags.TypeAlias) { + addNewLineIfDisplayPartsExist(); + displayParts.push(keywordPart(SyntaxKind.TypeKeyword)); + displayParts.push(spacePart()); + addFullSymbolName(symbol); + displayParts.push(spacePart()); + displayParts.push(operatorPart(SyntaxKind.EqualsToken)); + displayParts.push(spacePart()); + displayParts.push.apply(displayParts, typeToDisplayParts(typeChecker, typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration)); + } + if (symbolFlags & SymbolFlags.Enum) { + addNewLineIfDisplayPartsExist(); + if (forEach(symbol.declarations, isConstEnumDeclaration)) { + displayParts.push(keywordPart(SyntaxKind.ConstKeyword)); + displayParts.push(spacePart()); + } + displayParts.push(keywordPart(SyntaxKind.EnumKeyword)); + displayParts.push(spacePart()); + addFullSymbolName(symbol); + } + if (symbolFlags & SymbolFlags.Module) { + addNewLineIfDisplayPartsExist(); + displayParts.push(keywordPart(SyntaxKind.ModuleKeyword)); + displayParts.push(spacePart()); + addFullSymbolName(symbol); + } + if ((symbolFlags & SymbolFlags.TypeParameter) && (semanticMeaning & SemanticMeaning.Type)) { + addNewLineIfDisplayPartsExist(); + displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); + displayParts.push(textPart("type parameter")); + displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); + displayParts.push(spacePart()); + addFullSymbolName(symbol); + displayParts.push(spacePart()); + displayParts.push(keywordPart(SyntaxKind.InKeyword)); + displayParts.push(spacePart()); + if (symbol.parent) { + // Class/Interface type parameter + addFullSymbolName(symbol.parent, enclosingDeclaration); + writeTypeParametersOfSymbol(symbol.parent, enclosingDeclaration); + } + else { + // Method/function type parameter + let signatureDeclaration = getDeclarationOfKind(symbol, SyntaxKind.TypeParameter).parent; + let signature = typeChecker.getSignatureFromDeclaration(signatureDeclaration); + if (signatureDeclaration.kind === SyntaxKind.ConstructSignature) { + displayParts.push(keywordPart(SyntaxKind.NewKeyword)); + displayParts.push(spacePart()); + } + else if (signatureDeclaration.kind !== SyntaxKind.CallSignature && signatureDeclaration.name) { + addFullSymbolName(signatureDeclaration.symbol); + } + displayParts.push.apply(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); + } + } + if (symbolFlags & SymbolFlags.EnumMember) { + addPrefixForAnyFunctionOrVar(symbol, "enum member"); + let declaration = symbol.declarations[0]; + if (declaration.kind === SyntaxKind.EnumMember) { + let constantValue = typeChecker.getConstantValue(declaration); + if (constantValue !== undefined) { + displayParts.push(spacePart()); + displayParts.push(operatorPart(SyntaxKind.EqualsToken)); + displayParts.push(spacePart()); + displayParts.push(displayPart(constantValue.toString(), SymbolDisplayPartKind.numericLiteral)); + } + } + } + if (symbolFlags & SymbolFlags.Alias) { + addNewLineIfDisplayPartsExist(); + displayParts.push(keywordPart(SyntaxKind.ImportKeyword)); + displayParts.push(spacePart()); + addFullSymbolName(symbol); + ts.forEach(symbol.declarations, declaration => { + if (declaration.kind === SyntaxKind.ImportEqualsDeclaration) { + let importEqualsDeclaration = declaration; + if (isExternalModuleImportEqualsDeclaration(importEqualsDeclaration)) { + displayParts.push(spacePart()); + displayParts.push(operatorPart(SyntaxKind.EqualsToken)); + displayParts.push(spacePart()); + displayParts.push(keywordPart(SyntaxKind.RequireKeyword)); + displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); + displayParts.push(displayPart(getTextOfNode(getExternalModuleImportEqualsDeclarationExpression(importEqualsDeclaration)), SymbolDisplayPartKind.stringLiteral)); + displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); + } + else { + let internalAliasSymbol = typeChecker.getSymbolAtLocation(importEqualsDeclaration.moduleReference); + if (internalAliasSymbol) { + displayParts.push(spacePart()); + displayParts.push(operatorPart(SyntaxKind.EqualsToken)); + displayParts.push(spacePart()); + addFullSymbolName(internalAliasSymbol, enclosingDeclaration); + } + } + return true; + } + }); + } + if (!hasAddedSymbolInfo) { + if (symbolKind !== ScriptElementKind.unknown) { + if (type) { + addPrefixForAnyFunctionOrVar(symbol, symbolKind); + // For properties, variables and local vars: show the type + if (symbolKind === ScriptElementKind.memberVariableElement || + symbolFlags & SymbolFlags.Variable || + symbolKind === ScriptElementKind.localVariableElement) { + displayParts.push(punctuationPart(SyntaxKind.ColonToken)); + displayParts.push(spacePart()); + // If the type is type parameter, format it specially + if (type.symbol && type.symbol.flags & SymbolFlags.TypeParameter) { + let typeParameterParts = mapToDisplayParts(writer => { + typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(type, writer, enclosingDeclaration); + }); + displayParts.push.apply(displayParts, typeParameterParts); + } + else { + displayParts.push.apply(displayParts, typeToDisplayParts(typeChecker, type, enclosingDeclaration)); + } + } + else if (symbolFlags & SymbolFlags.Function || + symbolFlags & SymbolFlags.Method || + symbolFlags & SymbolFlags.Constructor || + symbolFlags & SymbolFlags.Signature || + symbolFlags & SymbolFlags.Accessor || + symbolKind === ScriptElementKind.memberFunctionElement) { + let allSignatures = type.getCallSignatures(); + addSignatureDisplayParts(allSignatures[0], allSignatures); + } + } + } + else { + symbolKind = getSymbolKind(symbol, location); + } + } + + if (!documentation) { + documentation = symbol.getDocumentationComment(); + } + + return { displayParts, documentation, symbolKind }; + + function addNewLineIfDisplayPartsExist() { + if (displayParts.length) { + displayParts.push(lineBreakPart()); + } + } + + function addFullSymbolName(symbol: Symbol, enclosingDeclaration?: Node) { + let fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbol, enclosingDeclaration || sourceFile, /*meaning*/ undefined, + SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing); + displayParts.push.apply(displayParts, fullSymbolDisplayParts); + } + + function addPrefixForAnyFunctionOrVar(symbol: Symbol, symbolKind: string) { + addNewLineIfDisplayPartsExist(); + if (symbolKind) { + pushTypePart(symbolKind); + displayParts.push(spacePart()); + addFullSymbolName(symbol); + } + } + + function pushTypePart(symbolKind: string) { + switch (symbolKind) { + case ScriptElementKind.variableElement: + case ScriptElementKind.functionElement: + case ScriptElementKind.letElement: + case ScriptElementKind.constElement: + case ScriptElementKind.constructorImplementationElement: + displayParts.push(textOrKeywordPart(symbolKind)); + return; + default: + displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); + displayParts.push(textOrKeywordPart(symbolKind)); + displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); + return; + } + } + + function addSignatureDisplayParts(signature: Signature, allSignatures: Signature[], flags?: TypeFormatFlags) { + displayParts.push.apply(displayParts, signatureToDisplayParts(typeChecker, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature)); + if (allSignatures.length > 1) { + displayParts.push(spacePart()); + displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); + displayParts.push(operatorPart(SyntaxKind.PlusToken)); + displayParts.push(displayPart((allSignatures.length - 1).toString(), SymbolDisplayPartKind.numericLiteral)); + displayParts.push(spacePart()); + displayParts.push(textPart(allSignatures.length === 2 ? "overload" : "overloads")); + displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); + } + documentation = signature.getDocumentationComment(); + } + + function writeTypeParametersOfSymbol(symbol: Symbol, enclosingDeclaration: Node) { + let typeParameterParts = mapToDisplayParts(writer => { + typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplayFromSymbol(symbol, writer, enclosingDeclaration); + }); + displayParts.push.apply(displayParts, typeParameterParts); + } + } + + function getQuickInfoAtPosition(fileName: string, position: number): QuickInfo { + synchronizeHostData(); + + let sourceFile = getValidSourceFile(fileName); + let node = getTouchingPropertyName(sourceFile, position); + if (!node) { + return undefined; + } + + if (isLabelName(node)) { + return undefined; + } + + let typeChecker = program.getTypeChecker(); + let symbol = typeChecker.getSymbolAtLocation(node); + + if (!symbol) { + // Try getting just type at this position and show + switch (node.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.QualifiedName: + case SyntaxKind.ThisKeyword: + case SyntaxKind.SuperKeyword: + // For the identifiers/this/super etc get the type at position + let type = typeChecker.getTypeAtLocation(node); + if (type) { + return { + kind: ScriptElementKind.unknown, + kindModifiers: ScriptElementKindModifier.none, + textSpan: createTextSpan(node.getStart(), node.getWidth()), + displayParts: typeToDisplayParts(typeChecker, type, getContainerNode(node)), + documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined + }; + } + } + + return undefined; + } + + let displayPartsDocumentationsAndKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, getContainerNode(node), node); + return { + kind: displayPartsDocumentationsAndKind.symbolKind, + kindModifiers: getSymbolModifiers(symbol), + textSpan: createTextSpan(node.getStart(), node.getWidth()), + displayParts: displayPartsDocumentationsAndKind.displayParts, + documentation: displayPartsDocumentationsAndKind.documentation + }; + } + + function createDefinitionInfo(node: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo { + return { + fileName: node.getSourceFile().fileName, + textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()), + kind: symbolKind, + name: symbolName, + containerKind: undefined, + containerName + }; + } + + /// Goto definition + function getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { + synchronizeHostData(); + + let sourceFile = getValidSourceFile(fileName); + + let node = getTouchingPropertyName(sourceFile, position); + if (!node) { + return undefined; + } + + // Labels + if (isJumpStatementTarget(node)) { + let labelName = (node).text; + let label = getTargetLabel((node.parent), (node).text); + return label ? [createDefinitionInfo(label, ScriptElementKind.label, labelName, /*containerName*/ undefined)] : undefined; + } + + /// Triple slash reference comments + let comment = forEach(sourceFile.referencedFiles, r => (r.pos <= position && position < r.end) ? r : undefined); + if (comment) { + let referenceFile = tryResolveScriptReference(program, sourceFile, comment); + if (referenceFile) { + return [{ + fileName: referenceFile.fileName, + textSpan: createTextSpanFromBounds(0, 0), + kind: ScriptElementKind.scriptElement, + name: comment.fileName, + containerName: undefined, + containerKind: undefined + }]; + } + return undefined; + } + + let typeChecker = program.getTypeChecker(); + let symbol = typeChecker.getSymbolAtLocation(node); + + // Could not find a symbol e.g. node is string or number keyword, + // or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol + if (!symbol) { + return undefined; + } + + // If this is an alias, and the request came at the declaration location + // get the aliased symbol instead. This allows for goto def on an import e.g. + // import {A, B} from "mod"; + // to jump to the implementation directly. + if (symbol.flags & SymbolFlags.Alias) { + let declaration = symbol.declarations[0]; + if (node.kind === SyntaxKind.Identifier && node.parent === declaration) { + symbol = typeChecker.getAliasedSymbol(symbol); + } + } + + // Because name in short-hand property assignment has two different meanings: property name and property value, + // using go-to-definition at such position should go to the variable declaration of the property value rather than + // go to the declaration of the property name (in this case stay at the same position). However, if go-to-definition + // is performed at the location of property access, we would like to go to definition of the property in the short-hand + // assignment. This case and others are handled by the following code. + if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) { + let shorthandSymbol = typeChecker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration); + if (!shorthandSymbol) { + return []; + } + + let shorthandDeclarations = shorthandSymbol.getDeclarations(); + let shorthandSymbolKind = getSymbolKind(shorthandSymbol, node); + let shorthandSymbolName = typeChecker.symbolToString(shorthandSymbol); + let shorthandContainerName = typeChecker.symbolToString(symbol.parent, node); + return map(shorthandDeclarations, + declaration => createDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName)); + } + + let result: DefinitionInfo[] = []; + let declarations = symbol.getDeclarations(); + let symbolName = typeChecker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol + let symbolKind = getSymbolKind(symbol, node); + let containerSymbol = symbol.parent; + let containerName = containerSymbol ? typeChecker.symbolToString(containerSymbol, node) : ""; + + if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) && + !tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) { + // Just add all the declarations. + forEach(declarations, declaration => { + result.push(createDefinitionInfo(declaration, symbolKind, symbolName, containerName)); + }); + } + + return result; + + function tryAddConstructSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { + // Applicable only if we are in a new expression, or we are on a constructor declaration + // and in either case the symbol has a construct signature definition, i.e. class + if (isNewExpressionTarget(location) || location.kind === SyntaxKind.ConstructorKeyword) { + if (symbol.flags & SymbolFlags.Class) { + let classDeclaration = symbol.getDeclarations()[0]; + Debug.assert(classDeclaration && classDeclaration.kind === SyntaxKind.ClassDeclaration); + + return tryAddSignature(classDeclaration.members, /*selectConstructors*/ true, symbolKind, symbolName, containerName, result); + } + } + return false; + } + + function tryAddCallSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { + if (isCallExpressionTarget(location) || isNewExpressionTarget(location) || isNameOfFunctionDeclaration(location)) { + return tryAddSignature(symbol.declarations, /*selectConstructors*/ false, symbolKind, symbolName, containerName, result); + } + return false; + } + + function tryAddSignature(signatureDeclarations: Declaration[], selectConstructors: boolean, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { + let declarations: Declaration[] = []; + let definition: Declaration; + + forEach(signatureDeclarations, d => { + if ((selectConstructors && d.kind === SyntaxKind.Constructor) || + (!selectConstructors && (d.kind === SyntaxKind.FunctionDeclaration || d.kind === SyntaxKind.MethodDeclaration || d.kind === SyntaxKind.MethodSignature))) { + declarations.push(d); + if ((d).body) definition = d; + } + }); + + if (definition) { + result.push(createDefinitionInfo(definition, symbolKind, symbolName, containerName)); + return true; + } + else if (declarations.length) { + result.push(createDefinitionInfo(declarations[declarations.length - 1], symbolKind, symbolName, containerName)); + return true; + } + + return false; + } + } + + function getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[] { + let results = getOccurrencesAtPositionCore(fileName, position); + + if (results) { + let sourceFile = getCanonicalFileName(normalizeSlashes(fileName)); + + // Get occurrences only supports reporting occurrences for the file queried. So + // filter down to that list. + results = filter(results, r => getCanonicalFileName(ts.normalizeSlashes(r.fileName)) === sourceFile); + } + + return results; + } + + function getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] { + synchronizeHostData(); + + filesToSearch = map(filesToSearch, normalizeSlashes); + let sourceFilesToSearch = filter(program.getSourceFiles(), f => contains(filesToSearch, f.fileName)); + let sourceFile = getValidSourceFile(fileName); + + let node = getTouchingWord(sourceFile, position); + if (!node) { + return undefined; + } + + return getSemanticDocumentHighlights(node) || getSyntacticDocumentHighlights(node); + + function getHighlightSpanForNode(node: Node): HighlightSpan { + let start = node.getStart(); + let end = node.getEnd(); + + return { + fileName: sourceFile.fileName, + textSpan: createTextSpanFromBounds(start, end), + kind: HighlightSpanKind.none + }; + } + + function getSemanticDocumentHighlights(node: Node): DocumentHighlights[] { + if (node.kind === SyntaxKind.Identifier || + node.kind === SyntaxKind.ThisKeyword || + node.kind === SyntaxKind.SuperKeyword || + isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || + isNameOfExternalModuleImportOrDeclaration(node)) { + + let referencedSymbols = getReferencedSymbolsForNodes(node, sourceFilesToSearch, /*findInStrings:*/ false, /*findInComments:*/ false); + return convertReferencedSymbols(referencedSymbols); + } + + return undefined; + + function convertReferencedSymbols(referencedSymbols: ReferencedSymbol[]): DocumentHighlights[] { + if (!referencedSymbols) { + return undefined; + } + + let fileNameToDocumentHighlights: Map = {}; + let result: DocumentHighlights[] = []; + for (let referencedSymbol of referencedSymbols) { + for (let referenceEntry of referencedSymbol.references) { + let fileName = referenceEntry.fileName; + let documentHighlights = getProperty(fileNameToDocumentHighlights, fileName); + if (!documentHighlights) { + documentHighlights = { fileName, highlightSpans: [] }; + + fileNameToDocumentHighlights[fileName] = documentHighlights; + result.push(documentHighlights); + } + + documentHighlights.highlightSpans.push({ + textSpan: referenceEntry.textSpan, + kind: referenceEntry.isWriteAccess ? HighlightSpanKind.writtenReference : HighlightSpanKind.reference + }); + } + } + + return result; + } + } + + function getSyntacticDocumentHighlights(node: Node): DocumentHighlights[] { + let fileName = sourceFile.fileName; + + var highlightSpans = getHighlightSpans(node); + if (!highlightSpans || highlightSpans.length === 0) { + return undefined; + } + + return [{ fileName, highlightSpans }]; + + // returns true if 'node' is defined and has a matching 'kind'. + function hasKind(node: Node, kind: SyntaxKind) { + return node !== undefined && node.kind === kind; + } + + // Null-propagating 'parent' function. + function parent(node: Node): Node { + return node && node.parent; + } + + function getHighlightSpans(node: Node): HighlightSpan[] { + if (node) { + switch (node.kind) { + case SyntaxKind.IfKeyword: + case SyntaxKind.ElseKeyword: + if (hasKind(node.parent, SyntaxKind.IfStatement)) { + return getIfElseOccurrences(node.parent); + } + break; + case SyntaxKind.ReturnKeyword: + if (hasKind(node.parent, SyntaxKind.ReturnStatement)) { + return getReturnOccurrences(node.parent); + } + break; + case SyntaxKind.ThrowKeyword: + if (hasKind(node.parent, SyntaxKind.ThrowStatement)) { + return getThrowOccurrences(node.parent); + } + break; + case SyntaxKind.CatchKeyword: + if (hasKind(parent(parent(node)), SyntaxKind.TryStatement)) { + return getTryCatchFinallyOccurrences(node.parent.parent); + } + break; + case SyntaxKind.TryKeyword: + case SyntaxKind.FinallyKeyword: + if (hasKind(parent(node), SyntaxKind.TryStatement)) { + return getTryCatchFinallyOccurrences(node.parent); + } + break; + case SyntaxKind.SwitchKeyword: + if (hasKind(node.parent, SyntaxKind.SwitchStatement)) { + return getSwitchCaseDefaultOccurrences(node.parent); + } + break; + case SyntaxKind.CaseKeyword: + case SyntaxKind.DefaultKeyword: + if (hasKind(parent(parent(parent(node))), SyntaxKind.SwitchStatement)) { + return getSwitchCaseDefaultOccurrences(node.parent.parent.parent); + } + break; + case SyntaxKind.BreakKeyword: + case SyntaxKind.ContinueKeyword: + if (hasKind(node.parent, SyntaxKind.BreakStatement) || hasKind(node.parent, SyntaxKind.ContinueStatement)) { + return getBreakOrContinueStatementOccurences(node.parent); + } + break; + case SyntaxKind.ForKeyword: + if (hasKind(node.parent, SyntaxKind.ForStatement) || + hasKind(node.parent, SyntaxKind.ForInStatement) || + hasKind(node.parent, SyntaxKind.ForOfStatement)) { + return getLoopBreakContinueOccurrences(node.parent); + } + break; + case SyntaxKind.WhileKeyword: + case SyntaxKind.DoKeyword: + if (hasKind(node.parent, SyntaxKind.WhileStatement) || hasKind(node.parent, SyntaxKind.DoStatement)) { + return getLoopBreakContinueOccurrences(node.parent); + } + break; + case SyntaxKind.ConstructorKeyword: + if (hasKind(node.parent, SyntaxKind.Constructor)) { + return getConstructorOccurrences(node.parent); + } + break; + case SyntaxKind.GetKeyword: + case SyntaxKind.SetKeyword: + if (hasKind(node.parent, SyntaxKind.GetAccessor) || hasKind(node.parent, SyntaxKind.SetAccessor)) { + return getGetAndSetOccurrences(node.parent); + } + default: + if (isModifier(node.kind) && node.parent && + (isDeclaration(node.parent) || node.parent.kind === SyntaxKind.VariableStatement)) { + return getModifierOccurrences(node.kind, node.parent); + } + } + } + + return undefined; + } + + /** + * Aggregates all throw-statements within this node *without* crossing + * into function boundaries and try-blocks with catch-clauses. + */ + function aggregateOwnedThrowStatements(node: Node): ThrowStatement[] { + let statementAccumulator: ThrowStatement[] = [] + aggregate(node); + return statementAccumulator; + + function aggregate(node: Node): void { + if (node.kind === SyntaxKind.ThrowStatement) { + statementAccumulator.push(node); + } + else if (node.kind === SyntaxKind.TryStatement) { + let tryStatement = node; + + if (tryStatement.catchClause) { + aggregate(tryStatement.catchClause); + } + else { + // Exceptions thrown within a try block lacking a catch clause + // are "owned" in the current context. + aggregate(tryStatement.tryBlock); + } + + if (tryStatement.finallyBlock) { + aggregate(tryStatement.finallyBlock); + } + } + // Do not cross function boundaries. + else if (!isFunctionLike(node)) { + forEachChild(node, aggregate); + } + }; + } + + /** + * For lack of a better name, this function takes a throw statement and returns the + * nearest ancestor that is a try-block (whose try statement has a catch clause), + * function-block, or source file. + */ + function getThrowStatementOwner(throwStatement: ThrowStatement): Node { + let child: Node = throwStatement; + + while (child.parent) { + let parent = child.parent; + + if (isFunctionBlock(parent) || parent.kind === SyntaxKind.SourceFile) { + return parent; + } + + // A throw-statement is only owned by a try-statement if the try-statement has + // a catch clause, and if the throw-statement occurs within the try block. + if (parent.kind === SyntaxKind.TryStatement) { + let tryStatement = parent; + + if (tryStatement.tryBlock === child && tryStatement.catchClause) { + return child; + } + } + + child = parent; + } + + return undefined; + } + + function aggregateAllBreakAndContinueStatements(node: Node): BreakOrContinueStatement[] { + let statementAccumulator: BreakOrContinueStatement[] = [] + aggregate(node); + return statementAccumulator; + + function aggregate(node: Node): void { + if (node.kind === SyntaxKind.BreakStatement || node.kind === SyntaxKind.ContinueStatement) { + statementAccumulator.push(node); + } + // Do not cross function boundaries. + else if (!isFunctionLike(node)) { + forEachChild(node, aggregate); + } + }; + } + + function ownsBreakOrContinueStatement(owner: Node, statement: BreakOrContinueStatement): boolean { + let actualOwner = getBreakOrContinueOwner(statement); + + return actualOwner && actualOwner === owner; + } + + function getBreakOrContinueOwner(statement: BreakOrContinueStatement): Node { + for (let node = statement.parent; node; node = node.parent) { + switch (node.kind) { + case SyntaxKind.SwitchStatement: + if (statement.kind === SyntaxKind.ContinueStatement) { + continue; + } + // Fall through. + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.DoStatement: + if (!statement.label || isLabeledBy(node, statement.label.text)) { + return node; + } + break; + default: + // Don't cross function boundaries. + if (isFunctionLike(node)) { + return undefined; + } + break; + } + } + + return undefined; + } + + function getModifierOccurrences(modifier: SyntaxKind, declaration: Node): HighlightSpan[] { + let container = declaration.parent; + + // Make sure we only highlight the keyword when it makes sense to do so. + if (isAccessibilityModifier(modifier)) { + if (!(container.kind === SyntaxKind.ClassDeclaration || + (declaration.kind === SyntaxKind.Parameter && hasKind(container, SyntaxKind.Constructor)))) { + return undefined; + } + } + else if (modifier === SyntaxKind.StaticKeyword) { + if (container.kind !== SyntaxKind.ClassDeclaration) { + return undefined; + } + } + else if (modifier === SyntaxKind.ExportKeyword || modifier === SyntaxKind.DeclareKeyword) { + if (!(container.kind === SyntaxKind.ModuleBlock || container.kind === SyntaxKind.SourceFile)) { + return undefined; + } + } + else { + // unsupported modifier + return undefined; + } + + let keywords: Node[] = []; + let modifierFlag: NodeFlags = getFlagFromModifier(modifier); + + let nodes: Node[]; + switch (container.kind) { + case SyntaxKind.ModuleBlock: + case SyntaxKind.SourceFile: + nodes = (container).statements; + break; + case SyntaxKind.Constructor: + nodes = ((container).parameters).concat( + (container.parent).members); + break; + case SyntaxKind.ClassDeclaration: + nodes = (container).members; + + // If we're an accessibility modifier, we're in an instance member and should search + // the constructor's parameter list for instance members as well. + if (modifierFlag & NodeFlags.AccessibilityModifier) { + let constructor = forEach((container).members, member => { + return member.kind === SyntaxKind.Constructor && member; + }); + + if (constructor) { + nodes = nodes.concat(constructor.parameters); + } + } + break; + default: + Debug.fail("Invalid container kind.") + } + + forEach(nodes, node => { + if (node.modifiers && node.flags & modifierFlag) { + forEach(node.modifiers, child => pushKeywordIf(keywords, child, modifier)); + } + }); + + return map(keywords, getHighlightSpanForNode); + + function getFlagFromModifier(modifier: SyntaxKind) { + switch (modifier) { + case SyntaxKind.PublicKeyword: + return NodeFlags.Public; + case SyntaxKind.PrivateKeyword: + return NodeFlags.Private; + case SyntaxKind.ProtectedKeyword: + return NodeFlags.Protected; + case SyntaxKind.StaticKeyword: + return NodeFlags.Static; + case SyntaxKind.ExportKeyword: + return NodeFlags.Export; + case SyntaxKind.DeclareKeyword: + return NodeFlags.Ambient; + default: + Debug.fail(); + } + } + } + + function pushKeywordIf(keywordList: Node[], token: Node, ...expected: SyntaxKind[]): boolean { + if (token && contains(expected, token.kind)) { + keywordList.push(token); + return true; + } + + return false; + } + + function getGetAndSetOccurrences(accessorDeclaration: AccessorDeclaration): HighlightSpan[] { + let keywords: Node[] = []; + + tryPushAccessorKeyword(accessorDeclaration.symbol, SyntaxKind.GetAccessor); + tryPushAccessorKeyword(accessorDeclaration.symbol, SyntaxKind.SetAccessor); + + return map(keywords, getHighlightSpanForNode); + + function tryPushAccessorKeyword(accessorSymbol: Symbol, accessorKind: SyntaxKind): void { + let accessor = getDeclarationOfKind(accessorSymbol, accessorKind); + + if (accessor) { + forEach(accessor.getChildren(), child => pushKeywordIf(keywords, child, SyntaxKind.GetKeyword, SyntaxKind.SetKeyword)); + } + } + } + + function getConstructorOccurrences(constructorDeclaration: ConstructorDeclaration): HighlightSpan[] { + let declarations = constructorDeclaration.symbol.getDeclarations() + + let keywords: Node[] = []; + + forEach(declarations, declaration => { + forEach(declaration.getChildren(), token => { + return pushKeywordIf(keywords, token, SyntaxKind.ConstructorKeyword); + }); + }); + + return map(keywords, getHighlightSpanForNode); + } + + function getLoopBreakContinueOccurrences(loopNode: IterationStatement): HighlightSpan[] { + let keywords: Node[] = []; + + if (pushKeywordIf(keywords, loopNode.getFirstToken(), SyntaxKind.ForKeyword, SyntaxKind.WhileKeyword, SyntaxKind.DoKeyword)) { + // If we succeeded and got a do-while loop, then start looking for a 'while' keyword. + if (loopNode.kind === SyntaxKind.DoStatement) { + let loopTokens = loopNode.getChildren(); + + for (let i = loopTokens.length - 1; i >= 0; i--) { + if (pushKeywordIf(keywords, loopTokens[i], SyntaxKind.WhileKeyword)) { + break; + } + } + } + } + + let breaksAndContinues = aggregateAllBreakAndContinueStatements(loopNode.statement); + + forEach(breaksAndContinues, statement => { + if (ownsBreakOrContinueStatement(loopNode, statement)) { + pushKeywordIf(keywords, statement.getFirstToken(), SyntaxKind.BreakKeyword, SyntaxKind.ContinueKeyword); + } + }); + + return map(keywords, getHighlightSpanForNode); + } + + function getBreakOrContinueStatementOccurences(breakOrContinueStatement: BreakOrContinueStatement): HighlightSpan[] { + let owner = getBreakOrContinueOwner(breakOrContinueStatement); + + if (owner) { + switch (owner.kind) { + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + return getLoopBreakContinueOccurrences(owner) + case SyntaxKind.SwitchStatement: + return getSwitchCaseDefaultOccurrences(owner); + + } + } + + return undefined; + } + + function getSwitchCaseDefaultOccurrences(switchStatement: SwitchStatement): HighlightSpan[] { + let keywords: Node[] = []; + + pushKeywordIf(keywords, switchStatement.getFirstToken(), SyntaxKind.SwitchKeyword); + + // Go through each clause in the switch statement, collecting the 'case'/'default' keywords. + forEach(switchStatement.caseBlock.clauses, clause => { + pushKeywordIf(keywords, clause.getFirstToken(), SyntaxKind.CaseKeyword, SyntaxKind.DefaultKeyword); + + let breaksAndContinues = aggregateAllBreakAndContinueStatements(clause); + + forEach(breaksAndContinues, statement => { + if (ownsBreakOrContinueStatement(switchStatement, statement)) { + pushKeywordIf(keywords, statement.getFirstToken(), SyntaxKind.BreakKeyword); + } + }); + }); + + return map(keywords, getHighlightSpanForNode); + } + + function getTryCatchFinallyOccurrences(tryStatement: TryStatement): HighlightSpan[] { + let keywords: Node[] = []; + + pushKeywordIf(keywords, tryStatement.getFirstToken(), SyntaxKind.TryKeyword); + + if (tryStatement.catchClause) { + pushKeywordIf(keywords, tryStatement.catchClause.getFirstToken(), SyntaxKind.CatchKeyword); + } + + if (tryStatement.finallyBlock) { + let finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile); + pushKeywordIf(keywords, finallyKeyword, SyntaxKind.FinallyKeyword); + } + + return map(keywords, getHighlightSpanForNode); + } + + function getThrowOccurrences(throwStatement: ThrowStatement): HighlightSpan[] { + let owner = getThrowStatementOwner(throwStatement); + + if (!owner) { + return undefined; + } + + let keywords: Node[] = []; + + forEach(aggregateOwnedThrowStatements(owner), throwStatement => { + pushKeywordIf(keywords, throwStatement.getFirstToken(), SyntaxKind.ThrowKeyword); + }); + + // If the "owner" is a function, then we equate 'return' and 'throw' statements in their + // ability to "jump out" of the function, and include occurrences for both. + if (isFunctionBlock(owner)) { + forEachReturnStatement(owner, returnStatement => { + pushKeywordIf(keywords, returnStatement.getFirstToken(), SyntaxKind.ReturnKeyword); + }); + } + + return map(keywords, getHighlightSpanForNode); + } + + function getReturnOccurrences(returnStatement: ReturnStatement): HighlightSpan[] { + let func = getContainingFunction(returnStatement); + + // If we didn't find a containing function with a block body, bail out. + if (!(func && hasKind(func.body, SyntaxKind.Block))) { + return undefined; + } + + let keywords: Node[] = [] + forEachReturnStatement(func.body, returnStatement => { + pushKeywordIf(keywords, returnStatement.getFirstToken(), SyntaxKind.ReturnKeyword); + }); + + // Include 'throw' statements that do not occur within a try block. + forEach(aggregateOwnedThrowStatements(func.body), throwStatement => { + pushKeywordIf(keywords, throwStatement.getFirstToken(), SyntaxKind.ThrowKeyword); + }); + + return map(keywords, getHighlightSpanForNode); + } + + function getIfElseOccurrences(ifStatement: IfStatement): HighlightSpan[] { + let keywords: Node[] = []; + + // Traverse upwards through all parent if-statements linked by their else-branches. + while (hasKind(ifStatement.parent, SyntaxKind.IfStatement) && (ifStatement.parent).elseStatement === ifStatement) { + ifStatement = ifStatement.parent; + } + + // Now traverse back down through the else branches, aggregating if/else keywords of if-statements. + while (ifStatement) { + let children = ifStatement.getChildren(); + pushKeywordIf(keywords, children[0], SyntaxKind.IfKeyword); + + // Generally the 'else' keyword is second-to-last, so we traverse backwards. + for (let i = children.length - 1; i >= 0; i--) { + if (pushKeywordIf(keywords, children[i], SyntaxKind.ElseKeyword)) { + break; + } + } + + if (!hasKind(ifStatement.elseStatement, SyntaxKind.IfStatement)) { + break + } + + ifStatement = ifStatement.elseStatement; + } + + let result: HighlightSpan[] = []; + + // We'd like to highlight else/ifs together if they are only separated by whitespace + // (i.e. the keywords are separated by no comments, no newlines). + for (let i = 0; i < keywords.length; i++) { + if (keywords[i].kind === SyntaxKind.ElseKeyword && i < keywords.length - 1) { + let elseKeyword = keywords[i]; + let ifKeyword = keywords[i + 1]; // this *should* always be an 'if' keyword. + + let shouldCombindElseAndIf = true; + + // Avoid recalculating getStart() by iterating backwards. + for (let j = ifKeyword.getStart() - 1; j >= elseKeyword.end; j--) { + if (!isWhiteSpace(sourceFile.text.charCodeAt(j))) { + shouldCombindElseAndIf = false; + break; + } + } + + if (shouldCombindElseAndIf) { + result.push({ + fileName: fileName, + textSpan: createTextSpanFromBounds(elseKeyword.getStart(), ifKeyword.end), + kind: HighlightSpanKind.reference + }); + i++; // skip the next keyword + continue; + } + } + + // Ordinary case: just highlight the keyword. + result.push(getHighlightSpanForNode(keywords[i])); + } + + return result; + } + } + } + + /// References and Occurrences + function getOccurrencesAtPositionCore(fileName: string, position: number): ReferenceEntry[] { + synchronizeHostData(); + + return convertDocumentHighlights(getDocumentHighlights(fileName, position, [fileName])); + + function convertDocumentHighlights(documentHighlights: DocumentHighlights[]): ReferenceEntry[] { + if (!documentHighlights) { + return undefined; + } + + let result: ReferenceEntry[] = []; + for (let entry of documentHighlights) { + for (let highlightSpan of entry.highlightSpans) { + result.push({ + fileName: entry.fileName, + textSpan: highlightSpan.textSpan, + isWriteAccess: highlightSpan.kind === HighlightSpanKind.writtenReference + }); + } + } + + return result; + } + } + + function convertReferences(referenceSymbols: ReferencedSymbol[]): ReferenceEntry[] { + if (!referenceSymbols) { + return undefined; + } + + let referenceEntries: ReferenceEntry[] = []; + + for (let referenceSymbol of referenceSymbols) { + addRange(referenceEntries, referenceSymbol.references); + } + + return referenceEntries; + } + + function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] { + var referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments); + return convertReferences(referencedSymbols); + } + + function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] { + var referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings:*/ false, /*findInComments:*/ false); + return convertReferences(referencedSymbols); + } + + function findReferences(fileName: string, position: number): ReferencedSymbol[]{ + var referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings:*/ false, /*findInComments:*/ false); + + // Only include referenced symbols that have a valid definition. + return filter(referencedSymbols, rs => !!rs.definition); + } + + function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] { + synchronizeHostData(); + + let sourceFile = getValidSourceFile(fileName); + + let node = getTouchingPropertyName(sourceFile, position); + if (!node) { + return undefined; + } + + if (node.kind !== SyntaxKind.Identifier && + // TODO (drosen): This should be enabled in a later release - currently breaks rename. + //node.kind !== SyntaxKind.ThisKeyword && + //node.kind !== SyntaxKind.SuperKeyword && + !isLiteralNameOfPropertyDeclarationOrIndexAccess(node) && + !isNameOfExternalModuleImportOrDeclaration(node)) { + return undefined; + } + + Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.NumericLiteral || node.kind === SyntaxKind.StringLiteral); + return getReferencedSymbolsForNodes(node, program.getSourceFiles(), findInStrings, findInComments); + } + + function getReferencedSymbolsForNodes(node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] { + let typeChecker = program.getTypeChecker(); + + // Labels + if (isLabelName(node)) { + if (isJumpStatementTarget(node)) { + let labelDefinition = getTargetLabel((node.parent), (node).text); + // if we have a label definition, look within its statement for references, if not, then + // the label is undefined and we have no results.. + return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : undefined; + } + else { + // it is a label definition and not a target, search within the parent labeledStatement + return getLabelReferencesInNode(node.parent, node); + } + } + + if (node.kind === SyntaxKind.ThisKeyword) { + return getReferencesForThisKeyword(node, sourceFiles); + } + + if (node.kind === SyntaxKind.SuperKeyword) { + return getReferencesForSuperKeyword(node); + } + + let symbol = typeChecker.getSymbolAtLocation(node); + + // Could not find a symbol e.g. unknown identifier + if (!symbol) { + // Can't have references to something that we have no symbol for. + return undefined; + } + + let declarations = symbol.declarations; + + // The symbol was an internal symbol and does not have a declaration e.g.undefined symbol + if (!declarations || !declarations.length) { + return undefined; + } + + let result: ReferencedSymbol[]; + + // Compute the meaning from the location and the symbol it references + let searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations); + + // Get the text to search for, we need to normalize it as external module names will have quote + let declaredName = getDeclaredName(symbol, node); + + // Try to get the smallest valid scope that we can limit our search to; + // otherwise we'll need to search globally (i.e. include each file). + let scope = getSymbolScope(symbol); + + // Maps from a symbol ID to the ReferencedSymbol entry in 'result'. + let symbolToIndex: number[] = []; + + if (scope) { + result = []; + getReferencesInNode(scope, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex); + } + else { + let internedName = getInternedName(symbol, node, declarations) + for (let sourceFile of sourceFiles) { + cancellationToken.throwIfCancellationRequested(); + + let nameTable = getNameTable(sourceFile); + + if (lookUp(nameTable, internedName)) { + result = result || []; + getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex); + } + } + } + + return result; + + function getDefinition(symbol: Symbol): DefinitionInfo { + let info = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, node.getSourceFile(), getContainerNode(node), node); + let name = map(info.displayParts, p => p.text).join(""); + let declarations = symbol.declarations; + if (!declarations || declarations.length === 0) { + return undefined; + } + + return { + containerKind: "", + containerName: "", + name, + kind: info.symbolKind, + fileName: declarations[0].getSourceFile().fileName, + textSpan: createTextSpan(declarations[0].getStart(), 0) + }; + } + + function isImportOrExportSpecifierName(location: Node): boolean { + return location.parent && + (location.parent.kind === SyntaxKind.ImportSpecifier || location.parent.kind === SyntaxKind.ExportSpecifier) && + (location.parent).propertyName === location; + } + + function isImportOrExportSpecifierImportSymbol(symbol: Symbol) { + return (symbol.flags & SymbolFlags.Alias) && forEach(symbol.declarations, declaration => { + return declaration.kind === SyntaxKind.ImportSpecifier || declaration.kind === SyntaxKind.ExportSpecifier; + }); + } + + function getDeclaredName(symbol: Symbol, location: Node) { + // Special case for function expressions, whose names are solely local to their bodies. + let functionExpression = forEach(symbol.declarations, d => d.kind === SyntaxKind.FunctionExpression ? d : undefined); + + // When a name gets interned into a SourceFile's 'identifiers' Map, + // its name is escaped and stored in the same way its symbol name/identifier + // name should be stored. Function expressions, however, are a special case, + // because despite sometimes having a name, the binder unconditionally binds them + // to a symbol with the name "__function". + let name: string; + if (functionExpression && functionExpression.name) { + name = functionExpression.name.text; + } + + // If this is an export or import specifier it could have been renamed using the as syntax. + // if so we want to search for whatever under the cursor, the symbol is pointing to the alias (name) + // so check for the propertyName. + if (isImportOrExportSpecifierName(location)) { + return location.getText(); + } + + name = typeChecker.symbolToString(symbol); + + return stripQuotes(name); + } + + function getInternedName(symbol: Symbol, location: Node, declarations: Declaration[]): string { + // If this is an export or import specifier it could have been renamed using the as syntax. + // if so we want to search for whatever under the cursor, the symbol is pointing to the alias (name) + // so check for the propertyName. + if (isImportOrExportSpecifierName(location)) { + return location.getText(); + } + + // Special case for function expressions, whose names are solely local to their bodies. + let functionExpression = forEach(declarations, d => d.kind === SyntaxKind.FunctionExpression ? d : undefined); + + // When a name gets interned into a SourceFile's 'identifiers' Map, + // its name is escaped and stored in the same way its symbol name/identifier + // name should be stored. Function expressions, however, are a special case, + // because despite sometimes having a name, the binder unconditionally binds them + // to a symbol with the name "__function". + let name = functionExpression && functionExpression.name + ? functionExpression.name.text + : symbol.name; + + return stripQuotes(name); + } + + function stripQuotes(name: string) { + let length = name.length; + if (length >= 2 && name.charCodeAt(0) === CharacterCodes.doubleQuote && name.charCodeAt(length - 1) === CharacterCodes.doubleQuote) { + return name.substring(1, length - 1); + }; + return name; + } + + function getSymbolScope(symbol: Symbol): Node { + // If this is private property or method, the scope is the containing class + if (symbol.flags & (SymbolFlags.Property | SymbolFlags.Method)) { + let privateDeclaration = forEach(symbol.getDeclarations(), d => (d.flags & NodeFlags.Private) ? d : undefined); + if (privateDeclaration) { + return getAncestor(privateDeclaration, SyntaxKind.ClassDeclaration); + } + } + + // If the symbol is an import we would like to find it if we are looking for what it imports. + // So consider it visibile outside its declaration scope. + if (symbol.flags & SymbolFlags.Alias) { + return undefined; + } + + // if this symbol is visible from its parent container, e.g. exported, then bail out + // if symbol correspond to the union property - bail out + if (symbol.parent || (symbol.flags & SymbolFlags.UnionProperty)) { + return undefined; + } + + let scope: Node = undefined; + + let declarations = symbol.getDeclarations(); + if (declarations) { + for (let declaration of declarations) { + let container = getContainerNode(declaration); + + if (!container) { + return undefined; + } + + if (scope && scope !== container) { + // Different declarations have different containers, bail out + return undefined; + } + + if (container.kind === SyntaxKind.SourceFile && !isExternalModule(container)) { + // This is a global variable and not an external module, any declaration defined + // within this scope is visible outside the file + return undefined; + } + + // The search scope is the container node + scope = container; + } + } + + return scope; + } + + function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, start: number, end: number): number[] { + let positions: number[] = []; + + /// TODO: Cache symbol existence for files to save text search + // Also, need to make this work for unicode escapes. + + // Be resilient in the face of a symbol with no name or zero length name + if (!symbolName || !symbolName.length) { + return positions; + } + + let text = sourceFile.text; + let sourceLength = text.length; + let symbolNameLength = symbolName.length; + + let position = text.indexOf(symbolName, start); + while (position >= 0) { + cancellationToken.throwIfCancellationRequested(); + + // If we are past the end, stop looking + if (position > end) break; + + // We found a match. Make sure it's not part of a larger word (i.e. the char + // before and after it have to be a non-identifier char). + let endPosition = position + symbolNameLength; + + if ((position === 0 || !isIdentifierPart(text.charCodeAt(position - 1), ScriptTarget.Latest)) && + (endPosition === sourceLength || !isIdentifierPart(text.charCodeAt(endPosition), ScriptTarget.Latest))) { + // Found a real match. Keep searching. + positions.push(position); + } + position = text.indexOf(symbolName, position + symbolNameLength + 1); + } + + return positions; + } + + function getLabelReferencesInNode(container: Node, targetLabel: Identifier): ReferencedSymbol[] { + let references: ReferenceEntry[] = []; + let sourceFile = container.getSourceFile(); + let labelName = targetLabel.text; + let possiblePositions = getPossibleSymbolReferencePositions(sourceFile, labelName, container.getStart(), container.getEnd()); + forEach(possiblePositions, position => { + cancellationToken.throwIfCancellationRequested(); + + let node = getTouchingWord(sourceFile, position); + if (!node || node.getWidth() !== labelName.length) { + return; + } + + // Only pick labels that are either the target label, or have a target that is the target label + if (node === targetLabel || + (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel)) { + references.push(getReferenceEntryFromNode(node)); + } + }); + + var definition: DefinitionInfo = { + containerKind: "", + containerName: "", + fileName: targetLabel.getSourceFile().fileName, + kind: ScriptElementKind.label, + name: labelName, + textSpan: createTextSpanFromBounds(targetLabel.getStart(), targetLabel.getEnd()) + } + + return [{ definition, references }]; + } + + function isValidReferencePosition(node: Node, searchSymbolName: string): boolean { + if (node) { + // Compare the length so we filter out strict superstrings of the symbol we are looking for + switch (node.kind) { + case SyntaxKind.Identifier: + return node.getWidth() === searchSymbolName.length; + + case SyntaxKind.StringLiteral: + if (isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || + isNameOfExternalModuleImportOrDeclaration(node)) { + // For string literals we have two additional chars for the quotes + return node.getWidth() === searchSymbolName.length + 2; + } + break; + + case SyntaxKind.NumericLiteral: + if (isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) { + return node.getWidth() === searchSymbolName.length; + } + break; + } + } + + return false; + } + + /** Search within node "container" for references for a search value, where the search value is defined as a + * tuple of(searchSymbol, searchText, searchLocation, and searchMeaning). + * searchLocation: a node where the search value + */ + function getReferencesInNode(container: Node, + searchSymbol: Symbol, + searchText: string, + searchLocation: Node, + searchMeaning: SemanticMeaning, + findInStrings: boolean, + findInComments: boolean, + result: ReferencedSymbol[], + symbolToIndex: number[]): void { + + let sourceFile = container.getSourceFile(); + let tripleSlashDirectivePrefixRegex = /^\/\/\/\s* { + cancellationToken.throwIfCancellationRequested(); + + let referenceLocation = getTouchingPropertyName(sourceFile, position); + if (!isValidReferencePosition(referenceLocation, searchText)) { + // This wasn't the start of a token. Check to see if it might be a + // match in a comment or string if that's what the caller is asking + // for. + if ((findInStrings && isInString(position)) || + (findInComments && isInComment(position))) { + + // In the case where we're looking inside comments/strings, we don't have + // an actual definition. So just use 'undefined' here. Features like + // 'Rename' won't care (as they ignore the definitions), and features like + // 'FindReferences' will just filter out these results. + result.push({ + definition: undefined, + references: [{ + fileName: sourceFile.fileName, + textSpan: createTextSpan(position, searchText.length), + isWriteAccess: false + }] + }); + } + return; + } + + if (!(getMeaningFromLocation(referenceLocation) & searchMeaning)) { + return; + } + + let referenceSymbol = typeChecker.getSymbolAtLocation(referenceLocation); + if (referenceSymbol) { + let referenceSymbolDeclaration = referenceSymbol.valueDeclaration; + let shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration); + var relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation); + + if (relatedSymbol) { + var referencedSymbol = getReferencedSymbol(relatedSymbol); + referencedSymbol.references.push(getReferenceEntryFromNode(referenceLocation)); + } + /* Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment + * has two meaning : property name and property value. Therefore when we do findAllReference at the position where + * an identifier is declared, the language service should return the position of the variable declaration as well as + * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the + * position of property accessing, the referenceEntry of such position will be handled in the first case. + */ + else if (!(referenceSymbol.flags & SymbolFlags.Transient) && searchSymbols.indexOf(shorthandValueSymbol) >= 0) { + var referencedSymbol = getReferencedSymbol(shorthandValueSymbol); + referencedSymbol.references.push(getReferenceEntryFromNode(referenceSymbolDeclaration.name)); + } + } + }); + } + + return; + + function getReferencedSymbol(symbol: Symbol): ReferencedSymbol { + var symbolId = getSymbolId(symbol); + var index = symbolToIndex[symbolId]; + if (index === undefined) { + index = result.length; + symbolToIndex[symbolId] = index; + + result.push({ + definition: getDefinition(symbol), + references: [] + }); + } + + return result[index]; + } + + function isInString(position: number) { + let token = getTokenAtPosition(sourceFile, position); + return token && token.kind === SyntaxKind.StringLiteral && position > token.getStart(); + } + + function isInComment(position: number) { + let token = getTokenAtPosition(sourceFile, position); + if (token && position < token.getStart()) { + // First, we have to see if this position actually landed in a comment. + let commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos); + + // Then we want to make sure that it wasn't in a "///<" directive comment + // We don't want to unintentionally update a file name. + return forEach(commentRanges, c => { + if (c.pos < position && position < c.end) { + let commentText = sourceFile.text.substring(c.pos, c.end); + if (!tripleSlashDirectivePrefixRegex.test(commentText)) { + return true; + } + } + }); + } + + return false; + } + } + + function getReferencesForSuperKeyword(superKeyword: Node): ReferencedSymbol[] { + let searchSpaceNode = getSuperContainer(superKeyword, /*includeFunctions*/ false); + if (!searchSpaceNode) { + return undefined; + } + // Whether 'super' occurs in a static context within a class. + let staticFlag = NodeFlags.Static; + + switch (searchSpaceNode.kind) { + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + staticFlag &= searchSpaceNode.flags; + searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class + break; + default: + return undefined; + } + + let references: ReferenceEntry[] = []; + + let sourceFile = searchSpaceNode.getSourceFile(); + let possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "super", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); + forEach(possiblePositions, position => { + cancellationToken.throwIfCancellationRequested(); + + let node = getTouchingWord(sourceFile, position); + + if (!node || node.kind !== SyntaxKind.SuperKeyword) { + return; + } + + let container = getSuperContainer(node, /*includeFunctions*/ false); + + // If we have a 'super' container, we must have an enclosing class. + // Now make sure the owning class is the same as the search-space + // and has the same static qualifier as the original 'super's owner. + if (container && (NodeFlags.Static & container.flags) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) { + references.push(getReferenceEntryFromNode(node)); + } + }); + + var definition = getDefinition(searchSpaceNode.symbol); + return [{ definition, references }]; + } + + function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: SourceFile[]): ReferencedSymbol[] { + let searchSpaceNode = getThisContainer(thisOrSuperKeyword, /* includeArrowFunctions */ false); + + // Whether 'this' occurs in a static context within a class. + let staticFlag = NodeFlags.Static; + + switch (searchSpaceNode.kind) { + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + if (isObjectLiteralMethod(searchSpaceNode)) { + break; + } + // fall through + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + staticFlag &= searchSpaceNode.flags + searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class + break; + case SyntaxKind.SourceFile: + if (isExternalModule(searchSpaceNode)) { + return undefined; + } + // Fall through + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + break; + // Computed properties in classes are not handled here because references to this are illegal, + // so there is no point finding references to them. + default: + return undefined; + } + + let references: ReferenceEntry[] = []; + + let possiblePositions: number[]; + if (searchSpaceNode.kind === SyntaxKind.SourceFile) { + forEach(sourceFiles, sourceFile => { + possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", sourceFile.getStart(), sourceFile.getEnd()); + getThisReferencesInFile(sourceFile, sourceFile, possiblePositions, references); + }); + } + else { + let sourceFile = searchSpaceNode.getSourceFile(); + possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); + getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, references); + } + + return [{ + definition: { + containerKind: "", + containerName: "", + fileName: node.getSourceFile().fileName, + kind: ScriptElementKind.variableElement, + name: "this", + textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()) + }, + references: references + }]; + + function getThisReferencesInFile(sourceFile: SourceFile, searchSpaceNode: Node, possiblePositions: number[], result: ReferenceEntry[]): void { + forEach(possiblePositions, position => { + cancellationToken.throwIfCancellationRequested(); + + let node = getTouchingWord(sourceFile, position); + if (!node || node.kind !== SyntaxKind.ThisKeyword) { + return; + } + + let container = getThisContainer(node, /* includeArrowFunctions */ false); + + switch (searchSpaceNode.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + if (searchSpaceNode.symbol === container.symbol) { + result.push(getReferenceEntryFromNode(node)); + } + break; + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + if (isObjectLiteralMethod(searchSpaceNode) && searchSpaceNode.symbol === container.symbol) { + result.push(getReferenceEntryFromNode(node)); + } + break; + case SyntaxKind.ClassDeclaration: + // Make sure the container belongs to the same class + // and has the appropriate static modifier from the original container. + if (container.parent && searchSpaceNode.symbol === container.parent.symbol && (container.flags & NodeFlags.Static) === staticFlag) { + result.push(getReferenceEntryFromNode(node)); + } + break; + case SyntaxKind.SourceFile: + if (container.kind === SyntaxKind.SourceFile && !isExternalModule(container)) { + result.push(getReferenceEntryFromNode(node)); + } + break; + } + }); + } + } + + function populateSearchSymbolSet(symbol: Symbol, location: Node): Symbol[] { + // The search set contains at least the current symbol + let result = [symbol]; + + // If the symbol is an alias, add what it alaises to the list + if (isImportOrExportSpecifierImportSymbol(symbol)) { + result.push(typeChecker.getAliasedSymbol(symbol)); + } + + // If the location is in a context sensitive location (i.e. in an object literal) try + // to get a contextual type for it, and add the property symbol from the contextual + // type to the search set + if (isNameOfPropertyAssignment(location)) { + forEach(getPropertySymbolsFromContextualType(location), contextualSymbol => { + result.push.apply(result, typeChecker.getRootSymbols(contextualSymbol)); + }); + + /* Because in short-hand property assignment, location has two meaning : property name and as value of the property + * When we do findAllReference at the position of the short-hand property assignment, we would want to have references to position of + * property name and variable declaration of the identifier. + * Like in below example, when querying for all references for an identifier 'name', of the property assignment, the language service + * should show both 'name' in 'obj' and 'name' in variable declaration + * let name = "Foo"; + * let obj = { name }; + * In order to do that, we will populate the search set with the value symbol of the identifier as a value of the property assignment + * so that when matching with potential reference symbol, both symbols from property declaration and variable declaration + * will be included correctly. + */ + let shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(location.parent); + if (shorthandValueSymbol) { + result.push(shorthandValueSymbol); + } + } + + // If this is a union property, add all the symbols from all its source symbols in all unioned types. + // If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list + forEach(typeChecker.getRootSymbols(symbol), rootSymbol => { + if (rootSymbol !== symbol) { + result.push(rootSymbol); + } + + // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions + if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result); + } + }); + + return result; + } + + function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, result: Symbol[]): void { + if (symbol && symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { + forEach(symbol.getDeclarations(), declaration => { + if (declaration.kind === SyntaxKind.ClassDeclaration) { + getPropertySymbolFromTypeReference(getClassExtendsHeritageClauseElement(declaration)); + forEach(getClassImplementsHeritageClauseElements(declaration), getPropertySymbolFromTypeReference); + } + else if (declaration.kind === SyntaxKind.InterfaceDeclaration) { + forEach(getInterfaceBaseTypeNodes(declaration), getPropertySymbolFromTypeReference); + } + }); + } + return; + + function getPropertySymbolFromTypeReference(typeReference: HeritageClauseElement) { + if (typeReference) { + let type = typeChecker.getTypeAtLocation(typeReference); + if (type) { + let propertySymbol = typeChecker.getPropertyOfType(type, propertyName); + if (propertySymbol) { + result.push(propertySymbol); + } + + // Visit the typeReference as well to see if it directly or indirectly use that property + getPropertySymbolsFromBaseTypes(type.symbol, propertyName, result); + } + } + } + } + + function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node): Symbol { + if (searchSymbols.indexOf(referenceSymbol) >= 0) { + return referenceSymbol; + } + + // If the reference symbol is an alias, check if what it is aliasing is one of the search + // symbols. + if (isImportOrExportSpecifierImportSymbol(referenceSymbol)) { + var aliasedSymbol = typeChecker.getAliasedSymbol(referenceSymbol); + if (searchSymbols.indexOf(aliasedSymbol) >= 0) { + return aliasedSymbol; + } + } + + // If the reference location is in an object literal, try to get the contextual type for the + // object literal, lookup the property symbol in the contextual type, and use this symbol to + // compare to our searchSymbol + if (isNameOfPropertyAssignment(referenceLocation)) { + return forEach(getPropertySymbolsFromContextualType(referenceLocation), contextualSymbol => { + return forEach(typeChecker.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined); + }); + } + + // Unwrap symbols to get to the root (e.g. transient symbols as a result of widening) + // Or a union property, use its underlying unioned symbols + return forEach(typeChecker.getRootSymbols(referenceSymbol), rootSymbol => { + // if it is in the list, then we are done + if (searchSymbols.indexOf(rootSymbol) >= 0) { + return rootSymbol; + } + + // Finally, try all properties with the same name in any type the containing type extended or implemented, and + // see if any is in the list + if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { + let result: Symbol[] = []; + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result); + return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined); + } + + return undefined; + }); + } + + function getPropertySymbolsFromContextualType(node: Node): Symbol[] { + if (isNameOfPropertyAssignment(node)) { + let objectLiteral = node.parent.parent; + let contextualType = typeChecker.getContextualType(objectLiteral); + let name = (node).text; + if (contextualType) { + if (contextualType.flags & TypeFlags.Union) { + // This is a union type, first see if the property we are looking for is a union property (i.e. exists in all types) + // if not, search the constituent types for the property + let unionProperty = contextualType.getProperty(name) + if (unionProperty) { + return [unionProperty]; + } + else { + let result: Symbol[] = []; + forEach((contextualType).types, t => { + let symbol = t.getProperty(name); + if (symbol) { + result.push(symbol); + } + }); + return result; + } + } + else { + let symbol = contextualType.getProperty(name); + if (symbol) { + return [symbol]; + } + } + } + } + return undefined; + } + + /** Given an initial searchMeaning, extracted from a location, widen the search scope based on the declarations + * of the corresponding symbol. e.g. if we are searching for "Foo" in value position, but "Foo" references a class + * then we need to widen the search to include type positions as well. + * On the contrary, if we are searching for "Bar" in type position and we trace bar to an interface, and an uninstantiated + * module, we want to keep the search limited to only types, as the two declarations (interface and uninstantiated module) + * do not intersect in any of the three spaces. + */ + function getIntersectingMeaningFromDeclarations(meaning: SemanticMeaning, declarations: Declaration[]): SemanticMeaning { + if (declarations) { + let lastIterationMeaning: SemanticMeaning; + do { + // The result is order-sensitive, for instance if initialMeaning === Namespace, and declarations = [class, instantiated module] + // we need to consider both as they initialMeaning intersects with the module in the namespace space, and the module + // intersects with the class in the value space. + // To achieve that we will keep iterating until the result stabilizes. + + // Remember the last meaning + lastIterationMeaning = meaning; + + for (let declaration of declarations) { + let declarationMeaning = getMeaningFromDeclaration(declaration); + + if (declarationMeaning & meaning) { + meaning |= declarationMeaning; + } + } + } + while (meaning !== lastIterationMeaning); + } + return meaning; + } + } + + function getReferenceEntryFromNode(node: Node): ReferenceEntry { + let start = node.getStart(); + let end = node.getEnd(); + + if (node.kind === SyntaxKind.StringLiteral) { + start += 1; + end -= 1; + } + + return { + fileName: node.getSourceFile().fileName, + textSpan: createTextSpanFromBounds(start, end), + isWriteAccess: isWriteAccess(node) + }; + } + + /** A node is considered a writeAccess iff it is a name of a declaration or a target of an assignment */ + function isWriteAccess(node: Node): boolean { + if (node.kind === SyntaxKind.Identifier && isDeclarationName(node)) { + return true; + } + + let parent = node.parent; + if (parent) { + if (parent.kind === SyntaxKind.PostfixUnaryExpression || parent.kind === SyntaxKind.PrefixUnaryExpression) { + return true; + } + else if (parent.kind === SyntaxKind.BinaryExpression && (parent).left === node) { + let operator = (parent).operatorToken.kind; + return SyntaxKind.FirstAssignment <= operator && operator <= SyntaxKind.LastAssignment; + } + } + + return false; + } + + /// NavigateTo + function getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[] { + synchronizeHostData(); + + return ts.NavigateTo.getNavigateToItems(program, cancellationToken, searchValue, maxResultCount); + } + + function containErrors(diagnostics: Diagnostic[]): boolean { + return forEach(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error); + } + + function getEmitOutput(fileName: string): EmitOutput { + synchronizeHostData(); + + let sourceFile = getValidSourceFile(fileName); + let outputFiles: OutputFile[] = []; + + function writeFile(fileName: string, data: string, writeByteOrderMark: boolean) { + outputFiles.push({ + name: fileName, + writeByteOrderMark: writeByteOrderMark, + text: data + }); + } + + let emitOutput = program.emit(sourceFile, writeFile); + + return { + outputFiles, + emitSkipped: emitOutput.emitSkipped + }; + } + + function getMeaningFromDeclaration(node: Node): SemanticMeaning { + switch (node.kind) { + case SyntaxKind.Parameter: + case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.EnumMember: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.CatchClause: + return SemanticMeaning.Value; + + case SyntaxKind.TypeParameter: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.TypeLiteral: + return SemanticMeaning.Type; + + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + return SemanticMeaning.Value | SemanticMeaning.Type; + + case SyntaxKind.ModuleDeclaration: + if ((node).name.kind === SyntaxKind.StringLiteral) { + return SemanticMeaning.Namespace | SemanticMeaning.Value; + } + else if (getModuleInstanceState(node) === ModuleInstanceState.Instantiated) { + return SemanticMeaning.Namespace | SemanticMeaning.Value; + } + else { + return SemanticMeaning.Namespace; + } + + case SyntaxKind.NamedImports: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ExportAssignment: + case SyntaxKind.ExportDeclaration: + return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace; + + // An external module can be a Value + case SyntaxKind.SourceFile: + return SemanticMeaning.Namespace | SemanticMeaning.Value; + } + + return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace; + + Debug.fail("Unknown declaration type"); + } + + function isTypeReference(node: Node): boolean { + if (isRightSideOfQualifiedNameOrPropertyAccess(node) ) { + node = node.parent; + } + + return node.parent.kind === SyntaxKind.TypeReference || node.parent.kind === SyntaxKind.HeritageClauseElement; + } + + function isNamespaceReference(node: Node): boolean { + return isQualifiedNameNamespaceReference(node) || isPropertyAccessNamespaceReference(node); + } + + function isPropertyAccessNamespaceReference(node: Node): boolean { + let root = node; + let isLastClause = true; + if (root.parent.kind === SyntaxKind.PropertyAccessExpression) { + while (root.parent && root.parent.kind === SyntaxKind.PropertyAccessExpression) { + root = root.parent; + } + + isLastClause = (root).name === node; + } + + if (!isLastClause && root.parent.kind === SyntaxKind.HeritageClauseElement && root.parent.parent.kind === SyntaxKind.HeritageClause) { + let decl = root.parent.parent.parent; + return (decl.kind === SyntaxKind.ClassDeclaration && (root.parent.parent).token === SyntaxKind.ImplementsKeyword) || + (decl.kind === SyntaxKind.InterfaceDeclaration && (root.parent.parent).token === SyntaxKind.ExtendsKeyword); + } + + return false; + } + + function isQualifiedNameNamespaceReference(node: Node): boolean { + let root = node; + let isLastClause = true; + if (root.parent.kind === SyntaxKind.QualifiedName) { + while (root.parent && root.parent.kind === SyntaxKind.QualifiedName) { + root = root.parent; + } + + isLastClause = (root).right === node; + } + + return root.parent.kind === SyntaxKind.TypeReference && !isLastClause; + } + + function isInRightSideOfImport(node: Node) { + while (node.parent.kind === SyntaxKind.QualifiedName) { + node = node.parent; + } + return isInternalModuleImportEqualsDeclaration(node.parent) && (node.parent).moduleReference === node; + } + + function getMeaningFromRightHandSideOfImportEquals(node: Node) { + Debug.assert(node.kind === SyntaxKind.Identifier); + + // import a = |b|; // Namespace + // import a = |b.c|; // Value, type, namespace + // import a = |b.c|.d; // Namespace + + if (node.parent.kind === SyntaxKind.QualifiedName && + (node.parent).right === node && + node.parent.parent.kind === SyntaxKind.ImportEqualsDeclaration) { + return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace; + } + return SemanticMeaning.Namespace; + } + + function getMeaningFromLocation(node: Node): SemanticMeaning { + if (node.parent.kind === SyntaxKind.ExportAssignment) { + return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace; + } + else if (isInRightSideOfImport(node)) { + return getMeaningFromRightHandSideOfImportEquals(node); + } + else if (isDeclarationName(node)) { + return getMeaningFromDeclaration(node.parent); + } + else if (isTypeReference(node)) { + return SemanticMeaning.Type; + } + else if (isNamespaceReference(node)) { + return SemanticMeaning.Namespace; + } + else { + return SemanticMeaning.Value; + } + } + + // Signature help + /** + * This is a semantic operation. + */ + function getSignatureHelpItems(fileName: string, position: number): SignatureHelpItems { + synchronizeHostData(); + + let sourceFile = getValidSourceFile(fileName); + + return SignatureHelp.getSignatureHelpItems(program, sourceFile, position, cancellationToken); + } + + /// Syntactic features + function getSourceFile(fileName: string): SourceFile { + return syntaxTreeCache.getCurrentSourceFile(fileName); + } + + function getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan { + let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + + // Get node at the location + let node = getTouchingPropertyName(sourceFile, startPos); + + if (!node) { + return; + } + + switch (node.kind) { + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.QualifiedName: + case SyntaxKind.StringLiteral: + case SyntaxKind.FalseKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.SuperKeyword: + case SyntaxKind.ThisKeyword: + case SyntaxKind.Identifier: + break; + + // Cant create the text span + default: + return; + } + + let nodeForStartPos = node; + while (true) { + if (isRightSideOfPropertyAccess(nodeForStartPos) || isRightSideOfQualifiedName(nodeForStartPos)) { + // If on the span is in right side of the the property or qualified name, return the span from the qualified name pos to end of this node + nodeForStartPos = nodeForStartPos.parent; + } + else if (isNameOfModuleDeclaration(nodeForStartPos)) { + // If this is name of a module declarations, check if this is right side of dotted module name + // If parent of the module declaration which is parent of this node is module declaration and its body is the module declaration that this node is name of + // Then this name is name from dotted module + if (nodeForStartPos.parent.parent.kind === SyntaxKind.ModuleDeclaration && + (nodeForStartPos.parent.parent).body === nodeForStartPos.parent) { + // Use parent module declarations name for start pos + nodeForStartPos = (nodeForStartPos.parent.parent).name; + } + else { + // We have to use this name for start pos + break; + } + } + else { + // Is not a member expression so we have found the node for start pos + break; + } + } + + return createTextSpanFromBounds(nodeForStartPos.getStart(), node.getEnd()); + } + + function getBreakpointStatementAtPosition(fileName: string, position: number) { + // doesn't use compiler - no need to synchronize with host + let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + + return BreakpointResolver.spanInSourceFileAtLocation(sourceFile, position); + } + + function getNavigationBarItems(fileName: string): NavigationBarItem[]{ + let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + + return NavigationBar.getNavigationBarItems(sourceFile); + } + + function getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] { + synchronizeHostData(); + + let sourceFile = getValidSourceFile(fileName); + let typeChecker = program.getTypeChecker(); + + let result: ClassifiedSpan[] = []; + processNode(sourceFile); + + return result; + + function classifySymbol(symbol: Symbol, meaningAtPosition: SemanticMeaning) { + let flags = symbol.getFlags(); + + if (flags & SymbolFlags.Class) { + return ClassificationTypeNames.className; + } + else if (flags & SymbolFlags.Enum) { + return ClassificationTypeNames.enumName; + } + else if (flags & SymbolFlags.TypeAlias) { + return ClassificationTypeNames.typeAlias; + } + else if (meaningAtPosition & SemanticMeaning.Type) { + if (flags & SymbolFlags.Interface) { + return ClassificationTypeNames.interfaceName; + } + else if (flags & SymbolFlags.TypeParameter) { + return ClassificationTypeNames.typeParameterName; + } + } + else if (flags & SymbolFlags.Module) { + // Only classify a module as such if + // - It appears in a namespace context. + // - There exists a module declaration which actually impacts the value side. + if (meaningAtPosition & SemanticMeaning.Namespace || + (meaningAtPosition & SemanticMeaning.Value && hasValueSideModule(symbol))) { + return ClassificationTypeNames.moduleName; + } + } + + return undefined; + + /** + * Returns true if there exists a module that introduces entities on the value side. + */ + function hasValueSideModule(symbol: Symbol): boolean { + return forEach(symbol.declarations, declaration => { + return declaration.kind === SyntaxKind.ModuleDeclaration && getModuleInstanceState(declaration) == ModuleInstanceState.Instantiated; + }); + } + } + + function processNode(node: Node) { + // Only walk into nodes that intersect the requested span. + if (node && textSpanIntersectsWith(span, node.getStart(), node.getWidth())) { + if (node.kind === SyntaxKind.Identifier && node.getWidth() > 0) { + let symbol = typeChecker.getSymbolAtLocation(node); + if (symbol) { + let type = classifySymbol(symbol, getMeaningFromLocation(node)); + if (type) { + result.push({ + textSpan: createTextSpan(node.getStart(), node.getWidth()), + classificationType: type + }); + } + } + } + + forEachChild(node, processNode); + } + } + } + + function getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] { + // doesn't use compiler - no need to synchronize with host + let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + + // Make a scanner we can get trivia from. + let triviaScanner = createScanner(ScriptTarget.Latest, /*skipTrivia:*/ false, sourceFile.text); + let mergeConflictScanner = createScanner(ScriptTarget.Latest, /*skipTrivia:*/ false, sourceFile.text); + + let result: ClassifiedSpan[] = []; + processElement(sourceFile); + + return result; + + function classifyLeadingTrivia(token: Node): void { + let tokenStart = skipTrivia(sourceFile.text, token.pos, /*stopAfterLineBreak:*/ false); + if (tokenStart === token.pos) { + return; + } + + // token has trivia. Classify them appropriately. + triviaScanner.setTextPos(token.pos); + while (true) { + let start = triviaScanner.getTextPos(); + let kind = triviaScanner.scan(); + let end = triviaScanner.getTextPos(); + let width = end - start; + + if (textSpanIntersectsWith(span, start, width)) { + if (!isTrivia(kind)) { + return; + } + + if (isComment(kind)) { + // Simple comment. Just add as is. + result.push({ + textSpan: createTextSpan(start, width), + classificationType: ClassificationTypeNames.comment + }) + continue; + } + + if (kind === SyntaxKind.ConflictMarkerTrivia) { + let text = sourceFile.text; + let ch = text.charCodeAt(start); + + // for the <<<<<<< and >>>>>>> markers, we just add them in as comments + // in the classification stream. + if (ch === CharacterCodes.lessThan || ch === CharacterCodes.greaterThan) { + result.push({ + textSpan: createTextSpan(start, width), + classificationType: ClassificationTypeNames.comment + }); + continue; + } + + // for the ======== add a comment for the first line, and then lex all + // subsequent lines up until the end of the conflict marker. + Debug.assert(ch === CharacterCodes.equals); + classifyDisabledMergeCode(text, start, end); + } + } + } + } + + function classifyDisabledMergeCode(text: string, start: number, end: number) { + // Classify the line that the ======= marker is on as a comment. Then just lex + // all further tokens and add them to the result. + for (var i = start; i < end; i++) { + if (isLineBreak(text.charCodeAt(i))) { + break; + } + } + result.push({ + textSpan: createTextSpanFromBounds(start, i), + classificationType: ClassificationTypeNames.comment + }); + + mergeConflictScanner.setTextPos(i); + + while (mergeConflictScanner.getTextPos() < end) { + classifyDisabledCodeToken(); + } + } + + function classifyDisabledCodeToken() { + let start = mergeConflictScanner.getTextPos(); + let tokenKind = mergeConflictScanner.scan(); + let end = mergeConflictScanner.getTextPos(); + + let type = classifyTokenType(tokenKind); + if (type) { + result.push({ + textSpan: createTextSpanFromBounds(start, end), + classificationType: type + }); + } + } + + function classifyToken(token: Node): void { + classifyLeadingTrivia(token); + + if (token.getWidth() > 0) { + let type = classifyTokenType(token.kind, token); + if (type) { + result.push({ + textSpan: createTextSpan(token.getStart(), token.getWidth()), + classificationType: type + }); + } + } + } + + // for accurate classification, the actual token should be passed in. however, for + // cases like 'disabled merge code' classification, we just get the token kind and + // classify based on that instead. + function classifyTokenType(tokenKind: SyntaxKind, token?: Node): string { + if (isKeyword(tokenKind)) { + return ClassificationTypeNames.keyword; + } + + // Special case < and > If they appear in a generic context they are punctuation, + // not operators. + if (tokenKind === SyntaxKind.LessThanToken || tokenKind === SyntaxKind.GreaterThanToken) { + // If the node owning the token has a type argument list or type parameter list, then + // we can effectively assume that a '<' and '>' belong to those lists. + if (token && getTypeArgumentOrTypeParameterList(token.parent)) { + return ClassificationTypeNames.punctuation; + } + } + + if (isPunctuation(tokenKind)) { + if (token) { + if (tokenKind === SyntaxKind.EqualsToken) { + // the '=' in a variable declaration is special cased here. + if (token.parent.kind === SyntaxKind.VariableDeclaration || + token.parent.kind === SyntaxKind.PropertyDeclaration || + token.parent.kind === SyntaxKind.Parameter) { + return ClassificationTypeNames.operator; + } + } + + if (token.parent.kind === SyntaxKind.BinaryExpression || + token.parent.kind === SyntaxKind.PrefixUnaryExpression || + token.parent.kind === SyntaxKind.PostfixUnaryExpression || + token.parent.kind === SyntaxKind.ConditionalExpression) { + return ClassificationTypeNames.operator; + } + } + + return ClassificationTypeNames.punctuation; + } + else if (tokenKind === SyntaxKind.NumericLiteral) { + return ClassificationTypeNames.numericLiteral; + } + else if (tokenKind === SyntaxKind.StringLiteral) { + return ClassificationTypeNames.stringLiteral; + } + else if (tokenKind === SyntaxKind.RegularExpressionLiteral) { + // TODO: we should get another classification type for these literals. + return ClassificationTypeNames.stringLiteral; + } + else if (isTemplateLiteralKind(tokenKind)) { + // TODO (drosen): we should *also* get another classification type for these literals. + return ClassificationTypeNames.stringLiteral; + } + else if (tokenKind === SyntaxKind.Identifier) { + if (token) { + switch (token.parent.kind) { + case SyntaxKind.ClassDeclaration: + if ((token.parent).name === token) { + return ClassificationTypeNames.className; + } + return; + case SyntaxKind.TypeParameter: + if ((token.parent).name === token) { + return ClassificationTypeNames.typeParameterName; + } + return; + case SyntaxKind.InterfaceDeclaration: + if ((token.parent).name === token) { + return ClassificationTypeNames.interfaceName; + } + return; + case SyntaxKind.EnumDeclaration: + if ((token.parent).name === token) { + return ClassificationTypeNames.enumName; + } + return; + case SyntaxKind.ModuleDeclaration: + if ((token.parent).name === token) { + return ClassificationTypeNames.moduleName; + } + return; + } + } + + return ClassificationTypeNames.text; + } + } + + function processElement(element: Node) { + // Ignore nodes that don't intersect the original span to classify. + if (textSpanIntersectsWith(span, element.getFullStart(), element.getFullWidth())) { + let children = element.getChildren(); + for (let child of children) { + if (isToken(child)) { + classifyToken(child); + } + else { + // Recurse into our child nodes. + processElement(child); + } + } + } + } + } + + function getOutliningSpans(fileName: string): OutliningSpan[] { + // doesn't use compiler - no need to synchronize with host + let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + return OutliningElementsCollector.collectElements(sourceFile); + } + + function getBraceMatchingAtPosition(fileName: string, position: number) { + let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + let result: TextSpan[] = []; + + let token = getTouchingToken(sourceFile, position); + + if (token.getStart(sourceFile) === position) { + let matchKind = getMatchingTokenKind(token); + + // Ensure that there is a corresponding token to match ours. + if (matchKind) { + let parentElement = token.parent; + + let childNodes = parentElement.getChildren(sourceFile); + for (let current of childNodes) { + if (current.kind === matchKind) { + let range1 = createTextSpan(token.getStart(sourceFile), token.getWidth(sourceFile)); + let range2 = createTextSpan(current.getStart(sourceFile), current.getWidth(sourceFile)); + + // We want to order the braces when we return the result. + if (range1.start < range2.start) { + result.push(range1, range2); + } + else { + result.push(range2, range1); + } + + break; + } + } + } + } + + return result; + + function getMatchingTokenKind(token: Node): ts.SyntaxKind { + switch (token.kind) { + case ts.SyntaxKind.OpenBraceToken: return ts.SyntaxKind.CloseBraceToken + case ts.SyntaxKind.OpenParenToken: return ts.SyntaxKind.CloseParenToken; + case ts.SyntaxKind.OpenBracketToken: return ts.SyntaxKind.CloseBracketToken; + case ts.SyntaxKind.LessThanToken: return ts.SyntaxKind.GreaterThanToken; + case ts.SyntaxKind.CloseBraceToken: return ts.SyntaxKind.OpenBraceToken + case ts.SyntaxKind.CloseParenToken: return ts.SyntaxKind.OpenParenToken; + case ts.SyntaxKind.CloseBracketToken: return ts.SyntaxKind.OpenBracketToken; + case ts.SyntaxKind.GreaterThanToken: return ts.SyntaxKind.LessThanToken; + } + + return undefined; + } + } + + function getIndentationAtPosition(fileName: string, position: number, editorOptions: EditorOptions) { + let start = new Date().getTime(); + let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + log("getIndentationAtPosition: getCurrentSourceFile: " + (new Date().getTime() - start)); + + start = new Date().getTime(); + + let result = formatting.SmartIndenter.getIndentation(position, sourceFile, editorOptions); + log("getIndentationAtPosition: computeIndentation : " + (new Date().getTime() - start)); + + return result; + } + + function getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions): TextChange[] { + let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + return formatting.formatSelection(start, end, sourceFile, getRuleProvider(options), options); + } + + function getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions): TextChange[] { + let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + return formatting.formatDocument(sourceFile, getRuleProvider(options), options); + } + + function getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextChange[] { + let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + + if (key === "}") { + return formatting.formatOnClosingCurly(position, sourceFile, getRuleProvider(options), options); + } + else if (key === ";") { + return formatting.formatOnSemicolon(position, sourceFile, getRuleProvider(options), options); + } + else if (key === "\n") { + return formatting.formatOnEnter(position, sourceFile, getRuleProvider(options), options); + } + + return []; + } + + function getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] { + // Note: while getting todo comments seems like a syntactic operation, we actually + // treat it as a semantic operation here. This is because we expect our host to call + // this on every single file. If we treat this syntactically, then that will cause + // us to populate and throw away the tree in our syntax tree cache for each file. By + // treating this as a semantic operation, we can access any tree without throwing + // anything away. + synchronizeHostData(); + + let sourceFile = getValidSourceFile(fileName); + + cancellationToken.throwIfCancellationRequested(); + + let fileContents = sourceFile.text; + let result: TodoComment[] = []; + + if (descriptors.length > 0) { + let regExp = getTodoCommentsRegExp(); + + let matchArray: RegExpExecArray; + while (matchArray = regExp.exec(fileContents)) { + cancellationToken.throwIfCancellationRequested(); + + // If we got a match, here is what the match array will look like. Say the source text is: + // + // " // hack 1" + // + // The result array with the regexp: will be: + // + // ["// hack 1", "// ", "hack 1", undefined, "hack"] + // + // Here are the relevant capture groups: + // 0) The full match for the entire regexp. + // 1) The preamble to the message portion. + // 2) The message portion. + // 3...N) The descriptor that was matched - by index. 'undefined' for each + // descriptor that didn't match. an actual value if it did match. + // + // i.e. 'undefined' in position 3 above means TODO(jason) didn't match. + // "hack" in position 4 means HACK did match. + let firstDescriptorCaptureIndex = 3; + Debug.assert(matchArray.length === descriptors.length + firstDescriptorCaptureIndex); + + let preamble = matchArray[1]; + let matchPosition = matchArray.index + preamble.length; + + // OK, we have found a match in the file. This is only an acceptable match if + // it is contained within a comment. + let token = getTokenAtPosition(sourceFile, matchPosition); + if (!isInsideComment(sourceFile, token, matchPosition)) { + continue; + } + + let descriptor: TodoCommentDescriptor = undefined; + for (let i = 0, n = descriptors.length; i < n; i++) { + if (matchArray[i + firstDescriptorCaptureIndex]) { + descriptor = descriptors[i]; + } + } + Debug.assert(descriptor !== undefined); + + // We don't want to match something like 'TODOBY', so we make sure a non + // letter/digit follows the match. + if (isLetterOrDigit(fileContents.charCodeAt(matchPosition + descriptor.text.length))) { + continue; + } + + let message = matchArray[2]; + result.push({ + descriptor: descriptor, + message: message, + position: matchPosition + }); + } + } + + return result; + + function escapeRegExp(str: string): string { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + } + + function getTodoCommentsRegExp(): RegExp { + // NOTE: ?: means 'non-capture group'. It allows us to have groups without having to + // filter them out later in the final result array. + + // TODO comments can appear in one of the following forms: + // + // 1) // TODO or /////////// TODO + // + // 2) /* TODO or /********** TODO + // + // 3) /* + // * TODO + // */ + // + // The following three regexps are used to match the start of the text up to the TODO + // comment portion. + let singleLineCommentStart = /(?:\/\/+\s*)/.source; + let multiLineCommentStart = /(?:\/\*+\s*)/.source; + let anyNumberOfSpacesAndAsterixesAtStartOfLine = /(?:^(?:\s|\*)*)/.source; + + // Match any of the above three TODO comment start regexps. + // Note that the outermost group *is* a capture group. We want to capture the preamble + // so that we can determine the starting position of the TODO comment match. + let preamble = "(" + anyNumberOfSpacesAndAsterixesAtStartOfLine + "|" + singleLineCommentStart + "|" + multiLineCommentStart + ")"; + + // Takes the descriptors and forms a regexp that matches them as if they were literals. + // For example, if the descriptors are "TODO(jason)" and "HACK", then this will be: + // + // (?:(TODO\(jason\))|(HACK)) + // + // Note that the outermost group is *not* a capture group, but the innermost groups + // *are* capture groups. By capturing the inner literals we can determine after + // matching which descriptor we are dealing with. + let literals = "(?:" + map(descriptors, d => "(" + escapeRegExp(d.text) + ")").join("|") + ")"; + + // After matching a descriptor literal, the following regexp matches the rest of the + // text up to the end of the line (or */). + let endOfLineOrEndOfComment = /(?:$|\*\/)/.source + let messageRemainder = /(?:.*?)/.source + + // This is the portion of the match we'll return as part of the TODO comment result. We + // match the literal portion up to the end of the line or end of comment. + let messagePortion = "(" + literals + messageRemainder + ")"; + let regExpString = preamble + messagePortion + endOfLineOrEndOfComment; + + // The final regexp will look like this: + // /((?:\/\/+\s*)|(?:\/\*+\s*)|(?:^(?:\s|\*)*))((?:(TODO\(jason\))|(HACK))(?:.*?))(?:$|\*\/)/gim + + // The flags of the regexp are important here. + // 'g' is so that we are doing a global search and can find matches several times + // in the input. + // + // 'i' is for case insensitivity (We do this to match C# TODO comment code). + // + // 'm' is so we can find matches in a multi-line input. + return new RegExp(regExpString, "gim"); + } + + function isLetterOrDigit(char: number): boolean { + return (char >= CharacterCodes.a && char <= CharacterCodes.z) || + (char >= CharacterCodes.A && char <= CharacterCodes.Z) || + (char >= CharacterCodes._0 && char <= CharacterCodes._9); + } + } + + + function getRenameInfo(fileName: string, position: number): RenameInfo { + synchronizeHostData(); + + let sourceFile = getValidSourceFile(fileName); + let typeChecker = program.getTypeChecker(); + + let node = getTouchingWord(sourceFile, position); + + // Can only rename an identifier. + if (node && node.kind === SyntaxKind.Identifier) { + let symbol = typeChecker.getSymbolAtLocation(node); + + // Only allow a symbol to be renamed if it actually has at least one declaration. + if (symbol) { + let declarations = symbol.getDeclarations(); + if (declarations && declarations.length > 0) { + // Disallow rename for elements that are defined in the standard TypeScript library. + let defaultLibFileName = host.getDefaultLibFileName(host.getCompilationSettings()); + if (defaultLibFileName) { + for (let current of declarations) { + let sourceFile = current.getSourceFile(); + if (sourceFile && getCanonicalFileName(ts.normalizePath(sourceFile.fileName)) === getCanonicalFileName(ts.normalizePath(defaultLibFileName))) { + return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library.key)); + } + } + } + + let kind = getSymbolKind(symbol, node); + if (kind) { + return { + canRename: true, + localizedErrorMessage: undefined, + displayName: symbol.name, + fullDisplayName: typeChecker.getFullyQualifiedName(symbol), + kind: kind, + kindModifiers: getSymbolModifiers(symbol), + triggerSpan: createTextSpan(node.getStart(), node.getWidth()) + }; + } + } + } + } + + return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_this_element.key)); + + function getRenameInfoError(localizedErrorMessage: string): RenameInfo { + return { + canRename: false, + localizedErrorMessage: localizedErrorMessage, + displayName: undefined, + fullDisplayName: undefined, + kind: undefined, + kindModifiers: undefined, + triggerSpan: undefined + }; + } + } + + return { + dispose, + cleanupSemanticCache, + getSyntacticDiagnostics, + getSemanticDiagnostics, + getCompilerOptionsDiagnostics, + getSyntacticClassifications, + getSemanticClassifications, + getCompletionsAtPosition, + getCompletionEntryDetails, + getSignatureHelpItems, + getQuickInfoAtPosition, + getDefinitionAtPosition, + getReferencesAtPosition, + findReferences, + getOccurrencesAtPosition, + getDocumentHighlights, + getNameOrDottedNameSpan, + getBreakpointStatementAtPosition, + getNavigateToItems, + getRenameInfo, + findRenameLocations, + getNavigationBarItems, + getOutliningSpans, + getTodoComments, + getBraceMatchingAtPosition, + getIndentationAtPosition, + getFormattingEditsForRange, + getFormattingEditsForDocument, + getFormattingEditsAfterKeystroke, + getEmitOutput, + getSourceFile, + getProgram + }; + } + + /* @internal */ + export function getNameTable(sourceFile: SourceFile): Map { + if (!sourceFile.nameTable) { + initializeNameTable(sourceFile) + } + + return sourceFile.nameTable; + } + + function initializeNameTable(sourceFile: SourceFile): void { + let nameTable: Map = {}; + + walk(sourceFile); + sourceFile.nameTable = nameTable; + + function walk(node: Node) { + switch (node.kind) { + case SyntaxKind.Identifier: + nameTable[(node).text] = (node).text; + break; + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + // We want to store any numbers/strings if they were a name that could be + // related to a declaration. So, if we have 'import x = require("something")' + // then we want 'something' to be in the name table. Similarly, if we have + // "a['propname']" then we want to store "propname" in the name table. + if (isDeclarationName(node) || + node.parent.kind === SyntaxKind.ExternalModuleReference || + isArgumentOfElementAccessExpression(node)) { + + nameTable[(node).text] = (node).text; + } + break; + default: + forEachChild(node, walk); + } + } + } + + function isArgumentOfElementAccessExpression(node: Node) { + return node && + node.parent && + node.parent.kind === SyntaxKind.ElementAccessExpression && + (node.parent).argumentExpression === node; + } + + /// Classifier + export function createClassifier(): Classifier { + let scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false); + + /// We do not have a full parser support to know when we should parse a regex or not + /// If we consider every slash token to be a regex, we could be missing cases like "1/2/3", where + /// we have a series of divide operator. this list allows us to be more accurate by ruling out + /// locations where a regexp cannot exist. + let noRegexTable: boolean[] = []; + noRegexTable[SyntaxKind.Identifier] = true; + noRegexTable[SyntaxKind.StringLiteral] = true; + noRegexTable[SyntaxKind.NumericLiteral] = true; + noRegexTable[SyntaxKind.RegularExpressionLiteral] = true; + noRegexTable[SyntaxKind.ThisKeyword] = true; + noRegexTable[SyntaxKind.PlusPlusToken] = true; + noRegexTable[SyntaxKind.MinusMinusToken] = true; + noRegexTable[SyntaxKind.CloseParenToken] = true; + noRegexTable[SyntaxKind.CloseBracketToken] = true; + noRegexTable[SyntaxKind.CloseBraceToken] = true; + noRegexTable[SyntaxKind.TrueKeyword] = true; + noRegexTable[SyntaxKind.FalseKeyword] = true; + + // Just a stack of TemplateHeads and OpenCurlyBraces, used to perform rudimentary (inexact) + // classification on template strings. Because of the context free nature of templates, + // the only precise way to classify a template portion would be by propagating the stack across + // lines, just as we do with the end-of-line state. However, this is a burden for implementers, + // and the behavior is entirely subsumed by the syntactic classifier anyway, so we instead + // flatten any nesting when the template stack is non-empty and encode it in the end-of-line state. + // Situations in which this fails are + // 1) When template strings are nested across different lines: + // `hello ${ `world + // ` }` + // + // Where on the second line, you will get the closing of a template, + // a closing curly, and a new template. + // + // 2) When substitution expressions have curly braces and the curly brace falls on the next line: + // `hello ${ () => { + // return "world" } } ` + // + // Where on the second line, you will get the 'return' keyword, + // a string literal, and a template end consisting of '} } `'. + let templateStack: SyntaxKind[] = []; + + /** Returns true if 'keyword2' can legally follow 'keyword1' in any language construct. */ + function canFollow(keyword1: SyntaxKind, keyword2: SyntaxKind) { + if (isAccessibilityModifier(keyword1)) { + if (keyword2 === SyntaxKind.GetKeyword || + keyword2 === SyntaxKind.SetKeyword || + keyword2 === SyntaxKind.ConstructorKeyword || + keyword2 === SyntaxKind.StaticKeyword) { + + // Allow things like "public get", "public constructor" and "public static". + // These are all legal. + return true; + } + + // Any other keyword following "public" is actually an identifier an not a real + // keyword. + return false; + } + + // Assume any other keyword combination is legal. This can be refined in the future + // if there are more cases we want the classifier to be better at. + return true; + } + + // If there is a syntactic classifier ('syntacticClassifierAbsent' is false), + // we will be more conservative in order to avoid conflicting with the syntactic classifier. + function getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult { + let offset = 0; + let token = SyntaxKind.Unknown; + let lastNonTriviaToken = SyntaxKind.Unknown; + + // Empty out the template stack for reuse. + while (templateStack.length > 0) { + templateStack.pop(); + } + + // If we're in a string literal, then prepend: "\ + // (and a newline). That way when we lex we'll think we're still in a string literal. + // + // If we're in a multiline comment, then prepend: /* + // (and a newline). That way when we lex we'll think we're still in a multiline comment. + switch (lexState) { + case EndOfLineState.InDoubleQuoteStringLiteral: + text = '"\\\n' + text; + offset = 3; + break; + case EndOfLineState.InSingleQuoteStringLiteral: + text = "'\\\n" + text; + offset = 3; + break; + case EndOfLineState.InMultiLineCommentTrivia: + text = "/*\n" + text; + offset = 3; + break; + case EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate: + text = "`\n" + text; + offset = 2; + break; + case EndOfLineState.InTemplateMiddleOrTail: + text = "}\n" + text; + offset = 2; + // fallthrough + case EndOfLineState.InTemplateSubstitutionPosition: + templateStack.push(SyntaxKind.TemplateHead); + break; + } + + scanner.setText(text); + + let result: ClassificationResult = { + finalLexState: EndOfLineState.Start, + entries: [] + }; + + // We can run into an unfortunate interaction between the lexical and syntactic classifier + // when the user is typing something generic. Consider the case where the user types: + // + // Foo tokens. It's a weak heuristic, but should + // work well enough in practice. + let angleBracketStack = 0; + + do { + token = scanner.scan(); + + if (!isTrivia(token)) { + if ((token === SyntaxKind.SlashToken || token === SyntaxKind.SlashEqualsToken) && !noRegexTable[lastNonTriviaToken]) { + if (scanner.reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) { + token = SyntaxKind.RegularExpressionLiteral; + } + } + else if (lastNonTriviaToken === SyntaxKind.DotToken && isKeyword(token)) { + token = SyntaxKind.Identifier; + } + else if (isKeyword(lastNonTriviaToken) && isKeyword(token) && !canFollow(lastNonTriviaToken, token)) { + // We have two keywords in a row. Only treat the second as a keyword if + // it's a sequence that could legally occur in the language. Otherwise + // treat it as an identifier. This way, if someone writes "private var" + // we recognize that 'var' is actually an identifier here. + token = SyntaxKind.Identifier; + } + else if (lastNonTriviaToken === SyntaxKind.Identifier && + token === SyntaxKind.LessThanToken) { + // Could be the start of something generic. Keep track of that by bumping + // up the current count of generic contexts we may be in. + angleBracketStack++; + } + else if (token === SyntaxKind.GreaterThanToken && angleBracketStack > 0) { + // If we think we're currently in something generic, then mark that that + // generic entity is complete. + angleBracketStack--; + } + else if (token === SyntaxKind.AnyKeyword || + token === SyntaxKind.StringKeyword || + token === SyntaxKind.NumberKeyword || + token === SyntaxKind.BooleanKeyword || + token === SyntaxKind.SymbolKeyword) { + if (angleBracketStack > 0 && !syntacticClassifierAbsent) { + // If it looks like we're could be in something generic, don't classify this + // as a keyword. We may just get overwritten by the syntactic classifier, + // causing a noisy experience for the user. + token = SyntaxKind.Identifier; + } + } + else if (token === SyntaxKind.TemplateHead) { + templateStack.push(token); + } + else if (token === SyntaxKind.OpenBraceToken) { + // If we don't have anything on the template stack, + // then we aren't trying to keep track of a previously scanned template head. + if (templateStack.length > 0) { + templateStack.push(token); + } + } + else if (token === SyntaxKind.CloseBraceToken) { + // If we don't have anything on the template stack, + // then we aren't trying to keep track of a previously scanned template head. + if (templateStack.length > 0) { + let lastTemplateStackToken = lastOrUndefined(templateStack); + + if (lastTemplateStackToken === SyntaxKind.TemplateHead) { + token = scanner.reScanTemplateToken(); + + // Only pop on a TemplateTail; a TemplateMiddle indicates there is more for us. + if (token === SyntaxKind.TemplateTail) { + templateStack.pop(); + } + else { + Debug.assert(token === SyntaxKind.TemplateMiddle, "Should have been a template middle. Was " + token); + } + } + else { + Debug.assert(lastTemplateStackToken === SyntaxKind.OpenBraceToken, "Should have been an open brace. Was: " + token); + templateStack.pop(); + } + } + } + + lastNonTriviaToken = token; + } + + processToken(); + } + while (token !== SyntaxKind.EndOfFileToken); + + return result; + + function processToken(): void { + let start = scanner.getTokenPos(); + let end = scanner.getTextPos(); + + addResult(end - start, classFromKind(token)); + + if (end >= text.length) { + if (token === SyntaxKind.StringLiteral) { + // Check to see if we finished up on a multiline string literal. + let tokenText = scanner.getTokenText(); + if (scanner.isUnterminated()) { + let lastCharIndex = tokenText.length - 1; + + let numBackslashes = 0; + while (tokenText.charCodeAt(lastCharIndex - numBackslashes) === CharacterCodes.backslash) { + numBackslashes++; + } + + // If we have an odd number of backslashes, then the multiline string is unclosed + if (numBackslashes & 1) { + let quoteChar = tokenText.charCodeAt(0); + result.finalLexState = quoteChar === CharacterCodes.doubleQuote + ? EndOfLineState.InDoubleQuoteStringLiteral + : EndOfLineState.InSingleQuoteStringLiteral; + } + } + } + else if (token === SyntaxKind.MultiLineCommentTrivia) { + // Check to see if the multiline comment was unclosed. + if (scanner.isUnterminated()) { + result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; + } + } + else if (isTemplateLiteralKind(token)) { + if (scanner.isUnterminated()) { + if (token === SyntaxKind.TemplateTail) { + result.finalLexState = EndOfLineState.InTemplateMiddleOrTail; + } + else if (token === SyntaxKind.NoSubstitutionTemplateLiteral) { + result.finalLexState = EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate; + } + else { + Debug.fail("Only 'NoSubstitutionTemplateLiteral's and 'TemplateTail's can be unterminated; got SyntaxKind #" + token); + } + } + } + else if (templateStack.length > 0 && lastOrUndefined(templateStack) === SyntaxKind.TemplateHead) { + result.finalLexState = EndOfLineState.InTemplateSubstitutionPosition; + } + } + } + + function addResult(length: number, classification: TokenClass): void { + if (length > 0) { + // If this is the first classification we're adding to the list, then remove any + // offset we have if we were continuing a construct from the previous line. + if (result.entries.length === 0) { + length -= offset; + } + + result.entries.push({ length: length, classification: classification }); + } + } + } + + function isBinaryExpressionOperatorToken(token: SyntaxKind): boolean { + switch (token) { + case SyntaxKind.AsteriskToken: + case SyntaxKind.SlashToken: + case SyntaxKind.PercentToken: + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + case SyntaxKind.LessThanLessThanToken: + case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + case SyntaxKind.LessThanToken: + case SyntaxKind.GreaterThanToken: + case SyntaxKind.LessThanEqualsToken: + case SyntaxKind.GreaterThanEqualsToken: + case SyntaxKind.InstanceOfKeyword: + case SyntaxKind.InKeyword: + case SyntaxKind.EqualsEqualsToken: + case SyntaxKind.ExclamationEqualsToken: + case SyntaxKind.EqualsEqualsEqualsToken: + case SyntaxKind.ExclamationEqualsEqualsToken: + case SyntaxKind.AmpersandToken: + case SyntaxKind.CaretToken: + case SyntaxKind.BarToken: + case SyntaxKind.AmpersandAmpersandToken: + case SyntaxKind.BarBarToken: + case SyntaxKind.BarEqualsToken: + case SyntaxKind.AmpersandEqualsToken: + case SyntaxKind.CaretEqualsToken: + case SyntaxKind.LessThanLessThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + case SyntaxKind.PlusEqualsToken: + case SyntaxKind.MinusEqualsToken: + case SyntaxKind.AsteriskEqualsToken: + case SyntaxKind.SlashEqualsToken: + case SyntaxKind.PercentEqualsToken: + case SyntaxKind.EqualsToken: + case SyntaxKind.CommaToken: + return true; + default: + return false; + } + } + + function isPrefixUnaryExpressionOperatorToken(token: SyntaxKind): boolean { + switch (token) { + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + case SyntaxKind.TildeToken: + case SyntaxKind.ExclamationToken: + case SyntaxKind.PlusPlusToken: + case SyntaxKind.MinusMinusToken: + return true; + default: + return false; + } + } + + function isKeyword(token: SyntaxKind): boolean { + return token >= SyntaxKind.FirstKeyword && token <= SyntaxKind.LastKeyword; + } + + function classFromKind(token: SyntaxKind) { + if (isKeyword(token)) { + return TokenClass.Keyword; + } + else if (isBinaryExpressionOperatorToken(token) || isPrefixUnaryExpressionOperatorToken(token)) { + return TokenClass.Operator; + } + else if (token >= SyntaxKind.FirstPunctuation && token <= SyntaxKind.LastPunctuation) { + return TokenClass.Punctuation; + } + + switch (token) { + case SyntaxKind.NumericLiteral: + return TokenClass.NumberLiteral; + case SyntaxKind.StringLiteral: + return TokenClass.StringLiteral; + case SyntaxKind.RegularExpressionLiteral: + return TokenClass.RegExpLiteral; + case SyntaxKind.ConflictMarkerTrivia: + case SyntaxKind.MultiLineCommentTrivia: + case SyntaxKind.SingleLineCommentTrivia: + return TokenClass.Comment; + case SyntaxKind.WhitespaceTrivia: + case SyntaxKind.NewLineTrivia: + return TokenClass.Whitespace; + case SyntaxKind.Identifier: + default: + if (isTemplateLiteralKind(token)) { + return TokenClass.StringLiteral; + } + return TokenClass.Identifier; + } + } + + return { getClassificationsForLine }; + } + + /// getDefaultLibraryFilePath + declare let __dirname: string; + + /** + * Get the path of the default library file (lib.d.ts) as distributed with the typescript + * node package. + * The functionality is not supported if the ts module is consumed outside of a node module. + */ + export function getDefaultLibFilePath(options: CompilerOptions): string { + // Check __dirname is defined and that we are on a node.js system. + if (typeof __dirname !== "undefined") { + return __dirname + directorySeparator + getDefaultLibFileName(options); + } + + throw new Error("getDefaultLibFilePath is only supported when consumed as a node module. "); + } + + function initializeServices() { + objectAllocator = { + getNodeConstructor: kind => { + function Node() { + } + let proto = kind === SyntaxKind.SourceFile ? new SourceFileObject() : new NodeObject(); + proto.kind = kind; + proto.pos = 0; + proto.end = 0; + proto.flags = 0; + proto.parent = undefined; + Node.prototype = proto; + return Node; + }, + getSymbolConstructor: () => SymbolObject, + getTypeConstructor: () => TypeObject, + getSignatureConstructor: () => SignatureObject, + }; + } + + initializeServices(); +} diff --git a/lib/typescript/services/shims.ts b/lib/typescript/services/shims.ts new file mode 100644 index 000000000..e0572b649 --- /dev/null +++ b/lib/typescript/services/shims.ts @@ -0,0 +1,918 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +/* @internal */ +var debugObjectHost = (this); + +/* @internal */ +module ts { + export interface ScriptSnapshotShim { + /** Gets a portion of the script snapshot specified by [start, end). */ + getText(start: number, end: number): string; + + /** Gets the length of this script snapshot. */ + getLength(): number; + + /** + * Returns a JSON-encoded value of the type: + * { span: { start: number; length: number }; newLength: number } + * + * Or undefined value if there was no change. + */ + getChangeRange(oldSnapshot: ScriptSnapshotShim): string; + } + + export interface Logger { + log(s: string): void; + trace(s: string): void; + error(s: string): void; + } + + /** Public interface of the host of a language service shim instance.*/ + export interface LanguageServiceShimHost extends Logger { + getCompilationSettings(): string; + + /** Returns a JSON-encoded value of the type: string[] */ + getScriptFileNames(): string; + getScriptVersion(fileName: string): string; + getScriptSnapshot(fileName: string): ScriptSnapshotShim; + getLocalizedDiagnosticMessages(): string; + getCancellationToken(): CancellationToken; + getCurrentDirectory(): string; + getDefaultLibFileName(options: string): string; + getNewLine?(): string; + } + + /** Public interface of the the of a config service shim instance.*/ + export interface CoreServicesShimHost extends Logger { + /** Returns a JSON-encoded value of the type: string[] */ + readDirectory(rootDir: string, extension: string): string; + } + + /// + /// Pre-processing + /// + // Note: This is being using by the host (VS) and is marshaled back and forth. + // When changing this make sure the changes are reflected in the managed side as well + export interface IFileReference { + path: string; + position: number; + length: number; + } + + /** Public interface of a language service instance shim. */ + export interface ShimFactory { + registerShim(shim: Shim): void; + unregisterShim(shim: Shim): void; + } + + export interface Shim { + dispose(dummy: any): void; + } + + export interface LanguageServiceShim extends Shim { + languageService: LanguageService; + + dispose(dummy: any): void; + + refresh(throwOnError: boolean): void; + + cleanupSemanticCache(): void; + + getSyntacticDiagnostics(fileName: string): string; + getSemanticDiagnostics(fileName: string): string; + getCompilerOptionsDiagnostics(): string; + + getSyntacticClassifications(fileName: string, start: number, length: number): string; + getSemanticClassifications(fileName: string, start: number, length: number): string; + + getCompletionsAtPosition(fileName: string, position: number): string; + getCompletionEntryDetails(fileName: string, position: number, entryName: string): string; + + getQuickInfoAtPosition(fileName: string, position: number): string; + + getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string; + getBreakpointStatementAtPosition(fileName: string, position: number): string; + + getSignatureHelpItems(fileName: string, position: number): string; + + /** + * Returns a JSON-encoded value of the type: + * { canRename: boolean, localizedErrorMessage: string, displayName: string, fullDisplayName: string, kind: string, kindModifiers: string, triggerSpan: { start; length } } + */ + getRenameInfo(fileName: string, position: number): string; + + /** + * Returns a JSON-encoded value of the type: + * { fileName: string, textSpan: { start: number, length: number } }[] + */ + findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): string; + + /** + * Returns a JSON-encoded value of the type: + * { fileName: string; textSpan: { start: number; length: number}; kind: string; name: string; containerKind: string; containerName: string } + * + * Or undefined value if no definition can be found. + */ + getDefinitionAtPosition(fileName: string, position: number): string; + + /** + * Returns a JSON-encoded value of the type: + * { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean }[] + */ + getReferencesAtPosition(fileName: string, position: number): string; + + /** + * Returns a JSON-encoded value of the type: + * { definition: ; references: [] }[] + */ + findReferences(fileName: string, position: number): string; + + /** + * @deprecated + * Returns a JSON-encoded value of the type: + * { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean }[] + */ + getOccurrencesAtPosition(fileName: string, position: number): string; + + /** + * Returns a JSON-encoded value of the type: + * { fileName: string; highlights: { start: number; length: number, isDefinition: boolean }[] }[] + * + * @param fileToSearch A JSON encoded string[] containing the file names that should be + * considered when searching. + */ + getDocumentHighlights(fileName: string, position: number, filesToSearch: string): string; + + /** + * Returns a JSON-encoded value of the type: + * { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; textSpan: { start: number; length: number}; } [] = []; + */ + getNavigateToItems(searchValue: string, maxResultCount?: number): string; + + /** + * Returns a JSON-encoded value of the type: + * { text: string; kind: string; kindModifiers: string; bolded: boolean; grayed: boolean; indent: number; spans: { start: number; length: number; }[]; childItems: [] } [] = []; + */ + getNavigationBarItems(fileName: string): string; + + /** + * Returns a JSON-encoded value of the type: + * { textSpan: { start: number, length: number }; hintSpan: { start: number, length: number }; bannerText: string; autoCollapse: boolean } [] = []; + */ + getOutliningSpans(fileName: string): string; + + getTodoComments(fileName: string, todoCommentDescriptors: string): string; + + getBraceMatchingAtPosition(fileName: string, position: number): string; + getIndentationAtPosition(fileName: string, position: number, options: string/*Services.EditorOptions*/): string; + + getFormattingEditsForRange(fileName: string, start: number, end: number, options: string/*Services.FormatCodeOptions*/): string; + getFormattingEditsForDocument(fileName: string, options: string/*Services.FormatCodeOptions*/): string; + getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string; + + getEmitOutput(fileName: string): string; + } + + export interface ClassifierShim extends Shim { + getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string; + } + + export interface CoreServicesShim extends Shim { + getPreProcessedFileInfo(fileName: string, sourceText: IScriptSnapshot): string; + getTSConfigFileInfo(fileName: string, sourceText: IScriptSnapshot): string; + getDefaultCompilationSettings(): string; + } + + function logInternalError(logger: Logger, err: Error) { + logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); + } + + class ScriptSnapshotShimAdapter implements IScriptSnapshot { + private lineStartPositions: number[] = null; + + constructor(private scriptSnapshotShim: ScriptSnapshotShim) { + } + + public getText(start: number, end: number): string { + return this.scriptSnapshotShim.getText(start, end); + } + + public getLength(): number { + return this.scriptSnapshotShim.getLength(); + } + + public getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange { + var oldSnapshotShim = oldSnapshot; + var encoded = this.scriptSnapshotShim.getChangeRange(oldSnapshotShim.scriptSnapshotShim); + if (encoded == null) { + return null; + } + + var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded); + return createTextChangeRange( + createTextSpan(decoded.span.start, decoded.span.length), decoded.newLength); + } + } + + export class LanguageServiceShimHostAdapter implements LanguageServiceHost { + private files: string[]; + + constructor(private shimHost: LanguageServiceShimHost) { + } + + public log(s: string): void { + this.shimHost.log(s); + } + + public trace(s: string): void { + this.shimHost.trace(s); + } + + public error(s: string): void { + this.shimHost.error(s); + } + + public getCompilationSettings(): CompilerOptions { + var settingsJson = this.shimHost.getCompilationSettings(); + if (settingsJson == null || settingsJson == "") { + throw Error("LanguageServiceShimHostAdapter.getCompilationSettings: empty compilationSettings"); + return null; + } + return JSON.parse(settingsJson); + } + + public getScriptFileNames(): string[] { + var encoded = this.shimHost.getScriptFileNames(); + return this.files = JSON.parse(encoded); + } + + public getScriptSnapshot(fileName: string): IScriptSnapshot { + // Shim the API changes for 1.5 release. This should be removed once + // TypeScript 1.5 has shipped. + if (this.files && this.files.indexOf(fileName) < 0) { + return undefined; + } + var scriptSnapshot = this.shimHost.getScriptSnapshot(fileName); + return scriptSnapshot && new ScriptSnapshotShimAdapter(scriptSnapshot); + } + + public getScriptVersion(fileName: string): string { + return this.shimHost.getScriptVersion(fileName); + } + + public getLocalizedDiagnosticMessages(): any { + var diagnosticMessagesJson = this.shimHost.getLocalizedDiagnosticMessages(); + if (diagnosticMessagesJson == null || diagnosticMessagesJson == "") { + return null; + } + + try { + return JSON.parse(diagnosticMessagesJson); + } + catch (e) { + this.log(e.description || "diagnosticMessages.generated.json has invalid JSON format"); + return null; + } + } + + public getCancellationToken(): CancellationToken { + return this.shimHost.getCancellationToken(); + } + + public getCurrentDirectory(): string { + return this.shimHost.getCurrentDirectory(); + } + + public getDefaultLibFileName(options: CompilerOptions): string { + // Wrap the API changes for 1.5 release. This try/catch + // should be removed once TypeScript 1.5 has shipped. + try { + return this.shimHost.getDefaultLibFileName(JSON.stringify(options)); + } + catch (e) { + return ""; + } + } + } + + export class CoreServicesShimHostAdapter implements ParseConfigHost { + + constructor(private shimHost: CoreServicesShimHost) { + } + + public readDirectory(rootDir: string, extension: string): string[] { + var encoded = this.shimHost.readDirectory(rootDir, extension); + return JSON.parse(encoded); + } + } + + function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any): any { + logger.log(actionDescription); + var start = Date.now(); + var result = action(); + var end = Date.now(); + logger.log(actionDescription + " completed in " + (end - start) + " msec"); + if (typeof (result) === "string") { + var str = result; + if (str.length > 128) { + str = str.substring(0, 128) + "..."; + } + logger.log(" result.length=" + str.length + ", result='" + JSON.stringify(str) + "'"); + } + return result; + } + + function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any): string { + try { + var result = simpleForwardCall(logger, actionDescription, action); + return JSON.stringify({ result: result }); + } + catch (err) { + if (err instanceof OperationCanceledException) { + return JSON.stringify({ canceled: true }); + } + logInternalError(logger, err); + err.description = actionDescription; + return JSON.stringify({ error: err }); + } + } + + class ShimBase implements Shim { + constructor(private factory: ShimFactory) { + factory.registerShim(this); + } + public dispose(dummy: any): void { + this.factory.unregisterShim(this); + } + } + + export function realizeDiagnostics(diagnostics: Diagnostic[], newLine: string): { message: string; start: number; length: number; category: string; } []{ + return diagnostics.map(d => realizeDiagnostic(d, newLine)); + } + + function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; } { + return { + message: flattenDiagnosticMessageText(diagnostic.messageText, newLine), + start: diagnostic.start, + length: diagnostic.length, + /// TODO: no need for the tolowerCase call + category: DiagnosticCategory[diagnostic.category].toLowerCase(), + code: diagnostic.code + }; + } + + class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim { + private logger: Logger; + + constructor(factory: ShimFactory, + private host: LanguageServiceShimHost, + public languageService: LanguageService) { + super(factory); + this.logger = this.host; + } + + public forwardJSONCall(actionDescription: string, action: () => any): string { + return forwardJSONCall(this.logger, actionDescription, action); + } + + /// DISPOSE + + /** + * Ensure (almost) deterministic release of internal Javascript resources when + * some external native objects holds onto us (e.g. Com/Interop). + */ + public dispose(dummy: any): void { + this.logger.log("dispose()"); + this.languageService.dispose(); + this.languageService = null; + + // force a GC + if (debugObjectHost && debugObjectHost.CollectGarbage) { + debugObjectHost.CollectGarbage(); + this.logger.log("CollectGarbage()"); + } + + this.logger = null; + + super.dispose(dummy); + } + + /// REFRESH + + /** + * Update the list of scripts known to the compiler + */ + public refresh(throwOnError: boolean): void { + this.forwardJSONCall( + "refresh(" + throwOnError + ")", + () => { + return null; + }); + } + + public cleanupSemanticCache(): void { + this.forwardJSONCall( + "cleanupSemanticCache()", + () => { + this.languageService.cleanupSemanticCache(); + return null; + }); + } + + private realizeDiagnostics(diagnostics: Diagnostic[]): { message: string; start: number; length: number; category: string; }[]{ + var newLine = this.getNewLine(); + return ts.realizeDiagnostics(diagnostics, newLine); + } + + public getSyntacticClassifications(fileName: string, start: number, length: number): string { + return this.forwardJSONCall( + "getSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")", + () => { + var classifications = this.languageService.getSyntacticClassifications(fileName, createTextSpan(start, length)); + return classifications; + }); + } + + public getSemanticClassifications(fileName: string, start: number, length: number): string { + return this.forwardJSONCall( + "getSemanticClassifications('" + fileName + "', " + start + ", " + length + ")", + () => { + var classifications = this.languageService.getSemanticClassifications(fileName, createTextSpan(start, length)); + return classifications; + }); + } + + private getNewLine(): string { + return this.host.getNewLine ? this.host.getNewLine() : "\r\n"; + } + + public getSyntacticDiagnostics(fileName: string): string { + return this.forwardJSONCall( + "getSyntacticDiagnostics('" + fileName + "')", + () => { + var diagnostics = this.languageService.getSyntacticDiagnostics(fileName); + return this.realizeDiagnostics(diagnostics); + }); + } + + public getSemanticDiagnostics(fileName: string): string { + return this.forwardJSONCall( + "getSemanticDiagnostics('" + fileName + "')", + () => { + var diagnostics = this.languageService.getSemanticDiagnostics(fileName); + return this.realizeDiagnostics(diagnostics); + }); + } + + public getCompilerOptionsDiagnostics(): string { + return this.forwardJSONCall( + "getCompilerOptionsDiagnostics()", + () => { + var diagnostics = this.languageService.getCompilerOptionsDiagnostics(); + return this.realizeDiagnostics(diagnostics); + }); + } + + /// QUICKINFO + + /** + * Computes a string representation of the type at the requested position + * in the active file. + */ + public getQuickInfoAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getQuickInfoAtPosition('" + fileName + "', " + position + ")", + () => { + var quickInfo = this.languageService.getQuickInfoAtPosition(fileName, position); + return quickInfo; + }); + } + + + /// NAMEORDOTTEDNAMESPAN + + /** + * Computes span information of the name or dotted name at the requested position + * in the active file. + */ + public getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string { + return this.forwardJSONCall( + "getNameOrDottedNameSpan('" + fileName + "', " + startPos + ", " + endPos + ")", + () => { + var spanInfo = this.languageService.getNameOrDottedNameSpan(fileName, startPos, endPos); + return spanInfo; + }); + } + + /** + * STATEMENTSPAN + * Computes span information of statement at the requested position in the active file. + */ + public getBreakpointStatementAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getBreakpointStatementAtPosition('" + fileName + "', " + position + ")", + () => { + var spanInfo = this.languageService.getBreakpointStatementAtPosition(fileName, position); + return spanInfo; + }); + } + + /// SIGNATUREHELP + + public getSignatureHelpItems(fileName: string, position: number): string { + return this.forwardJSONCall( + "getSignatureHelpItems('" + fileName + "', " + position + ")", + () => { + var signatureInfo = this.languageService.getSignatureHelpItems(fileName, position); + return signatureInfo; + }); + } + + /// GOTO DEFINITION + + /** + * Computes the definition location and file for the symbol + * at the requested position. + */ + public getDefinitionAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getDefinitionAtPosition('" + fileName + "', " + position + ")", + () => { + return this.languageService.getDefinitionAtPosition(fileName, position); + }); + } + + public getRenameInfo(fileName: string, position: number): string { + return this.forwardJSONCall( + "getRenameInfo('" + fileName + "', " + position + ")", + () => { + return this.languageService.getRenameInfo(fileName, position); + }); + } + + public findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): string { + return this.forwardJSONCall( + "findRenameLocations('" + fileName + "', " + position + ", " + findInStrings + ", " + findInComments + ")", + () => { + return this.languageService.findRenameLocations(fileName, position, findInStrings, findInComments); + }); + } + + /// GET BRACE MATCHING + public getBraceMatchingAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getBraceMatchingAtPosition('" + fileName + "', " + position + ")", + () => { + var textRanges = this.languageService.getBraceMatchingAtPosition(fileName, position); + return textRanges; + }); + } + + /// GET SMART INDENT + public getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string { + return this.forwardJSONCall( + "getIndentationAtPosition('" + fileName + "', " + position + ")", + () => { + var localOptions: EditorOptions = JSON.parse(options); + return this.languageService.getIndentationAtPosition(fileName, position, localOptions); + }); + } + + /// GET REFERENCES + + public getReferencesAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getReferencesAtPosition('" + fileName + "', " + position + ")", + () => { + return this.languageService.getReferencesAtPosition(fileName, position); + }); + } + + public findReferences(fileName: string, position: number): string { + return this.forwardJSONCall( + "findReferences('" + fileName + "', " + position + ")", + () => { + return this.languageService.findReferences(fileName, position); + }); + } + + public getOccurrencesAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getOccurrencesAtPosition('" + fileName + "', " + position + ")", + () => { + return this.languageService.getOccurrencesAtPosition(fileName, position); + }); + } + + public getDocumentHighlights(fileName: string, position: number, filesToSearch: string): string { + return this.forwardJSONCall( + "getDocumentHighlights('" + fileName + "', " + position + ")", + () => { + return this.languageService.getDocumentHighlights(fileName, position, JSON.parse(filesToSearch)); + }); + } + + /// COMPLETION LISTS + + /** + * Get a string based representation of the completions + * to provide at the given source position and providing a member completion + * list if requested. + */ + public getCompletionsAtPosition(fileName: string, position: number) { + return this.forwardJSONCall( + "getCompletionsAtPosition('" + fileName + "', " + position + ")", + () => { + var completion = this.languageService.getCompletionsAtPosition(fileName, position); + return completion; + }); + } + + /** Get a string based representation of a completion list entry details */ + public getCompletionEntryDetails(fileName: string, position: number, entryName: string) { + return this.forwardJSONCall( + "getCompletionEntryDetails('" + fileName + "', " + position + ", " + entryName + ")", + () => { + var details = this.languageService.getCompletionEntryDetails(fileName, position, entryName); + return details; + }); + } + + public getFormattingEditsForRange(fileName: string, start: number, end: number, options: string/*Services.FormatCodeOptions*/): string { + return this.forwardJSONCall( + "getFormattingEditsForRange('" + fileName + "', " + start + ", " + end + ")", + () => { + var localOptions: ts.FormatCodeOptions = JSON.parse(options); + var edits = this.languageService.getFormattingEditsForRange(fileName, start, end, localOptions); + return edits; + }); + } + + public getFormattingEditsForDocument(fileName: string, options: string/*Services.FormatCodeOptions*/): string { + return this.forwardJSONCall( + "getFormattingEditsForDocument('" + fileName + "')", + () => { + var localOptions: ts.FormatCodeOptions = JSON.parse(options); + var edits = this.languageService.getFormattingEditsForDocument(fileName, localOptions); + return edits; + }); + } + + public getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string { + return this.forwardJSONCall( + "getFormattingEditsAfterKeystroke('" + fileName + "', " + position + ", '" + key + "')", + () => { + var localOptions: ts.FormatCodeOptions = JSON.parse(options); + var edits = this.languageService.getFormattingEditsAfterKeystroke(fileName, position, key, localOptions); + return edits; + }); + } + + /// NAVIGATE TO + + /** Return a list of symbols that are interesting to navigate to */ + public getNavigateToItems(searchValue: string, maxResultCount?: number): string { + return this.forwardJSONCall( + "getNavigateToItems('" + searchValue + "', " + maxResultCount+ ")", + () => { + var items = this.languageService.getNavigateToItems(searchValue, maxResultCount); + return items; + }); + } + + public getNavigationBarItems(fileName: string): string { + return this.forwardJSONCall( + "getNavigationBarItems('" + fileName + "')", + () => { + var items = this.languageService.getNavigationBarItems(fileName); + return items; + }); + } + + public getOutliningSpans(fileName: string): string { + return this.forwardJSONCall( + "getOutliningSpans('" + fileName + "')", + () => { + var items = this.languageService.getOutliningSpans(fileName); + return items; + }); + } + + public getTodoComments(fileName: string, descriptors: string): string { + return this.forwardJSONCall( + "getTodoComments('" + fileName + "')", + () => { + var items = this.languageService.getTodoComments(fileName, JSON.parse(descriptors)); + return items; + }); + } + + /// Emit + public getEmitOutput(fileName: string): string { + return this.forwardJSONCall( + "getEmitOutput('" + fileName + "')", + () => { + var output = this.languageService.getEmitOutput(fileName); + // Shim the API changes for 1.5 release. This should be removed once + // TypeScript 1.5 has shipped. + (output).emitOutputStatus = output.emitSkipped ? 1 : 0; + return output; + }); + } + } + + class ClassifierShimObject extends ShimBase implements ClassifierShim { + public classifier: Classifier; + + constructor(factory: ShimFactory) { + super(factory); + this.classifier = createClassifier(); + } + + /// COLORIZATION + public getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): string { + var classification = this.classifier.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics); + var items = classification.entries; + var result = ""; + for (var i = 0; i < items.length; i++) { + result += items[i].length + "\n"; + result += items[i].classification + "\n"; + } + result += classification.finalLexState; + return result; + } + } + + class CoreServicesShimObject extends ShimBase implements CoreServicesShim { + + constructor(factory: ShimFactory, public logger: Logger, private host: CoreServicesShimHostAdapter) { + super(factory); + } + + private forwardJSONCall(actionDescription: string, action: () => any): any { + return forwardJSONCall(this.logger, actionDescription, action); + } + + public getPreProcessedFileInfo(fileName: string, sourceTextSnapshot: IScriptSnapshot): string { + return this.forwardJSONCall( + "getPreProcessedFileInfo('" + fileName + "')", + () => { + var result = preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength())); + var convertResult = { + referencedFiles: [], + importedFiles: [], + isLibFile: result.isLibFile + }; + + forEach(result.referencedFiles, refFile => { + convertResult.referencedFiles.push({ + path: normalizePath(refFile.fileName), + position: refFile.pos, + length: refFile.end - refFile.pos + }); + }); + + forEach(result.importedFiles, importedFile => { + convertResult.importedFiles.push({ + path: normalizeSlashes(importedFile.fileName), + position: importedFile.pos, + length: importedFile.end - importedFile.pos + }); + }); + return convertResult; + }); + } + + public getTSConfigFileInfo(fileName: string, sourceTextSnapshot: IScriptSnapshot): string { + return this.forwardJSONCall( + "getTSConfigFileInfo('" + fileName + "')", + () => { + let text = sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()); + + let result = parseConfigFileText(fileName, text); + + if (result.error) { + return { + options: {}, + files: [], + errors: [realizeDiagnostic(result.error, '\r\n')] + }; + } + + var configFile = parseConfigFile(result.config, this.host, getDirectoryPath(normalizeSlashes(fileName))); + + return { + options: configFile.options, + files: configFile.fileNames, + errors: realizeDiagnostics(configFile.errors, '\r\n') + }; + }); + } + + public getDefaultCompilationSettings(): string { + return this.forwardJSONCall( + "getDefaultCompilationSettings()", + () => { + return getDefaultCompilerOptions(); + }); + } + } + + export class TypeScriptServicesFactory implements ShimFactory { + private _shims: Shim[] = []; + private documentRegistry: DocumentRegistry = createDocumentRegistry(); + + /* + * Returns script API version. + */ + public getServicesVersion(): string { + return servicesVersion; + } + + public createLanguageServiceShim(host: LanguageServiceShimHost): LanguageServiceShim { + try { + var hostAdapter = new LanguageServiceShimHostAdapter(host); + var languageService = createLanguageService(hostAdapter, this.documentRegistry); + return new LanguageServiceShimObject(this, host, languageService); + } + catch (err) { + logInternalError(host, err); + throw err; + } + } + + public createClassifierShim(logger: Logger): ClassifierShim { + try { + return new ClassifierShimObject(this); + } + catch (err) { + logInternalError(logger, err); + throw err; + } + } + + public createCoreServicesShim(host: CoreServicesShimHost): CoreServicesShim { + try { + var adapter = new CoreServicesShimHostAdapter(host); + return new CoreServicesShimObject(this, host, adapter); + } + catch (err) { + logInternalError(host, err); + throw err; + } + } + + public close(): void { + // Forget all the registered shims + this._shims = []; + this.documentRegistry = createDocumentRegistry(); + } + + public registerShim(shim: Shim): void { + this._shims.push(shim); + } + + public unregisterShim(shim: Shim): void { + for (var i = 0, n = this._shims.length; i < n; i++) { + if (this._shims[i] === shim) { + delete this._shims[i]; + return; + } + } + + throw new Error("Invalid operation"); + } + } + + // Here we expose the TypeScript services as an external module + // so that it may be consumed easily like a node module. + declare var module: any; + if (typeof module !== "undefined" && module.exports) { + module.exports = ts; + } +} + + +/// TODO: this is used by VS, clean this up on both sides of the interface +/* @internal */ +module TypeScript.Services { + export var TypeScriptServicesFactory = ts.TypeScriptServicesFactory; +} + +/* @internal */ +let toolsVersion = "1.4"; diff --git a/lib/typescript/services/signatureHelp.ts b/lib/typescript/services/signatureHelp.ts new file mode 100644 index 000000000..99ccb7166 --- /dev/null +++ b/lib/typescript/services/signatureHelp.ts @@ -0,0 +1,637 @@ +/// +/* @internal */ +module ts.SignatureHelp { + + // A partially written generic type expression is not guaranteed to have the correct syntax tree. the expression could be parsed as less than/greater than expression or a comma expression + // or some other combination depending on what the user has typed so far. For the purposes of signature help we need to consider any location after "<" as a possible generic type reference. + // To do this, the method will back parse the expression starting at the position required. it will try to parse the current expression as a generic type expression, if it did succeed it + // will return the generic identifier that started the expression (e.g. "foo" in "foo[]; + let resolvedSignature = typeChecker.getResolvedSignature(call, candidates); + cancellationToken.throwIfCancellationRequested(); + + if (!candidates.length) { + // We didn't have any sig help items produced by the TS compiler. If this is a JS + // file, then see if we can figure out anything better. + if (isJavaScript(sourceFile.fileName)) { + return createJavaScriptSignatureHelpItems(argumentInfo); + } + + return undefined; + } + + return createSignatureHelpItems(candidates, resolvedSignature, argumentInfo); + + function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo): SignatureHelpItems { + if (argumentInfo.invocation.kind !== SyntaxKind.CallExpression) { + return undefined; + } + + // See if we can find some symbol with the call expression name that has call signatures. + let callExpression = argumentInfo.invocation; + let expression = callExpression.expression; + let name = expression.kind === SyntaxKind.Identifier + ? expression + : expression.kind === SyntaxKind.PropertyAccessExpression + ? (expression).name + : undefined; + + if (!name || !name.text) { + return undefined; + } + + let typeChecker = program.getTypeChecker(); + for (let sourceFile of program.getSourceFiles()) { + let nameToDeclarations = sourceFile.getNamedDeclarations(); + let declarations = getProperty(nameToDeclarations, name.text); + + if (declarations) { + for (let declaration of declarations) { + let symbol = declaration.symbol; + if (symbol) { + let type = typeChecker.getTypeOfSymbolAtLocation(symbol, declaration); + if (type) { + let callSignatures = type.getCallSignatures(); + if (callSignatures && callSignatures.length) { + return createSignatureHelpItems(callSignatures, callSignatures[0], argumentInfo); + } + } + } + } + } + } + } + + /** + * Returns relevant information for the argument list and the current argument if we are + * in the argument of an invocation; returns undefined otherwise. + */ + function getImmediatelyContainingArgumentInfo(node: Node): ArgumentListInfo { + if (node.parent.kind === SyntaxKind.CallExpression || node.parent.kind === SyntaxKind.NewExpression) { + let callExpression = node.parent; + // There are 3 cases to handle: + // 1. The token introduces a list, and should begin a sig help session + // 2. The token is either not associated with a list, or ends a list, so the session should end + // 3. The token is buried inside a list, and should give sig help + // + // The following are examples of each: + // + // Case 1: + // foo<#T, U>(#a, b) -> The token introduces a list, and should begin a sig help session + // Case 2: + // fo#o#(a, b)# -> The token is either not associated with a list, or ends a list, so the session should end + // Case 3: + // foo(a#, #b#) -> The token is buried inside a list, and should give sig help + // Find out if 'node' is an argument, a type argument, or neither + if (node.kind === SyntaxKind.LessThanToken || + node.kind === SyntaxKind.OpenParenToken) { + // Find the list that starts right *after* the < or ( token. + // If the user has just opened a list, consider this item 0. + let list = getChildListThatStartsWithOpenerToken(callExpression, node, sourceFile); + let isTypeArgList = callExpression.typeArguments && callExpression.typeArguments.pos === list.pos; + Debug.assert(list !== undefined); + return { + kind: isTypeArgList ? ArgumentListKind.TypeArguments : ArgumentListKind.CallArguments, + invocation: callExpression, + argumentsSpan: getApplicableSpanForArguments(list), + argumentIndex: 0, + argumentCount: getArgumentCount(list) + }; + } + + // findListItemInfo can return undefined if we are not in parent's argument list + // or type argument list. This includes cases where the cursor is: + // - To the right of the closing paren, non-substitution template, or template tail. + // - Between the type arguments and the arguments (greater than token) + // - On the target of the call (parent.func) + // - On the 'new' keyword in a 'new' expression + let listItemInfo = findListItemInfo(node); + if (listItemInfo) { + let list = listItemInfo.list; + let isTypeArgList = callExpression.typeArguments && callExpression.typeArguments.pos === list.pos; + + let argumentIndex = getArgumentIndex(list, node); + let argumentCount = getArgumentCount(list); + + Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, + `argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`); + + return { + kind: isTypeArgList ? ArgumentListKind.TypeArguments : ArgumentListKind.CallArguments, + invocation: callExpression, + argumentsSpan: getApplicableSpanForArguments(list), + argumentIndex: argumentIndex, + argumentCount: argumentCount + }; + } + } + else if (node.kind === SyntaxKind.NoSubstitutionTemplateLiteral && node.parent.kind === SyntaxKind.TaggedTemplateExpression) { + // Check if we're actually inside the template; + // otherwise we'll fall out and return undefined. + if (isInsideTemplateLiteral(node, position)) { + return getArgumentListInfoForTemplate(node.parent, /*argumentIndex*/ 0); + } + } + else if (node.kind === SyntaxKind.TemplateHead && node.parent.parent.kind === SyntaxKind.TaggedTemplateExpression) { + let templateExpression = node.parent; + let tagExpression = templateExpression.parent; + Debug.assert(templateExpression.kind === SyntaxKind.TemplateExpression); + + let argumentIndex = isInsideTemplateLiteral(node, position) ? 0 : 1; + + return getArgumentListInfoForTemplate(tagExpression, argumentIndex); + } + else if (node.parent.kind === SyntaxKind.TemplateSpan && node.parent.parent.parent.kind === SyntaxKind.TaggedTemplateExpression) { + let templateSpan = node.parent; + let templateExpression = templateSpan.parent; + let tagExpression = templateExpression.parent; + Debug.assert(templateExpression.kind === SyntaxKind.TemplateExpression); + + // If we're just after a template tail, don't show signature help. + if (node.kind === SyntaxKind.TemplateTail && !isInsideTemplateLiteral(node, position)) { + return undefined; + } + + let spanIndex = templateExpression.templateSpans.indexOf(templateSpan); + let argumentIndex = getArgumentIndexForTemplatePiece(spanIndex, node); + + return getArgumentListInfoForTemplate(tagExpression, argumentIndex); + } + + return undefined; + } + + function getArgumentIndex(argumentsList: Node, node: Node) { + // The list we got back can include commas. In the presence of errors it may + // also just have nodes without commas. For example "Foo(a b c)" will have 3 + // args without commas. We want to find what index we're at. So we count + // forward until we hit ourselves, only incrementing the index if it isn't a + // comma. + // + // Note: the subtlety around trailing commas (in getArgumentCount) does not apply + // here. That's because we're only walking forward until we hit the node we're + // on. In that case, even if we're after the trailing comma, we'll still see + // that trailing comma in the list, and we'll have generated the appropriate + // arg index. + let argumentIndex = 0; + let listChildren = argumentsList.getChildren(); + for (let child of listChildren) { + if (child === node) { + break; + } + if (child.kind !== SyntaxKind.CommaToken) { + argumentIndex++; + } + } + + return argumentIndex; + } + + function getArgumentCount(argumentsList: Node) { + // The argument count for a list is normally the number of non-comma children it has. + // For example, if you have "Foo(a,b)" then there will be three children of the arg + // list 'a' '' 'b'. So, in this case the arg count will be 2. However, there + // is a small subtlety. If you have "Foo(a,)", then the child list will just have + // 'a' ''. So, in the case where the last child is a comma, we increase the + // arg count by one to compensate. + // + // Note: this subtlety only applies to the last comma. If you had "Foo(a,," then + // we'll have: 'a' '' '' + // That will give us 2 non-commas. We then add one for the last comma, givin us an + // arg count of 3. + let listChildren = argumentsList.getChildren(); + + let argumentCount = countWhere(listChildren, arg => arg.kind !== SyntaxKind.CommaToken); + if (listChildren.length > 0 && lastOrUndefined(listChildren).kind === SyntaxKind.CommaToken) { + argumentCount++; + } + + return argumentCount; + } + + // spanIndex is either the index for a given template span. + // This does not give appropriate results for a NoSubstitutionTemplateLiteral + function getArgumentIndexForTemplatePiece(spanIndex: number, node: Node): number { + // Because the TemplateStringsArray is the first argument, we have to offset each substitution expression by 1. + // There are three cases we can encounter: + // 1. We are precisely in the template literal (argIndex = 0). + // 2. We are in or to the right of the substitution expression (argIndex = spanIndex + 1). + // 3. We are directly to the right of the template literal, but because we look for the token on the left, + // not enough to put us in the substitution expression; we should consider ourselves part of + // the *next* span's expression by offsetting the index (argIndex = (spanIndex + 1) + 1). + // + // Example: f `# abcd $#{# 1 + 1# }# efghi ${ #"#hello"# } # ` + // ^ ^ ^ ^ ^ ^ ^ ^ ^ + // Case: 1 1 3 2 1 3 2 2 1 + Debug.assert(position >= node.getStart(), "Assumed 'position' could not occur before node."); + if (isTemplateLiteralKind(node.kind)) { + if (isInsideTemplateLiteral(node, position)) { + return 0; + } + return spanIndex + 2; + } + return spanIndex + 1; + } + + function getArgumentListInfoForTemplate(tagExpression: TaggedTemplateExpression, argumentIndex: number): ArgumentListInfo { + // argumentCount is either 1 or (numSpans + 1) to account for the template strings array argument. + let argumentCount = tagExpression.template.kind === SyntaxKind.NoSubstitutionTemplateLiteral + ? 1 + : (tagExpression.template).templateSpans.length + 1; + + Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, `argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`); + + return { + kind: ArgumentListKind.TaggedTemplateArguments, + invocation: tagExpression, + argumentsSpan: getApplicableSpanForTaggedTemplate(tagExpression), + argumentIndex: argumentIndex, + argumentCount: argumentCount + }; + } + + function getApplicableSpanForArguments(argumentsList: Node): TextSpan { + // We use full start and skip trivia on the end because we want to include trivia on + // both sides. For example, + // + // foo( /*comment */ a, b, c /*comment*/ ) + // | | + // + // The applicable span is from the first bar to the second bar (inclusive, + // but not including parentheses) + let applicableSpanStart = argumentsList.getFullStart(); + let applicableSpanEnd = skipTrivia(sourceFile.text, argumentsList.getEnd(), /*stopAfterLineBreak*/ false); + return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); + } + + function getApplicableSpanForTaggedTemplate(taggedTemplate: TaggedTemplateExpression): TextSpan { + let template = taggedTemplate.template; + let applicableSpanStart = template.getStart(); + let applicableSpanEnd = template.getEnd(); + + // We need to adjust the end position for the case where the template does not have a tail. + // Otherwise, we will not show signature help past the expression. + // For example, + // + // ` ${ 1 + 1 foo(10) + // | | + // + // This is because a Missing node has no width. However, what we actually want is to include trivia + // leading up to the next token in case the user is about to type in a TemplateMiddle or TemplateTail. + if (template.kind === SyntaxKind.TemplateExpression) { + let lastSpan = lastOrUndefined((template).templateSpans); + if (lastSpan.literal.getFullWidth() === 0) { + applicableSpanEnd = skipTrivia(sourceFile.text, applicableSpanEnd, /*stopAfterLineBreak*/ false); + } + } + + return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); + } + + function getContainingArgumentInfo(node: Node): ArgumentListInfo { + for (let n = node; n.kind !== SyntaxKind.SourceFile; n = n.parent) { + if (isFunctionBlock(n)) { + return undefined; + } + + // If the node is not a subspan of its parent, this is a big problem. + // There have been crashes that might be caused by this violation. + if (n.pos < n.parent.pos || n.end > n.parent.end) { + Debug.fail("Node of kind " + n.kind + " is not a subspan of its parent of kind " + n.parent.kind); + } + + let argumentInfo = getImmediatelyContainingArgumentInfo(n); + if (argumentInfo) { + return argumentInfo; + } + + + // TODO: Handle generic call with incomplete syntax + } + return undefined; + } + + function getChildListThatStartsWithOpenerToken(parent: Node, openerToken: Node, sourceFile: SourceFile): Node { + let children = parent.getChildren(sourceFile); + let indexOfOpenerToken = children.indexOf(openerToken); + Debug.assert(indexOfOpenerToken >= 0 && children.length > indexOfOpenerToken + 1); + return children[indexOfOpenerToken + 1]; + } + + /** + * The selectedItemIndex could be negative for several reasons. + * 1. There are too many arguments for all of the overloads + * 2. None of the overloads were type compatible + * The solution here is to try to pick the best overload by picking + * either the first one that has an appropriate number of parameters, + * or the one with the most parameters. + */ + function selectBestInvalidOverloadIndex(candidates: Signature[], argumentCount: number): number { + let maxParamsSignatureIndex = -1; + let maxParams = -1; + for (let i = 0; i < candidates.length; i++) { + let candidate = candidates[i]; + + if (candidate.hasRestParameter || candidate.parameters.length >= argumentCount) { + return i; + } + + if (candidate.parameters.length > maxParams) { + maxParams = candidate.parameters.length; + maxParamsSignatureIndex = i; + } + } + + return maxParamsSignatureIndex; + } + + function createSignatureHelpItems(candidates: Signature[], bestSignature: Signature, argumentListInfo: ArgumentListInfo): SignatureHelpItems { + let applicableSpan = argumentListInfo.argumentsSpan; + let isTypeParameterList = argumentListInfo.kind === ArgumentListKind.TypeArguments; + + let invocation = argumentListInfo.invocation; + let callTarget = getInvokedExpression(invocation) + let callTargetSymbol = typeChecker.getSymbolAtLocation(callTarget); + let callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined); + let items: SignatureHelpItem[] = map(candidates, candidateSignature => { + let signatureHelpParameters: SignatureHelpParameter[]; + let prefixDisplayParts: SymbolDisplayPart[] = []; + let suffixDisplayParts: SymbolDisplayPart[] = []; + + if (callTargetDisplayParts) { + prefixDisplayParts.push.apply(prefixDisplayParts, callTargetDisplayParts); + } + + if (isTypeParameterList) { + prefixDisplayParts.push(punctuationPart(SyntaxKind.LessThanToken)); + let typeParameters = candidateSignature.typeParameters; + signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray; + suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken)); + let parameterParts = mapToDisplayParts(writer => + typeChecker.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.parameters, writer, invocation)); + suffixDisplayParts.push.apply(suffixDisplayParts, parameterParts); + } + else { + let typeParameterParts = mapToDisplayParts(writer => + typeChecker.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, invocation)); + prefixDisplayParts.push.apply(prefixDisplayParts, typeParameterParts); + prefixDisplayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); + + let parameters = candidateSignature.parameters; + signatureHelpParameters = parameters.length > 0 ? map(parameters, createSignatureHelpParameterForParameter) : emptyArray; + suffixDisplayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); + } + + let returnTypeParts = mapToDisplayParts(writer => + typeChecker.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, invocation)); + suffixDisplayParts.push.apply(suffixDisplayParts, returnTypeParts); + + return { + isVariadic: candidateSignature.hasRestParameter, + prefixDisplayParts, + suffixDisplayParts, + separatorDisplayParts: [punctuationPart(SyntaxKind.CommaToken), spacePart()], + parameters: signatureHelpParameters, + documentation: candidateSignature.getDocumentationComment() + }; + }); + + let argumentIndex = argumentListInfo.argumentIndex; + + // argumentCount is the *apparent* number of arguments. + let argumentCount = argumentListInfo.argumentCount; + + let selectedItemIndex = candidates.indexOf(bestSignature); + if (selectedItemIndex < 0) { + selectedItemIndex = selectBestInvalidOverloadIndex(candidates, argumentCount); + } + + Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, `argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`); + + return { + items, + applicableSpan, + selectedItemIndex, + argumentIndex, + argumentCount + }; + + function createSignatureHelpParameterForParameter(parameter: Symbol): SignatureHelpParameter { + let displayParts = mapToDisplayParts(writer => + typeChecker.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, invocation)); + + let isOptional = hasQuestionToken(parameter.valueDeclaration); + + return { + name: parameter.name, + documentation: parameter.getDocumentationComment(), + displayParts, + isOptional + }; + } + + function createSignatureHelpParameterForTypeParameter(typeParameter: TypeParameter): SignatureHelpParameter { + let displayParts = mapToDisplayParts(writer => + typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(typeParameter, writer, invocation)); + + return { + name: typeParameter.symbol.name, + documentation: emptyArray, + displayParts, + isOptional: false + }; + } + } + } +} \ No newline at end of file diff --git a/lib/typescript/services/utilities.ts b/lib/typescript/services/utilities.ts new file mode 100644 index 000000000..2e1ccfdf8 --- /dev/null +++ b/lib/typescript/services/utilities.ts @@ -0,0 +1,659 @@ +// These utilities are common to multiple language service features. +/* @internal */ +module ts { + export interface ListItemInfo { + listItemIndex: number; + list: Node; + } + + export function getEndLinePosition(line: number, sourceFile: SourceFile): number { + Debug.assert(line >= 0); + let lineStarts = sourceFile.getLineStarts(); + + let lineIndex = line; + if (lineIndex + 1 === lineStarts.length) { + // last line - return EOF + return sourceFile.text.length - 1; + } + else { + // current line start + let start = lineStarts[lineIndex]; + // take the start position of the next line -1 = it should be some line break + let pos = lineStarts[lineIndex + 1] - 1; + Debug.assert(isLineBreak(sourceFile.text.charCodeAt(pos))); + // walk backwards skipping line breaks, stop the the beginning of current line. + // i.e: + // + // $ <- end of line for this position should match the start position + while (start <= pos && isLineBreak(sourceFile.text.charCodeAt(pos))) { + pos--; + } + return pos; + } + } + + export function getLineStartPositionForPosition(position: number, sourceFile: SourceFile): number { + let lineStarts = sourceFile.getLineStarts(); + let line = sourceFile.getLineAndCharacterOfPosition(position).line; + return lineStarts[line]; + } + + export function rangeContainsRange(r1: TextRange, r2: TextRange): boolean { + return startEndContainsRange(r1.pos, r1.end, r2); + } + + export function startEndContainsRange(start: number, end: number, range: TextRange): boolean { + return start <= range.pos && end >= range.end; + } + + export function rangeContainsStartEnd(range: TextRange, start: number, end: number): boolean { + return range.pos <= start && range.end >= end; + } + + export function rangeOverlapsWithStartEnd(r1: TextRange, start: number, end: number) { + return startEndOverlapsWithStartEnd(r1.pos, r1.end, start, end); + } + + export function startEndOverlapsWithStartEnd(start1: number, end1: number, start2: number, end2: number) { + let start = Math.max(start1, start2); + let end = Math.min(end1, end2); + return start < end; + } + + export function positionBelongsToNode(candidate: Node, position: number, sourceFile: SourceFile): boolean { + return candidate.end > position || !isCompletedNode(candidate, sourceFile); + } + + export function isCompletedNode(n: Node, sourceFile: SourceFile): boolean { + if (nodeIsMissing(n)) { + return false; + } + + switch (n.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.TypeLiteral: + case SyntaxKind.Block: + case SyntaxKind.ModuleBlock: + case SyntaxKind.CaseBlock: + return nodeEndsWith(n, SyntaxKind.CloseBraceToken, sourceFile); + case SyntaxKind.CatchClause: + return isCompletedNode((n).block, sourceFile); + case SyntaxKind.NewExpression: + if (!(n).arguments) { + return true; + } + // fall through + case SyntaxKind.CallExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.ParenthesizedType: + return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile); + + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + return isCompletedNode((n).type, sourceFile); + + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.ArrowFunction: + if ((n).body) { + return isCompletedNode((n).body, sourceFile); + } + + if ((n).type) { + return isCompletedNode((n).type, sourceFile); + } + + // Even though type parameters can be unclosed, we can get away with + // having at least a closing paren. + return hasChildOfKind(n, SyntaxKind.CloseParenToken, sourceFile); + + case SyntaxKind.ModuleDeclaration: + return (n).body && isCompletedNode((n).body, sourceFile); + + case SyntaxKind.IfStatement: + if ((n).elseStatement) { + return isCompletedNode((n).elseStatement, sourceFile); + } + return isCompletedNode((n).thenStatement, sourceFile); + + case SyntaxKind.ExpressionStatement: + return isCompletedNode((n).expression, sourceFile); + + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.ComputedPropertyName: + case SyntaxKind.TupleType: + return nodeEndsWith(n, SyntaxKind.CloseBracketToken, sourceFile); + + case SyntaxKind.IndexSignature: + if ((n).type) { + return isCompletedNode((n).type, sourceFile); + } + + return hasChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile); + + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + // there is no such thing as terminator token for CaseClause/DefaultClause so for simplicitly always consider them non-completed + return false; + + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.WhileStatement: + return isCompletedNode((n).statement, sourceFile); + case SyntaxKind.DoStatement: + // rough approximation: if DoStatement has While keyword - then if node is completed is checking the presence of ')'; + let hasWhileKeyword = findChildOfKind(n, SyntaxKind.WhileKeyword, sourceFile); + if (hasWhileKeyword) { + return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile); + } + return isCompletedNode((n).statement, sourceFile); + + case SyntaxKind.TypeQuery: + return isCompletedNode((n).exprName, sourceFile); + + case SyntaxKind.TypeOfExpression: + case SyntaxKind.DeleteExpression: + case SyntaxKind.VoidExpression: + case SyntaxKind.YieldExpression: + case SyntaxKind.SpreadElementExpression: + let unaryWordExpression = (n); + return isCompletedNode(unaryWordExpression.expression, sourceFile); + + case SyntaxKind.TaggedTemplateExpression: + return isCompletedNode((n).template, sourceFile); + case SyntaxKind.TemplateExpression: + let lastSpan = lastOrUndefined((n).templateSpans); + return isCompletedNode(lastSpan, sourceFile); + case SyntaxKind.TemplateSpan: + return nodeIsPresent((n).literal); + + case SyntaxKind.PrefixUnaryExpression: + return isCompletedNode((n).operand, sourceFile); + case SyntaxKind.BinaryExpression: + return isCompletedNode((n).right, sourceFile); + case SyntaxKind.ConditionalExpression: + return isCompletedNode((n).whenFalse, sourceFile); + + default: + return true; + } + } + + /* + * Checks if node ends with 'expectedLastToken'. + * If child at position 'length - 1' is 'SemicolonToken' it is skipped and 'expectedLastToken' is compared with child at position 'length - 2'. + */ + function nodeEndsWith(n: Node, expectedLastToken: SyntaxKind, sourceFile: SourceFile): boolean { + let children = n.getChildren(sourceFile); + if (children.length) { + let last = children[children.length - 1]; + if (last.kind === expectedLastToken) { + return true; + } + else if (last.kind === SyntaxKind.SemicolonToken && children.length !== 1) { + return children[children.length - 2].kind === expectedLastToken; + } + } + return false; + } + + export function findListItemInfo(node: Node): ListItemInfo { + let list = findContainingList(node); + + // It is possible at this point for syntaxList to be undefined, either if + // node.parent had no list child, or if none of its list children contained + // the span of node. If this happens, return undefined. The caller should + // handle this case. + if (!list) { + return undefined; + } + + let children = list.getChildren(); + let listItemIndex = indexOf(children, node); + + return { + listItemIndex, + list + }; + } + + export function hasChildOfKind(n: Node, kind: SyntaxKind, sourceFile?: SourceFile): boolean { + return !!findChildOfKind(n, kind, sourceFile); + } + + export function findChildOfKind(n: Node, kind: SyntaxKind, sourceFile?: SourceFile): Node { + return forEach(n.getChildren(sourceFile), c => c.kind === kind && c); + } + + export function findContainingList(node: Node): Node { + // The node might be a list element (nonsynthetic) or a comma (synthetic). Either way, it will + // be parented by the container of the SyntaxList, not the SyntaxList itself. + // In order to find the list item index, we first need to locate SyntaxList itself and then search + // for the position of the relevant node (or comma). + let syntaxList = forEach(node.parent.getChildren(), c => { + // find syntax list that covers the span of the node + if (c.kind === SyntaxKind.SyntaxList && c.pos <= node.pos && c.end >= node.end) { + return c; + } + }); + + // Either we didn't find an appropriate list, or the list must contain us. + Debug.assert(!syntaxList || contains(syntaxList.getChildren(), node)); + return syntaxList; + } + + /* Gets the token whose text has range [start, end) and + * position >= start and (position < end or (position === end && token is keyword or identifier)) + */ + export function getTouchingWord(sourceFile: SourceFile, position: number): Node { + return getTouchingToken(sourceFile, position, n => isWord(n.kind)); + } + + /* Gets the token whose text has range [start, end) and position >= start + * and (position < end or (position === end && token is keyword or identifier or numeric\string litera)) + */ + export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node { + return getTouchingToken(sourceFile, position, n => isPropertyName(n.kind)); + } + + /** Returns the token if position is in [start, end) or if position === end and includeItemAtEndPosition(token) === true */ + export function getTouchingToken(sourceFile: SourceFile, position: number, includeItemAtEndPosition?: (n: Node) => boolean): Node { + return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includeItemAtEndPosition); + } + + /** Returns a token if position is in [start-of-leading-trivia, end) */ + export function getTokenAtPosition(sourceFile: SourceFile, position: number): Node { + return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includeItemAtEndPosition*/ undefined); + } + + /** Get the token whose text contains the position */ + function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includeItemAtEndPosition: (n: Node) => boolean): Node { + let current: Node = sourceFile; + outer: while (true) { + if (isToken(current)) { + // exit early + return current; + } + + // find the child that contains 'position' + for (let i = 0, n = current.getChildCount(sourceFile); i < n; i++) { + let child = current.getChildAt(i); + let start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile); + if (start <= position) { + let end = child.getEnd(); + if (position < end || (position === end && child.kind === SyntaxKind.EndOfFileToken)) { + current = child; + continue outer; + } + else if (includeItemAtEndPosition && end === position) { + let previousToken = findPrecedingToken(position, sourceFile, child); + if (previousToken && includeItemAtEndPosition(previousToken)) { + return previousToken; + } + } + } + } + return current; + } + } + + /** + * The token on the left of the position is the token that strictly includes the position + * or sits to the left of the cursor if it is on a boundary. For example + * + * fo|o -> will return foo + * foo |bar -> will return foo + * + */ + export function findTokenOnLeftOfPosition(file: SourceFile, position: number): Node { + // Ideally, getTokenAtPosition should return a token. However, it is currently + // broken, so we do a check to make sure the result was indeed a token. + let tokenAtPosition = getTokenAtPosition(file, position); + if (isToken(tokenAtPosition) && position > tokenAtPosition.getStart(file) && position < tokenAtPosition.getEnd()) { + return tokenAtPosition; + } + + return findPrecedingToken(position, file); + } + + export function findNextToken(previousToken: Node, parent: Node): Node { + return find(parent); + + function find(n: Node): Node { + if (isToken(n) && n.pos === previousToken.end) { + // this is token that starts at the end of previous token - return it + return n; + } + + let children = n.getChildren(); + for (let child of children) { + let shouldDiveInChildNode = + // previous token is enclosed somewhere in the child + (child.pos <= previousToken.pos && child.end > previousToken.end) || + // previous token ends exactly at the beginning of child + (child.pos === previousToken.end); + + if (shouldDiveInChildNode && nodeHasTokens(child)) { + return find(child); + } + } + + return undefined; + } + } + + export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node): Node { + return find(startNode || sourceFile); + + function findRightmostToken(n: Node): Node { + if (isToken(n)) { + return n; + } + + let children = n.getChildren(); + let candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length); + return candidate && findRightmostToken(candidate); + + } + + function find(n: Node): Node { + if (isToken(n)) { + return n; + } + + let children = n.getChildren(); + for (let i = 0, len = children.length; i < len; i++) { + let child = children[i]; + if (nodeHasTokens(child)) { + if (position <= child.end) { + if (child.getStart(sourceFile) >= position) { + // 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) + } + else { + // candidate should be in this node + return find(child); + } + } + } + } + + Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile); + + // Here we know that none of child token nodes embrace the position, + // the only known case is when position is at the end of the file. + // Try to find the rightmost token in the file without filtering. + // Namely we are skipping the check: 'position < node.end' + if (children.length) { + let candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length); + return candidate && findRightmostToken(candidate); + } + } + + /// finds last node that is considered as candidate for search (isCandidate(node) === true) starting from 'exclusiveStartPosition' + function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number): Node { + for (let i = exclusiveStartPosition - 1; i >= 0; --i) { + if (nodeHasTokens(children[i])) { + return children[i]; + } + } + } + } + + function nodeHasTokens(n: Node): boolean { + // If we have a token or node that has a non-zero width, it must have tokens. + // Note, that getWidth() does not take trivia into account. + return n.getWidth() !== 0; + } + + export function getNodeModifiers(node: Node): string { + let flags = getCombinedNodeFlags(node); + let result: string[] = []; + + if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); + if (flags & NodeFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier); + if (flags & NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); + if (flags & NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier); + if (flags & NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); + if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); + + return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; + } + + export function getTypeArgumentOrTypeParameterList(node: Node): NodeArray { + if (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.CallExpression) { + return (node).typeArguments; + } + + if (isFunctionLike(node) || node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.InterfaceDeclaration) { + return (node).typeParameters; + } + + return undefined; + } + + export function isToken(n: Node): boolean { + return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken; + } + + export function isWord(kind: SyntaxKind): boolean { + return kind === SyntaxKind.Identifier || isKeyword(kind); + } + + function isPropertyName(kind: SyntaxKind): boolean { + return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NumericLiteral || isWord(kind); + } + + export function isComment(kind: SyntaxKind): boolean { + return kind === SyntaxKind.SingleLineCommentTrivia || kind === SyntaxKind.MultiLineCommentTrivia; + } + + export function isPunctuation(kind: SyntaxKind): boolean { + return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation; + } + + export function isInsideTemplateLiteral(node: LiteralExpression, position: number) { + return isTemplateLiteralKind(node.kind) + && (node.getStart() < position && position < node.getEnd()) || (!!node.isUnterminated && position === node.getEnd()); + } + + export function isAccessibilityModifier(kind: SyntaxKind) { + switch (kind) { + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + return true; + } + + return false; + } + + export function compareDataObjects(dst: any, src: any): boolean { + for (let e in dst) { + if (typeof dst[e] === "object") { + if (!compareDataObjects(dst[e], src[e])) { + return false; + } + } + else if (typeof dst[e] !== "function") { + if (dst[e] !== src[e]) { + return false; + } + } + } + return true; + } +} + +// Display-part writer helpers +/* @internal */ +module ts { + export function isFirstDeclarationOfSymbolParameter(symbol: Symbol) { + return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter; + } + + let displayPartWriter = getDisplayPartWriter(); + function getDisplayPartWriter(): DisplayPartsSymbolWriter { + let displayParts: SymbolDisplayPart[]; + let lineStart: boolean; + let indent: number; + + resetWriter(); + return { + displayParts: () => displayParts, + writeKeyword: text => writeKind(text, SymbolDisplayPartKind.keyword), + writeOperator: text => writeKind(text, SymbolDisplayPartKind.operator), + writePunctuation: text => writeKind(text, SymbolDisplayPartKind.punctuation), + writeSpace: text => writeKind(text, SymbolDisplayPartKind.space), + writeStringLiteral: text => writeKind(text, SymbolDisplayPartKind.stringLiteral), + writeParameter: text => writeKind(text, SymbolDisplayPartKind.parameterName), + writeSymbol, + writeLine, + increaseIndent: () => { indent++; }, + decreaseIndent: () => { indent--; }, + clear: resetWriter, + trackSymbol: () => { } + }; + + function writeIndent() { + if (lineStart) { + let indentString = getIndentString(indent); + if (indentString) { + displayParts.push(displayPart(indentString, SymbolDisplayPartKind.space)); + } + lineStart = false; + } + } + + function writeKind(text: string, kind: SymbolDisplayPartKind) { + writeIndent(); + displayParts.push(displayPart(text, kind)); + } + + function writeSymbol(text: string, symbol: Symbol) { + writeIndent(); + displayParts.push(symbolPart(text, symbol)); + } + + function writeLine() { + displayParts.push(lineBreakPart()); + lineStart = true; + } + + function resetWriter() { + displayParts = [] + lineStart = true; + indent = 0; + } + } + + export function symbolPart(text: string, symbol: Symbol) { + return displayPart(text, displayPartKind(symbol), symbol); + + function displayPartKind(symbol: Symbol): SymbolDisplayPartKind { + let flags = symbol.flags; + + if (flags & SymbolFlags.Variable) { + return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName : SymbolDisplayPartKind.localName; + } + else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.propertyName; } + else if (flags & SymbolFlags.GetAccessor) { return SymbolDisplayPartKind.propertyName; } + else if (flags & SymbolFlags.SetAccessor) { return SymbolDisplayPartKind.propertyName; } + else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.enumMemberName; } + else if (flags & SymbolFlags.Function) { return SymbolDisplayPartKind.functionName; } + else if (flags & SymbolFlags.Class) { return SymbolDisplayPartKind.className; } + else if (flags & SymbolFlags.Interface) { return SymbolDisplayPartKind.interfaceName; } + else if (flags & SymbolFlags.Enum) { return SymbolDisplayPartKind.enumName; } + else if (flags & SymbolFlags.Module) { return SymbolDisplayPartKind.moduleName; } + else if (flags & SymbolFlags.Method) { return SymbolDisplayPartKind.methodName; } + else if (flags & SymbolFlags.TypeParameter) { return SymbolDisplayPartKind.typeParameterName; } + else if (flags & SymbolFlags.TypeAlias) { return SymbolDisplayPartKind.aliasName; } + else if (flags & SymbolFlags.Alias) { return SymbolDisplayPartKind.aliasName; } + + + return SymbolDisplayPartKind.text; + } + } + + export function displayPart(text: string, kind: SymbolDisplayPartKind, symbol?: Symbol): SymbolDisplayPart { + return { + text: text, + kind: SymbolDisplayPartKind[kind] + }; + } + + export function spacePart() { + return displayPart(" ", SymbolDisplayPartKind.space); + } + + export function keywordPart(kind: SyntaxKind) { + return displayPart(tokenToString(kind), SymbolDisplayPartKind.keyword); + } + + export function punctuationPart(kind: SyntaxKind) { + return displayPart(tokenToString(kind), SymbolDisplayPartKind.punctuation); + } + + export function operatorPart(kind: SyntaxKind) { + return displayPart(tokenToString(kind), SymbolDisplayPartKind.operator); + } + + export function textOrKeywordPart(text: string) { + var kind = stringToToken(text); + return kind === undefined + ? textPart(text) + : keywordPart(kind); + } + + export function textPart(text: string) { + return displayPart(text, SymbolDisplayPartKind.text); + } + + export function lineBreakPart() { + return displayPart("\n", SymbolDisplayPartKind.lineBreak); + } + + export function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] { + writeDisplayParts(displayPartWriter); + let result = displayPartWriter.displayParts(); + displayPartWriter.clear(); + return result; + } + + export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] { + return mapToDisplayParts(writer => { + typechecker.getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); + }); + } + + export function symbolToDisplayParts(typeChecker: TypeChecker, symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): SymbolDisplayPart[] { + return mapToDisplayParts(writer => { + typeChecker.getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning, flags); + }); + } + + export function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] { + return mapToDisplayParts(writer => { + typechecker.getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags); + }); + } + + export function isJavaScript(fileName: string) { + return fileExtensionIs(fileName, ".js"); + } +} \ No newline at end of file diff --git a/lib/worker/child.ts b/lib/worker/child.ts index ef4f60016..35f54b765 100644 --- a/lib/worker/child.ts +++ b/lib/worker/child.ts @@ -1,6 +1,10 @@ ///ts:ref=globals /// ///ts:ref:generated +// setup typescript +import {makeTsGlobal} from "../typescript/makeTypeScriptGlobal"; +makeTsGlobal(); + import workerLib = require('./lib/workerLib');