From cbb948cddd190787b15eb66f0ed1448d0403ffbb Mon Sep 17 00:00:00 2001 From: Travis-CI Date: Sat, 20 Aug 2016 00:07:20 +0000 Subject: [PATCH] 2016-08-20 [ci skip] Version: 1.201608200007.1+a531b87b3c668f56a4140699f89b7fcc4160dfbc --- TypeScript | 2 +- bin/ntypescript.d.ts | 22 +++- bin/ntypescript.js | 115 ++++++++++++------ bin/typescript.d.ts | 22 +++- bin/typescript.js | 115 ++++++++++++------ kicktravis | 2 +- package.json | 2 +- src/compiler/checker.ts | 23 ++-- src/compiler/core.ts | 28 ++++- .../diagnosticInformationMap.generated.ts | 1 + .../diagnosticMessages.generated.json | 1 + src/compiler/diagnosticMessages.json | 4 + src/compiler/parser.ts | 3 + src/compiler/program.ts | 55 +++++---- src/compiler/utilities.ts | 5 + src/services/shims.ts | 2 +- 16 files changed, 275 insertions(+), 127 deletions(-) diff --git a/TypeScript b/TypeScript index a621c09..a531b87 160000 --- a/TypeScript +++ b/TypeScript @@ -1 +1 @@ -Subproject commit a621c09606ceeb3010a58cd0f48184a88370e613 +Subproject commit a531b87b3c668f56a4140699f89b7fcc4160dfbc diff --git a/bin/ntypescript.d.ts b/bin/ntypescript.d.ts index 41d91fd..afa4a18 100644 --- a/bin/ntypescript.d.ts +++ b/bin/ntypescript.d.ts @@ -2261,8 +2261,13 @@ declare namespace ts { * If no such value is found, the callback is applied to each element of array and undefined is returned. */ function forEach(array: T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined; - /** Like `forEach`, but assumes existence of array and fails if no truthy value is found. */ - function find(array: T[], callback: (element: T, index: number) => U | undefined): U; + /** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */ + function find(array: T[], predicate: (element: T, index: number) => boolean): T | undefined; + /** + * Returns the first truthy result of `callback`, or else fails. + * This is like `forEach`, but never returns undefined. + */ + function findMap(array: T[], callback: (element: T, index: number) => U | undefined): U; function contains(array: T[], value: T): boolean; function indexOf(array: T[], value: T): number; function indexOfAnyCharCode(text: string, charCodes: number[], start?: number): number; @@ -2457,6 +2462,8 @@ declare namespace ts { * List of supported extensions in order of file resolution precedence. */ const supportedTypeScriptExtensions: string[]; + /** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */ + const supportedTypescriptExtensionsForExtractExtension: string[]; const supportedJavascriptExtensions: string[]; function getSupportedExtensions(options?: CompilerOptions): string[]; function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions): boolean; @@ -2482,7 +2489,8 @@ declare namespace ts { */ function getNextLowestExtensionPriority(extensionPriority: ExtensionPriority): ExtensionPriority; function removeFileExtension(path: string): string; - function tryRemoveExtension(path: string, extension: string): string; + function tryRemoveExtension(path: string, extension: string): string | undefined; + function removeExtension(path: string, extension: string): string; function isJsxOrTsxExtension(ext: string): boolean; function changeExtension(path: T, newExtension: string): T; interface ObjectAllocator { @@ -2847,6 +2855,8 @@ declare namespace ts { function getLocalSymbolForExportDefault(symbol: Symbol): Symbol; function hasJavaScriptFileExtension(fileName: string): boolean; function hasTypeScriptFileExtension(fileName: string): boolean; + /** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */ + function tryExtractTypeScriptExtension(fileName: string): string | undefined; /** * Serialize an object graph into a JSON string. This is intended only for use on an acyclic graph * as the fallback implementation does not check for circular references by default. @@ -5821,6 +5831,12 @@ declare namespace ts { key: string; message: string; }; + An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead: { + code: number; + category: DiagnosticCategory; + key: string; + message: string; + }; Import_declaration_0_is_using_private_name_1: { code: number; category: DiagnosticCategory; diff --git a/bin/ntypescript.js b/bin/ntypescript.js index fb05d0a..cd814b0 100644 --- a/bin/ntypescript.js +++ b/bin/ntypescript.js @@ -1088,8 +1088,22 @@ var ts; return undefined; } ts.forEach = forEach; - /** Like `forEach`, but assumes existence of array and fails if no truthy value is found. */ - function find(array, callback) { + /** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */ + function find(array, predicate) { + for (var i = 0, len = array.length; i < len; i++) { + var value = array[i]; + if (predicate(value, i)) { + return value; + } + } + return undefined; + } + ts.find = find; + /** + * Returns the first truthy result of `callback`, or else fails. + * This is like `forEach`, but never returns undefined. + */ + function findMap(array, callback) { for (var i = 0, len = array.length; i < len; i++) { var result = callback(array[i], i); if (result) { @@ -1098,7 +1112,7 @@ var ts; } Debug.fail(); } - ts.find = find; + ts.findMap = findMap; function contains(array, value) { if (array) { for (var _i = 0, array_1 = array; _i < array_1.length; _i++) { @@ -2224,6 +2238,8 @@ var ts; * List of supported extensions in order of file resolution precedence. */ ts.supportedTypeScriptExtensions = [".ts", ".tsx", ".d.ts"]; + /** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */ + ts.supportedTypescriptExtensionsForExtractExtension = [".d.ts", ".ts", ".tsx"]; ts.supportedJavascriptExtensions = [".js", ".jsx"]; var allSupportedExtensions = ts.supportedTypeScriptExtensions.concat(ts.supportedJavascriptExtensions); function getSupportedExtensions(options) { @@ -2307,9 +2323,13 @@ var ts; } ts.removeFileExtension = removeFileExtension; function tryRemoveExtension(path, extension) { - return fileExtensionIs(path, extension) ? path.substring(0, path.length - extension.length) : undefined; + return fileExtensionIs(path, extension) ? removeExtension(path, extension) : undefined; } ts.tryRemoveExtension = tryRemoveExtension; + function removeExtension(path, extension) { + return path.substring(0, path.length - extension.length); + } + ts.removeExtension = removeExtension; function isJsxOrTsxExtension(ext) { return ext === ".jsx" || ext === ".tsx"; } @@ -5378,6 +5398,11 @@ var ts; return ts.forEach(ts.supportedTypeScriptExtensions, function (extension) { return ts.fileExtensionIs(fileName, extension); }); } ts.hasTypeScriptFileExtension = hasTypeScriptFileExtension; + /** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */ + function tryExtractTypeScriptExtension(fileName) { + return ts.find(ts.supportedTypescriptExtensionsForExtractExtension, function (extension) { return ts.fileExtensionIs(fileName, extension); }); + } + ts.tryExtractTypeScriptExtension = tryExtractTypeScriptExtension; /** * Replace each instance of non-ascii characters by one, two, three, or four escape sequences * representing the UTF-8 encoding of the character, and return the expanded char code list. @@ -6232,6 +6257,7 @@ var ts; Cannot_find_type_definition_file_for_0: { code: 2688, category: ts.DiagnosticCategory.Error, key: "Cannot_find_type_definition_file_for_0_2688", message: "Cannot find type definition file for '{0}'." }, Cannot_extend_an_interface_0_Did_you_mean_implements: { code: 2689, category: ts.DiagnosticCategory.Error, key: "Cannot_extend_an_interface_0_Did_you_mean_implements_2689", message: "Cannot extend an interface '{0}'. Did you mean 'implements'?" }, A_class_must_be_declared_after_its_base_class: { code: 2690, category: ts.DiagnosticCategory.Error, key: "A_class_must_be_declared_after_its_base_class_2690", message: "A class must be declared after its base class." }, + An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead: { code: 2691, category: ts.DiagnosticCategory.Error, key: "An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead_2691", message: "An import path cannot end with a '{0}' extension. Consider importing '{1}' instead." }, Import_declaration_0_is_using_private_name_1: { code: 4000, category: ts.DiagnosticCategory.Error, key: "Import_declaration_0_is_using_private_name_1_4000", message: "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_4002", message: "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_4004", message: "Type parameter '{0}' of exported interface has or is using private name '{1}'." }, @@ -11173,6 +11199,7 @@ var ts; * 6) - UnaryExpression[?yield] * 7) ~ UnaryExpression[?yield] * 8) ! UnaryExpression[?yield] + * 9) [+Await] await UnaryExpression[?yield] */ function parseSimpleUnaryExpression() { switch (token()) { @@ -11187,6 +11214,8 @@ var ts; return parseTypeOfExpression(); case 103 /* VoidKeyword */: return parseVoidExpression(); + case 119 /* AwaitKeyword */: + return parseAwaitExpression(); case 25 /* LessThanToken */: // This is modified UnaryExpression grammar in TypeScript // UnaryExpression (modified): @@ -17358,7 +17387,7 @@ var ts; } } function getDeclarationOfAliasSymbol(symbol) { - return ts.find(symbol.declarations, function (d) { return ts.isAliasSymbolDeclaration(d) ? d : undefined; }); + return ts.findMap(symbol.declarations, function (d) { return ts.isAliasSymbolDeclaration(d) ? d : undefined; }); } function getTargetOfImportEqualsDeclaration(node) { if (node.moduleReference.kind === 240 /* ExternalModuleReference */) { @@ -17662,7 +17691,14 @@ var ts; } if (moduleNotFoundError) { // report errors only if it was requested - error(moduleReferenceLiteral, moduleNotFoundError, moduleName); + var tsExtension = ts.tryExtractTypeScriptExtension(moduleName); + if (tsExtension) { + var diag = ts.Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead; + error(moduleReferenceLiteral, diag, tsExtension, ts.removeExtension(moduleName, tsExtension)); + } + else { + error(moduleReferenceLiteral, moduleNotFoundError, moduleName); + } } return undefined; } @@ -29282,12 +29318,7 @@ var ts; checkSignatureDeclaration(node); if (node.kind === 149 /* GetAccessor */) { if (!ts.isInAmbientContext(node) && ts.nodeIsPresent(node.body) && (node.flags & 32768 /* HasImplicitReturn */)) { - if (node.flags & 65536 /* HasExplicitReturn */) { - if (compilerOptions.noImplicitReturns) { - error(node.name, ts.Diagnostics.Not_all_code_paths_return_a_value); - } - } - else { + if (!(node.flags & 65536 /* HasExplicitReturn */)) { error(node.name, ts.Diagnostics.A_get_accessor_must_return_a_value); } } @@ -29316,7 +29347,10 @@ var ts; checkAccessorDeclarationTypesIdentical(node, otherAccessor, getThisTypeOfDeclaration, ts.Diagnostics.get_and_set_accessor_must_have_the_same_this_type); } } - getTypeOfAccessors(getSymbolOfNode(node)); + var returnType = getTypeOfAccessors(getSymbolOfNode(node)); + if (node.kind === 149 /* GetAccessor */) { + checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType); + } } if (node.parent.kind !== 171 /* ObjectLiteralExpression */) { checkSourceElement(node.body); @@ -45595,22 +45629,24 @@ var ts; * in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations. */ function loadModuleFromFile(candidate, extensions, failedLookupLocation, onlyRecordFailures, state) { - // First try to keep/add an extension: importing "./foo.ts" can be matched by a file "./foo.ts", and "./foo" by "./foo.d.ts" - var resolvedByAddingOrKeepingExtension = loadModuleFromFileWorker(candidate, extensions, failedLookupLocation, onlyRecordFailures, state); - if (resolvedByAddingOrKeepingExtension) { - return resolvedByAddingOrKeepingExtension; + // First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts" + var resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocation, onlyRecordFailures, state); + if (resolvedByAddingExtension) { + return resolvedByAddingExtension; } - // Then try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one, e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts" + // If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one; + // e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts" if (ts.hasJavaScriptFileExtension(candidate)) { var extensionless = ts.removeFileExtension(candidate); if (state.traceEnabled) { var extension = candidate.substring(extensionless.length); trace(state.host, ts.Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension); } - return loadModuleFromFileWorker(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state); + return tryAddingExtensions(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state); } } - function loadModuleFromFileWorker(candidate, extensions, failedLookupLocation, onlyRecordFailures, state) { + /** Try to return an existing file that adds one of the `extensions` to `candidate`. */ + function tryAddingExtensions(candidate, extensions, failedLookupLocation, onlyRecordFailures, state) { if (!onlyRecordFailures) { // check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing var directory = ts.getDirectoryPath(candidate); @@ -45618,25 +45654,24 @@ var ts; onlyRecordFailures = !directoryProbablyExists(directory, state.host); } } - return ts.forEach(extensions, tryLoad); - function tryLoad(ext) { - if (state.skipTsx && ts.isJsxOrTsxExtension(ext)) { - return undefined; - } - var fileName = ts.fileExtensionIs(candidate, ext) ? candidate : candidate + ext; - if (!onlyRecordFailures && state.host.fileExists(fileName)) { - if (state.traceEnabled) { - trace(state.host, ts.Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName); - } - return fileName; + return ts.forEach(extensions, function (ext) { + return !(state.skipTsx && ts.isJsxOrTsxExtension(ext)) && tryFile(candidate + ext, failedLookupLocation, onlyRecordFailures, state); + }); + } + /** Return the file if it exists. */ + function tryFile(fileName, failedLookupLocation, onlyRecordFailures, state) { + if (!onlyRecordFailures && state.host.fileExists(fileName)) { + if (state.traceEnabled) { + trace(state.host, ts.Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName); } - else { - if (state.traceEnabled) { - trace(state.host, ts.Diagnostics.File_0_does_not_exist, fileName); - } - failedLookupLocation.push(fileName); - return undefined; + return fileName; + } + else { + if (state.traceEnabled) { + trace(state.host, ts.Diagnostics.File_0_does_not_exist, fileName); } + failedLookupLocation.push(fileName); + return undefined; } } function loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocation, onlyRecordFailures, state) { @@ -45648,7 +45683,9 @@ var ts; } var typesFile = tryReadTypesSection(packageJsonPath, candidate, state); if (typesFile) { - var result = loadModuleFromFile(typesFile, extensions, failedLookupLocation, !directoryProbablyExists(ts.getDirectoryPath(typesFile), state.host), state); + var onlyRecordFailures_1 = !directoryProbablyExists(ts.getDirectoryPath(typesFile), state.host); + // The package.json "typings" property must specify the file with extension, so just try that exact filename. + var result = tryFile(typesFile, failedLookupLocation, onlyRecordFailures_1, state); if (result) { return result; } @@ -62056,7 +62093,7 @@ var TypeScript; // 'toolsVersion' gets consumed by the managed side, so it's not unused. // TODO: it should be moved into a namespace though. /* @internal */ -var toolsVersion = "1.9"; +var toolsVersion = "2.1"; /* tslint:enable:no-unused-variable */ /** * Sample: add a new utility function diff --git a/bin/typescript.d.ts b/bin/typescript.d.ts index 23c15d3..c1c1edf 100644 --- a/bin/typescript.d.ts +++ b/bin/typescript.d.ts @@ -2261,8 +2261,13 @@ declare namespace ts { * If no such value is found, the callback is applied to each element of array and undefined is returned. */ function forEach(array: T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined; - /** Like `forEach`, but assumes existence of array and fails if no truthy value is found. */ - function find(array: T[], callback: (element: T, index: number) => U | undefined): U; + /** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */ + function find(array: T[], predicate: (element: T, index: number) => boolean): T | undefined; + /** + * Returns the first truthy result of `callback`, or else fails. + * This is like `forEach`, but never returns undefined. + */ + function findMap(array: T[], callback: (element: T, index: number) => U | undefined): U; function contains(array: T[], value: T): boolean; function indexOf(array: T[], value: T): number; function indexOfAnyCharCode(text: string, charCodes: number[], start?: number): number; @@ -2457,6 +2462,8 @@ declare namespace ts { * List of supported extensions in order of file resolution precedence. */ const supportedTypeScriptExtensions: string[]; + /** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */ + const supportedTypescriptExtensionsForExtractExtension: string[]; const supportedJavascriptExtensions: string[]; function getSupportedExtensions(options?: CompilerOptions): string[]; function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions): boolean; @@ -2482,7 +2489,8 @@ declare namespace ts { */ function getNextLowestExtensionPriority(extensionPriority: ExtensionPriority): ExtensionPriority; function removeFileExtension(path: string): string; - function tryRemoveExtension(path: string, extension: string): string; + function tryRemoveExtension(path: string, extension: string): string | undefined; + function removeExtension(path: string, extension: string): string; function isJsxOrTsxExtension(ext: string): boolean; function changeExtension(path: T, newExtension: string): T; interface ObjectAllocator { @@ -2847,6 +2855,8 @@ declare namespace ts { function getLocalSymbolForExportDefault(symbol: Symbol): Symbol; function hasJavaScriptFileExtension(fileName: string): boolean; function hasTypeScriptFileExtension(fileName: string): boolean; + /** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */ + function tryExtractTypeScriptExtension(fileName: string): string | undefined; /** * Serialize an object graph into a JSON string. This is intended only for use on an acyclic graph * as the fallback implementation does not check for circular references by default. @@ -5821,6 +5831,12 @@ declare namespace ts { key: string; message: string; }; + An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead: { + code: number; + category: DiagnosticCategory; + key: string; + message: string; + }; Import_declaration_0_is_using_private_name_1: { code: number; category: DiagnosticCategory; diff --git a/bin/typescript.js b/bin/typescript.js index d4ca7f3..1b40af3 100644 --- a/bin/typescript.js +++ b/bin/typescript.js @@ -1088,8 +1088,22 @@ var ts; return undefined; } ts.forEach = forEach; - /** Like `forEach`, but assumes existence of array and fails if no truthy value is found. */ - function find(array, callback) { + /** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */ + function find(array, predicate) { + for (var i = 0, len = array.length; i < len; i++) { + var value = array[i]; + if (predicate(value, i)) { + return value; + } + } + return undefined; + } + ts.find = find; + /** + * Returns the first truthy result of `callback`, or else fails. + * This is like `forEach`, but never returns undefined. + */ + function findMap(array, callback) { for (var i = 0, len = array.length; i < len; i++) { var result = callback(array[i], i); if (result) { @@ -1098,7 +1112,7 @@ var ts; } Debug.fail(); } - ts.find = find; + ts.findMap = findMap; function contains(array, value) { if (array) { for (var _i = 0, array_1 = array; _i < array_1.length; _i++) { @@ -2224,6 +2238,8 @@ var ts; * List of supported extensions in order of file resolution precedence. */ ts.supportedTypeScriptExtensions = [".ts", ".tsx", ".d.ts"]; + /** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */ + ts.supportedTypescriptExtensionsForExtractExtension = [".d.ts", ".ts", ".tsx"]; ts.supportedJavascriptExtensions = [".js", ".jsx"]; var allSupportedExtensions = ts.supportedTypeScriptExtensions.concat(ts.supportedJavascriptExtensions); function getSupportedExtensions(options) { @@ -2307,9 +2323,13 @@ var ts; } ts.removeFileExtension = removeFileExtension; function tryRemoveExtension(path, extension) { - return fileExtensionIs(path, extension) ? path.substring(0, path.length - extension.length) : undefined; + return fileExtensionIs(path, extension) ? removeExtension(path, extension) : undefined; } ts.tryRemoveExtension = tryRemoveExtension; + function removeExtension(path, extension) { + return path.substring(0, path.length - extension.length); + } + ts.removeExtension = removeExtension; function isJsxOrTsxExtension(ext) { return ext === ".jsx" || ext === ".tsx"; } @@ -5378,6 +5398,11 @@ var ts; return ts.forEach(ts.supportedTypeScriptExtensions, function (extension) { return ts.fileExtensionIs(fileName, extension); }); } ts.hasTypeScriptFileExtension = hasTypeScriptFileExtension; + /** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */ + function tryExtractTypeScriptExtension(fileName) { + return ts.find(ts.supportedTypescriptExtensionsForExtractExtension, function (extension) { return ts.fileExtensionIs(fileName, extension); }); + } + ts.tryExtractTypeScriptExtension = tryExtractTypeScriptExtension; /** * Replace each instance of non-ascii characters by one, two, three, or four escape sequences * representing the UTF-8 encoding of the character, and return the expanded char code list. @@ -6232,6 +6257,7 @@ var ts; Cannot_find_type_definition_file_for_0: { code: 2688, category: ts.DiagnosticCategory.Error, key: "Cannot_find_type_definition_file_for_0_2688", message: "Cannot find type definition file for '{0}'." }, Cannot_extend_an_interface_0_Did_you_mean_implements: { code: 2689, category: ts.DiagnosticCategory.Error, key: "Cannot_extend_an_interface_0_Did_you_mean_implements_2689", message: "Cannot extend an interface '{0}'. Did you mean 'implements'?" }, A_class_must_be_declared_after_its_base_class: { code: 2690, category: ts.DiagnosticCategory.Error, key: "A_class_must_be_declared_after_its_base_class_2690", message: "A class must be declared after its base class." }, + An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead: { code: 2691, category: ts.DiagnosticCategory.Error, key: "An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead_2691", message: "An import path cannot end with a '{0}' extension. Consider importing '{1}' instead." }, Import_declaration_0_is_using_private_name_1: { code: 4000, category: ts.DiagnosticCategory.Error, key: "Import_declaration_0_is_using_private_name_1_4000", message: "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_4002", message: "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_4004", message: "Type parameter '{0}' of exported interface has or is using private name '{1}'." }, @@ -11173,6 +11199,7 @@ var ts; * 6) - UnaryExpression[?yield] * 7) ~ UnaryExpression[?yield] * 8) ! UnaryExpression[?yield] + * 9) [+Await] await UnaryExpression[?yield] */ function parseSimpleUnaryExpression() { switch (token()) { @@ -11187,6 +11214,8 @@ var ts; return parseTypeOfExpression(); case 103 /* VoidKeyword */: return parseVoidExpression(); + case 119 /* AwaitKeyword */: + return parseAwaitExpression(); case 25 /* LessThanToken */: // This is modified UnaryExpression grammar in TypeScript // UnaryExpression (modified): @@ -17358,7 +17387,7 @@ var ts; } } function getDeclarationOfAliasSymbol(symbol) { - return ts.find(symbol.declarations, function (d) { return ts.isAliasSymbolDeclaration(d) ? d : undefined; }); + return ts.findMap(symbol.declarations, function (d) { return ts.isAliasSymbolDeclaration(d) ? d : undefined; }); } function getTargetOfImportEqualsDeclaration(node) { if (node.moduleReference.kind === 240 /* ExternalModuleReference */) { @@ -17662,7 +17691,14 @@ var ts; } if (moduleNotFoundError) { // report errors only if it was requested - error(moduleReferenceLiteral, moduleNotFoundError, moduleName); + var tsExtension = ts.tryExtractTypeScriptExtension(moduleName); + if (tsExtension) { + var diag = ts.Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead; + error(moduleReferenceLiteral, diag, tsExtension, ts.removeExtension(moduleName, tsExtension)); + } + else { + error(moduleReferenceLiteral, moduleNotFoundError, moduleName); + } } return undefined; } @@ -29282,12 +29318,7 @@ var ts; checkSignatureDeclaration(node); if (node.kind === 149 /* GetAccessor */) { if (!ts.isInAmbientContext(node) && ts.nodeIsPresent(node.body) && (node.flags & 32768 /* HasImplicitReturn */)) { - if (node.flags & 65536 /* HasExplicitReturn */) { - if (compilerOptions.noImplicitReturns) { - error(node.name, ts.Diagnostics.Not_all_code_paths_return_a_value); - } - } - else { + if (!(node.flags & 65536 /* HasExplicitReturn */)) { error(node.name, ts.Diagnostics.A_get_accessor_must_return_a_value); } } @@ -29316,7 +29347,10 @@ var ts; checkAccessorDeclarationTypesIdentical(node, otherAccessor, getThisTypeOfDeclaration, ts.Diagnostics.get_and_set_accessor_must_have_the_same_this_type); } } - getTypeOfAccessors(getSymbolOfNode(node)); + var returnType = getTypeOfAccessors(getSymbolOfNode(node)); + if (node.kind === 149 /* GetAccessor */) { + checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType); + } } if (node.parent.kind !== 171 /* ObjectLiteralExpression */) { checkSourceElement(node.body); @@ -45595,22 +45629,24 @@ var ts; * in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations. */ function loadModuleFromFile(candidate, extensions, failedLookupLocation, onlyRecordFailures, state) { - // First try to keep/add an extension: importing "./foo.ts" can be matched by a file "./foo.ts", and "./foo" by "./foo.d.ts" - var resolvedByAddingOrKeepingExtension = loadModuleFromFileWorker(candidate, extensions, failedLookupLocation, onlyRecordFailures, state); - if (resolvedByAddingOrKeepingExtension) { - return resolvedByAddingOrKeepingExtension; + // First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts" + var resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocation, onlyRecordFailures, state); + if (resolvedByAddingExtension) { + return resolvedByAddingExtension; } - // Then try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one, e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts" + // If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one; + // e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts" if (ts.hasJavaScriptFileExtension(candidate)) { var extensionless = ts.removeFileExtension(candidate); if (state.traceEnabled) { var extension = candidate.substring(extensionless.length); trace(state.host, ts.Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension); } - return loadModuleFromFileWorker(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state); + return tryAddingExtensions(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state); } } - function loadModuleFromFileWorker(candidate, extensions, failedLookupLocation, onlyRecordFailures, state) { + /** Try to return an existing file that adds one of the `extensions` to `candidate`. */ + function tryAddingExtensions(candidate, extensions, failedLookupLocation, onlyRecordFailures, state) { if (!onlyRecordFailures) { // check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing var directory = ts.getDirectoryPath(candidate); @@ -45618,25 +45654,24 @@ var ts; onlyRecordFailures = !directoryProbablyExists(directory, state.host); } } - return ts.forEach(extensions, tryLoad); - function tryLoad(ext) { - if (state.skipTsx && ts.isJsxOrTsxExtension(ext)) { - return undefined; - } - var fileName = ts.fileExtensionIs(candidate, ext) ? candidate : candidate + ext; - if (!onlyRecordFailures && state.host.fileExists(fileName)) { - if (state.traceEnabled) { - trace(state.host, ts.Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName); - } - return fileName; + return ts.forEach(extensions, function (ext) { + return !(state.skipTsx && ts.isJsxOrTsxExtension(ext)) && tryFile(candidate + ext, failedLookupLocation, onlyRecordFailures, state); + }); + } + /** Return the file if it exists. */ + function tryFile(fileName, failedLookupLocation, onlyRecordFailures, state) { + if (!onlyRecordFailures && state.host.fileExists(fileName)) { + if (state.traceEnabled) { + trace(state.host, ts.Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName); } - else { - if (state.traceEnabled) { - trace(state.host, ts.Diagnostics.File_0_does_not_exist, fileName); - } - failedLookupLocation.push(fileName); - return undefined; + return fileName; + } + else { + if (state.traceEnabled) { + trace(state.host, ts.Diagnostics.File_0_does_not_exist, fileName); } + failedLookupLocation.push(fileName); + return undefined; } } function loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocation, onlyRecordFailures, state) { @@ -45648,7 +45683,9 @@ var ts; } var typesFile = tryReadTypesSection(packageJsonPath, candidate, state); if (typesFile) { - var result = loadModuleFromFile(typesFile, extensions, failedLookupLocation, !directoryProbablyExists(ts.getDirectoryPath(typesFile), state.host), state); + var onlyRecordFailures_1 = !directoryProbablyExists(ts.getDirectoryPath(typesFile), state.host); + // The package.json "typings" property must specify the file with extension, so just try that exact filename. + var result = tryFile(typesFile, failedLookupLocation, onlyRecordFailures_1, state); if (result) { return result; } @@ -62056,7 +62093,7 @@ var TypeScript; // 'toolsVersion' gets consumed by the managed side, so it's not unused. // TODO: it should be moved into a namespace though. /* @internal */ -var toolsVersion = "1.9"; +var toolsVersion = "2.1"; /* tslint:enable:no-unused-variable */ /** * Sample: add a new utility function diff --git a/kicktravis b/kicktravis index 0f1db73..850e3b3 100644 --- a/kicktravis +++ b/kicktravis @@ -1 +1 @@ -2016-08-19 [ci skip] Version: 1.201608190006.1+a621c09606ceeb3010a58cd0f48184a88370e613 +2016-08-20 [ci skip] Version: 1.201608200007.1+a531b87b3c668f56a4140699f89b7fcc4160dfbc diff --git a/package.json b/package.json index 360b06a..9084eee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ntypescript", - "version": "1.201608190006.1+a621c09606ceeb3010a58cd0f48184a88370e613", + "version": "1.201608200007.1+a531b87b3c668f56a4140699f89b7fcc4160dfbc", "description": "A nicer version of microsoft/typescript packaged and released for API developers", "main": "./bin/ntypescript.js", "bin": { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f7d0fd3..8568cd5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1024,7 +1024,7 @@ namespace ts { } function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration { - return find(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined); + return findMap(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined); } function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol { @@ -1361,7 +1361,14 @@ namespace ts { if (moduleNotFoundError) { // report errors only if it was requested - error(moduleReferenceLiteral, moduleNotFoundError, moduleName); + const tsExtension = tryExtractTypeScriptExtension(moduleName); + if (tsExtension) { + const diag = Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead; + error(moduleReferenceLiteral, diag, tsExtension, removeExtension(moduleName, tsExtension)); + } + else { + error(moduleReferenceLiteral, moduleNotFoundError, moduleName); + } } return undefined; } @@ -14119,12 +14126,7 @@ namespace ts { checkSignatureDeclaration(node); if (node.kind === SyntaxKind.GetAccessor) { if (!isInAmbientContext(node) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { - if (node.flags & NodeFlags.HasExplicitReturn) { - if (compilerOptions.noImplicitReturns) { - error(node.name, Diagnostics.Not_all_code_paths_return_a_value); - } - } - else { + if (!(node.flags & NodeFlags.HasExplicitReturn)) { error(node.name, Diagnostics.A_get_accessor_must_return_a_value); } } @@ -14154,7 +14156,10 @@ namespace ts { checkAccessorDeclarationTypesIdentical(node, otherAccessor, getThisTypeOfDeclaration, Diagnostics.get_and_set_accessor_must_have_the_same_this_type); } } - getTypeOfAccessors(getSymbolOfNode(node)); + const returnType = getTypeOfAccessors(getSymbolOfNode(node)); + if (node.kind === SyntaxKind.GetAccessor) { + checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType); + } } if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) { checkSourceElement(node.body); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 4034192..27b27bc 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -113,8 +113,22 @@ namespace ts { return undefined; } - /** Like `forEach`, but assumes existence of array and fails if no truthy value is found. */ - export function find(array: T[], callback: (element: T, index: number) => U | undefined): U { + /** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */ + export function find(array: T[], predicate: (element: T, index: number) => boolean): T | undefined { + for (let i = 0, len = array.length; i < len; i++) { + const value = array[i]; + if (predicate(value, i)) { + return value; + } + } + return undefined; + } + + /** + * Returns the first truthy result of `callback`, or else fails. + * This is like `forEach`, but never returns undefined. + */ + export function findMap(array: T[], callback: (element: T, index: number) => U | undefined): U { for (let i = 0, len = array.length; i < len; i++) { const result = callback(array[i], i); if (result) { @@ -1315,6 +1329,8 @@ namespace ts { * List of supported extensions in order of file resolution precedence. */ export const supportedTypeScriptExtensions = [".ts", ".tsx", ".d.ts"]; + /** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */ + export const supportedTypescriptExtensionsForExtractExtension = [".d.ts", ".ts", ".tsx"]; export const supportedJavascriptExtensions = [".js", ".jsx"]; const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions); @@ -1397,8 +1413,12 @@ namespace ts { return path; } - export function tryRemoveExtension(path: string, extension: string): string { - return fileExtensionIs(path, extension) ? path.substring(0, path.length - extension.length) : undefined; + export function tryRemoveExtension(path: string, extension: string): string | undefined { + return fileExtensionIs(path, extension) ? removeExtension(path, extension) : undefined; + } + + export function removeExtension(path: string, extension: string): string { + return path.substring(0, path.length - extension.length); } export function isJsxOrTsxExtension(ext: string): boolean { diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index b1e1259..81f95f2 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -491,6 +491,7 @@ namespace ts { Cannot_find_type_definition_file_for_0: { code: 2688, category: DiagnosticCategory.Error, key: "Cannot_find_type_definition_file_for_0_2688", message: "Cannot find type definition file for '{0}'." }, Cannot_extend_an_interface_0_Did_you_mean_implements: { code: 2689, category: DiagnosticCategory.Error, key: "Cannot_extend_an_interface_0_Did_you_mean_implements_2689", message: "Cannot extend an interface '{0}'. Did you mean 'implements'?" }, A_class_must_be_declared_after_its_base_class: { code: 2690, category: DiagnosticCategory.Error, key: "A_class_must_be_declared_after_its_base_class_2690", message: "A class must be declared after its base class." }, + An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead: { code: 2691, category: DiagnosticCategory.Error, key: "An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead_2691", message: "An import path cannot end with a '{0}' extension. Consider importing '{1}' instead." }, Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import_declaration_0_is_using_private_name_1_4000", message: "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_4002", message: "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_4004", message: "Type parameter '{0}' of exported interface has or is using private name '{1}'." }, diff --git a/src/compiler/diagnosticMessages.generated.json b/src/compiler/diagnosticMessages.generated.json index 436dcb8..f827a6c 100644 --- a/src/compiler/diagnosticMessages.generated.json +++ b/src/compiler/diagnosticMessages.generated.json @@ -487,6 +487,7 @@ "Cannot_find_type_definition_file_for_0_2688" : "Cannot find type definition file for '{0}'.", "Cannot_extend_an_interface_0_Did_you_mean_implements_2689" : "Cannot extend an interface '{0}'. Did you mean 'implements'?", "A_class_must_be_declared_after_its_base_class_2690" : "A class must be declared after its base class.", + "An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead_2691" : "An import path cannot end with a '{0}' extension. Consider importing '{1}' instead.", "Import_declaration_0_is_using_private_name_1_4000" : "Import declaration '{0}' is using private name '{1}'.", "Type_parameter_0_of_exported_class_has_or_is_using_private_name_1_4002" : "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_4004" : "Type parameter '{0}' of exported interface has or is using private name '{1}'.", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index c6a3698..6210a20 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1951,6 +1951,10 @@ "category": "Error", "code": 2690 }, + "An import path cannot end with a '{0}' extension. Consider importing '{1}' instead.": { + "category": "Error", + "code": 2691 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", "code": 4000 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b054513..035b742 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3417,6 +3417,7 @@ namespace ts { * 6) - UnaryExpression[?yield] * 7) ~ UnaryExpression[?yield] * 8) ! UnaryExpression[?yield] + * 9) [+Await] await UnaryExpression[?yield] */ function parseSimpleUnaryExpression(): UnaryExpression { switch (token()) { @@ -3431,6 +3432,8 @@ namespace ts { return parseTypeOfExpression(); case SyntaxKind.VoidKeyword: return parseVoidExpression(); + case SyntaxKind.AwaitKeyword: + return parseAwaitExpression(); case SyntaxKind.LessThanToken: // This is modified UnaryExpression grammar in TypeScript // UnaryExpression (modified): diff --git a/src/compiler/program.ts b/src/compiler/program.ts index e732fe2..afd2dda 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -661,24 +661,27 @@ namespace ts { * @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary * in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations. */ - function loadModuleFromFile(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string { - // First try to keep/add an extension: importing "./foo.ts" can be matched by a file "./foo.ts", and "./foo" by "./foo.d.ts" - const resolvedByAddingOrKeepingExtension = loadModuleFromFileWorker(candidate, extensions, failedLookupLocation, onlyRecordFailures, state); - if (resolvedByAddingOrKeepingExtension) { - return resolvedByAddingOrKeepingExtension; + function loadModuleFromFile(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined { + // First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts" + const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocation, onlyRecordFailures, state); + if (resolvedByAddingExtension) { + return resolvedByAddingExtension; } - // Then try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one, e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts" + + // If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one; + // e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts" if (hasJavaScriptFileExtension(candidate)) { const extensionless = removeFileExtension(candidate); if (state.traceEnabled) { const extension = candidate.substring(extensionless.length); trace(state.host, Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension); } - return loadModuleFromFileWorker(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state); + return tryAddingExtensions(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state); } } - function loadModuleFromFileWorker(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string { + /** Try to return an existing file that adds one of the `extensions` to `candidate`. */ + function tryAddingExtensions(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined { if (!onlyRecordFailures) { // check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing const directory = getDirectoryPath(candidate); @@ -686,26 +689,24 @@ namespace ts { onlyRecordFailures = !directoryProbablyExists(directory, state.host); } } - return forEach(extensions, tryLoad); + return forEach(extensions, ext => + !(state.skipTsx && isJsxOrTsxExtension(ext)) && tryFile(candidate + ext, failedLookupLocation, onlyRecordFailures, state)); + } - function tryLoad(ext: string): string { - if (state.skipTsx && isJsxOrTsxExtension(ext)) { - return undefined; - } - const fileName = fileExtensionIs(candidate, ext) ? candidate : candidate + ext; - if (!onlyRecordFailures && state.host.fileExists(fileName)) { - if (state.traceEnabled) { - trace(state.host, Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName); - } - return fileName; + /** Return the file if it exists. */ + function tryFile(fileName: string, failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined { + if (!onlyRecordFailures && state.host.fileExists(fileName)) { + if (state.traceEnabled) { + trace(state.host, Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName); } - else { - if (state.traceEnabled) { - trace(state.host, Diagnostics.File_0_does_not_exist, fileName); - } - failedLookupLocation.push(fileName); - return undefined; + return fileName; + } + else { + if (state.traceEnabled) { + trace(state.host, Diagnostics.File_0_does_not_exist, fileName); } + failedLookupLocation.push(fileName); + return undefined; } } @@ -718,7 +719,9 @@ namespace ts { } const typesFile = tryReadTypesSection(packageJsonPath, candidate, state); if (typesFile) { - const result = loadModuleFromFile(typesFile, extensions, failedLookupLocation, !directoryProbablyExists(getDirectoryPath(typesFile), state.host), state); + const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(typesFile), state.host); + // The package.json "typings" property must specify the file with extension, so just try that exact filename. + const result = tryFile(typesFile, failedLookupLocation, onlyRecordFailures, state); if (result) { return result; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0a1f432..870df4a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2694,6 +2694,11 @@ namespace ts { return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension)); } + /** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */ + export function tryExtractTypeScriptExtension(fileName: string): string | undefined { + return find(supportedTypescriptExtensionsForExtractExtension, extension => fileExtensionIs(fileName, extension)); + } + /** * Replace each instance of non-ascii characters by one, two, three, or four escape sequences * representing the UTF-8 encoding of the character, and return the expanded char code list. diff --git a/src/services/shims.ts b/src/services/shims.ts index ff57dd9..9a581ed 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -1203,6 +1203,6 @@ namespace TypeScript.Services { // TODO: it should be moved into a namespace though. /* @internal */ -const toolsVersion = "1.9"; +const toolsVersion = "2.1"; /* tslint:enable:no-unused-variable */