diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c2865280f44..51b232712e6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,12 +47,33 @@ e.g. to run all compiler baseline tests: jake runtests tests=compiler ``` -or to run specifc test: `tests\cases\compiler\2dArrays.ts` +or to run a specific test: `tests\cases\compiler\2dArrays.ts` ```Shell jake runtests tests=2dArrays ``` +## Debugging the tests + +To debug the tests, invoke the runtests-browser using jake. +You will probably only want to debug one test at a time: + +```Shell +jake runtests-browser tests=2dArrays +``` + +You can specify which browser to use for debugging. Currently Chrome and IE are supported: + +```Shell +jake runtests-browser tests=2dArrays browser=chrome +``` + +You can debug with VS Code or Node instead with `jake runtests debug=true`: + +```Shell +jake runtests tests=2dArrays debug=true +``` + ## Adding a Test To add a new testcase, simply place a `.ts` file in `tests\cases\compiler` containing code that exemplifies the bugfix or change you are making. diff --git a/lib/lib.core.d.ts b/lib/lib.core.d.ts index b588c9fdb77..50fd8a8e495 100644 --- a/lib/lib.core.d.ts +++ b/lib/lib.core.d.ts @@ -1225,7 +1225,7 @@ interface ArrayBuffer { interface ArrayBufferConstructor { prototype: ArrayBuffer; new (byteLength: number): ArrayBuffer; - isView(arg: any): boolean; + isView(arg: any): arg is ArrayBufferView; } declare var ArrayBuffer: ArrayBufferConstructor; diff --git a/lib/lib.core.es6.d.ts b/lib/lib.core.es6.d.ts index 6d6a68559f8..857f5957a45 100644 --- a/lib/lib.core.es6.d.ts +++ b/lib/lib.core.es6.d.ts @@ -1225,7 +1225,7 @@ interface ArrayBuffer { interface ArrayBufferConstructor { prototype: ArrayBuffer; new (byteLength: number): ArrayBuffer; - isView(arg: any): boolean; + isView(arg: any): arg is ArrayBufferView; } declare var ArrayBuffer: ArrayBufferConstructor; diff --git a/lib/lib.d.ts b/lib/lib.d.ts index 40a29796586..4fe0d9cf547 100644 --- a/lib/lib.d.ts +++ b/lib/lib.d.ts @@ -1225,7 +1225,7 @@ interface ArrayBuffer { interface ArrayBufferConstructor { prototype: ArrayBuffer; new (byteLength: number): ArrayBuffer; - isView(arg: any): boolean; + isView(arg: any): arg is ArrayBufferView; } declare var ArrayBuffer: ArrayBufferConstructor; diff --git a/lib/lib.es6.d.ts b/lib/lib.es6.d.ts index a7bf8f05076..4adbf2aa7a9 100644 --- a/lib/lib.es6.d.ts +++ b/lib/lib.es6.d.ts @@ -1225,7 +1225,7 @@ interface ArrayBuffer { interface ArrayBufferConstructor { prototype: ArrayBuffer; new (byteLength: number): ArrayBuffer; - isView(arg: any): boolean; + isView(arg: any): arg is ArrayBufferView; } declare var ArrayBuffer: ArrayBufferConstructor; diff --git a/lib/tsc.js b/lib/tsc.js index ed982c2d941..a38cb65a098 100644 --- a/lib/tsc.js +++ b/lib/tsc.js @@ -630,6 +630,9 @@ var ts; } ts.getRelativePathToDirectoryOrUrl = getRelativePathToDirectoryOrUrl; function getBaseFileName(path) { + if (!path) { + return undefined; + } var i = path.lastIndexOf(ts.directorySeparator); return i < 0 ? path : path.substring(i + 1); } @@ -654,6 +657,19 @@ var ts; ts.fileExtensionIs = fileExtensionIs; ts.supportedExtensions = [".ts", ".tsx", ".d.ts"]; ts.supportedJsExtensions = ts.supportedExtensions.concat(".js", ".jsx"); + function isSupportedSourceFileName(fileName) { + if (!fileName) { + return false; + } + for (var _i = 0; _i < ts.supportedExtensions.length; _i++) { + var extension = ts.supportedExtensions[_i]; + if (fileExtensionIs(fileName, extension)) { + return true; + } + } + return false; + } + ts.isSupportedSourceFileName = isSupportedSourceFileName; var extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"]; function removeFileExtension(path) { for (var _i = 0; _i < extensionsToRemove.length; _i++) { @@ -730,6 +746,16 @@ var ts; } Debug.fail = fail; })(Debug = ts.Debug || (ts.Debug = {})); + function copyListRemovingItem(item, list) { + var copiedList = []; + for (var i = 0, len = list.length; i < len; i++) { + if (list[i] !== item) { + copiedList.push(list[i]); + } + } + return copiedList; + } + ts.copyListRemovingItem = copyListRemovingItem; })(ts || (ts = {})); var ts; (function (ts) { @@ -868,6 +894,76 @@ var ts; var _fs = require("fs"); var _path = require("path"); var _os = require("os"); + function createWatchedFileSet(interval, chunkSize) { + if (interval === void 0) { interval = 2500; } + if (chunkSize === void 0) { chunkSize = 30; } + var watchedFiles = []; + var nextFileToCheck = 0; + var watchTimer; + function getModifiedTime(fileName) { + return _fs.statSync(fileName).mtime; + } + function poll(checkedIndex) { + var watchedFile = watchedFiles[checkedIndex]; + if (!watchedFile) { + return; + } + _fs.stat(watchedFile.fileName, function (err, stats) { + if (err) { + watchedFile.callback(watchedFile.fileName); + } + else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) { + watchedFile.mtime = getModifiedTime(watchedFile.fileName); + watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0); + } + }); + } + function startWatchTimer() { + watchTimer = setInterval(function () { + var count = 0; + var nextToCheck = nextFileToCheck; + var firstCheck = -1; + while ((count < chunkSize) && (nextToCheck !== firstCheck)) { + poll(nextToCheck); + if (firstCheck < 0) { + firstCheck = nextToCheck; + } + nextToCheck++; + if (nextToCheck === watchedFiles.length) { + nextToCheck = 0; + } + count++; + } + nextFileToCheck = nextToCheck; + }, interval); + } + function addFile(fileName, callback) { + var file = { + fileName: fileName, + callback: callback, + mtime: getModifiedTime(fileName) + }; + watchedFiles.push(file); + if (watchedFiles.length === 1) { + startWatchTimer(); + } + return file; + } + function removeFile(file) { + watchedFiles = ts.copyListRemovingItem(file, watchedFiles); + } + return { + getModifiedTime: getModifiedTime, + poll: poll, + startWatchTimer: startWatchTimer, + addFile: addFile, + removeFile: removeFile + }; + } + var watchedFileSet = createWatchedFileSet(); + function isNode4OrLater() { + return parseInt(process.version.charAt(1)) >= 4; + } var platform = _os.platform(); var useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin"; function readFile(fileName, encoding) { @@ -948,20 +1044,21 @@ var ts; 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.getTime() === 0) { - callback(fileName, true); - return; - } - if (+curr.mtime <= +prev.mtime) { - return; - } - callback(fileName, false); + if (isNode4OrLater()) { + return _fs.watch(fileName, function (eventName, relativeFileName) { return callback(fileName); }); } + var watchedFile = watchedFileSet.addFile(fileName, callback); + return { + close: function () { return watchedFileSet.removeFile(watchedFile); } + }; + }, + watchDirectory: function (path, callback, recursive) { + return _fs.watch(path, { persisten: true, recursive: !!recursive }, function (eventName, relativeFileName) { + if (eventName === "rename") { + callback(!relativeFileName ? relativeFileName : ts.normalizePath(ts.combinePaths(path, relativeFileName))); + } + ; + }); }, resolvePath: function (path) { return _path.resolve(path); @@ -1414,7 +1511,6 @@ var ts; Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2: { code: 2515, category: ts.DiagnosticCategory.Error, key: "Non-abstract class '{0}' does not implement inherited abstract member '{1}' from class '{2}'." }, All_declarations_of_an_abstract_method_must_be_consecutive: { code: 2516, category: ts.DiagnosticCategory.Error, key: "All declarations of an abstract method must be consecutive." }, Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type: { code: 2517, category: ts.DiagnosticCategory.Error, key: "Cannot assign an abstract constructor type to a non-abstract constructor type." }, - Only_an_ambient_class_can_be_merged_with_an_interface: { code: 2518, category: ts.DiagnosticCategory.Error, key: "Only an ambient class can be merged with an interface." }, Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions: { code: 2520, category: ts.DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions." }, Expression_resolves_to_variable_declaration_0_that_compiler_uses_to_support_async_functions: { code: 2521, category: ts.DiagnosticCategory.Error, key: "Expression resolves to variable declaration '{0}' that compiler uses to support async functions." }, The_arguments_object_cannot_be_referenced_in_an_async_arrow_function_Consider_using_a_standard_async_function_expression: { code: 2522, category: ts.DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an async arrow function. Consider using a standard async function expression." }, @@ -4615,7 +4711,8 @@ var ts; return expression.kind === 168 && expression.expression.kind === 69 && expression.expression.text === "require" && - expression.arguments.length === 1; + expression.arguments.length === 1 && + expression.arguments[0].kind === 9; } ts.isRequireCall = isRequireCall; function isExportsPropertyAssignment(expression) { @@ -5756,6 +5853,16 @@ var ts; } } ts.getTypeParameterOwner = getTypeParameterOwner; + function arrayStructurallyIsEqualTo(array1, array2) { + if (!array1 || !array2) { + return false; + } + if (array1.length !== array2.length) { + return false; + } + return ts.arrayIsEqualTo(array1.sort(), array2.sort()); + } + ts.arrayStructurallyIsEqualTo = arrayStructurallyIsEqualTo; })(ts || (ts = {})); var ts; (function (ts) { @@ -13372,7 +13479,9 @@ var ts; function getSignatureFromDeclaration(declaration) { var links = getNodeLinks(declaration); if (!links.resolvedSignature) { - var classType = declaration.kind === 144 ? getDeclaredTypeOfClassOrInterface(declaration.parent.symbol) : undefined; + var classType = declaration.kind === 144 ? + getDeclaredTypeOfClassOrInterface(getMergedSymbol(declaration.parent.symbol)) + : undefined; var typeParameters = classType ? classType.localTypeParameters : declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) : undefined; var parameters = []; @@ -17184,83 +17293,83 @@ var ts; } } function getEffectiveDecoratorFirstArgumentType(node) { - switch (node.kind) { - case 214: - case 186: + if (node.kind === 214) { + var classSymbol = getSymbolOfNode(node); + return getTypeOfSymbol(classSymbol); + } + if (node.kind === 138) { + node = node.parent; + if (node.kind === 144) { var classSymbol = getSymbolOfNode(node); return getTypeOfSymbol(classSymbol); - case 138: - node = node.parent; - if (node.kind === 144) { - var classSymbol_1 = getSymbolOfNode(node); - return getTypeOfSymbol(classSymbol_1); - } - case 141: - case 143: - case 145: - case 146: - return getParentTypeOfClassElement(node); - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + } } + if (node.kind === 141 || + node.kind === 143 || + node.kind === 145 || + node.kind === 146) { + return getParentTypeOfClassElement(node); + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } function getEffectiveDecoratorSecondArgumentType(node) { - switch (node.kind) { - case 214: - ts.Debug.fail("Class decorators should not have a second synthetic argument."); - return unknownType; - case 138: - node = node.parent; - if (node.kind === 144) { - return anyType; - } - case 141: - case 143: - case 145: - case 146: - var element = node; - switch (element.name.kind) { - case 69: - case 8: - case 9: - return getStringLiteralType(element.name); - case 136: - var nameType = checkComputedPropertyName(element.name); - if (allConstituentTypesHaveKind(nameType, 16777216)) { - return nameType; - } - else { - return stringType; - } - default: - ts.Debug.fail("Unsupported property name."); - return unknownType; - } - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + if (node.kind === 214) { + ts.Debug.fail("Class decorators should not have a second synthetic argument."); + return unknownType; } + if (node.kind === 138) { + node = node.parent; + if (node.kind === 144) { + return anyType; + } + } + if (node.kind === 141 || + node.kind === 143 || + node.kind === 145 || + node.kind === 146) { + var element = node; + switch (element.name.kind) { + case 69: + case 8: + case 9: + return getStringLiteralType(element.name); + case 136: + var nameType = checkComputedPropertyName(element.name); + if (allConstituentTypesHaveKind(nameType, 16777216)) { + return nameType; + } + else { + return stringType; + } + default: + ts.Debug.fail("Unsupported property name."); + return unknownType; + } + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } function getEffectiveDecoratorThirdArgumentType(node) { - switch (node.kind) { - case 214: - ts.Debug.fail("Class decorators should not have a third synthetic argument."); - return unknownType; - case 138: - return numberType; - case 141: - ts.Debug.fail("Property decorators should not have a third synthetic argument."); - return unknownType; - case 143: - case 145: - case 146: - var propertyType = getTypeOfNode(node); - return createTypedPropertyDescriptorType(propertyType); - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + if (node.kind === 214) { + ts.Debug.fail("Class decorators should not have a third synthetic argument."); + return unknownType; } + if (node.kind === 138) { + return numberType; + } + if (node.kind === 141) { + ts.Debug.fail("Property decorators should not have a third synthetic argument."); + return unknownType; + } + if (node.kind === 143 || + node.kind === 145 || + node.kind === 146) { + var propertyType = getTypeOfNode(node); + return createTypedPropertyDescriptorType(propertyType); + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } function getEffectiveDecoratorArgumentType(node, argIndex) { if (argIndex === 0) { @@ -18907,7 +19016,10 @@ var ts; } function getEffectiveDeclarationFlags(n, flagsToCheck) { var flags = ts.getCombinedNodeFlags(n); - if (n.parent.kind !== 215 && ts.isInAmbientContext(n)) { + if (n.parent.kind !== 215 && + n.parent.kind !== 214 && + n.parent.kind !== 186 && + ts.isInAmbientContext(n)) { if (!(flags & 2)) { flags |= 1; } @@ -20102,9 +20214,6 @@ var ts; grammarErrorOnFirstToken(node, ts.Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); } checkClassLikeDeclaration(node); - if (getSymbolOfNode(node).flags & 64 && !ts.isInAmbientContext(node)) { - error(node, ts.Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface); - } ts.forEach(node.members, checkSourceElement); } function checkClassLikeDeclaration(node) { @@ -20324,15 +20433,6 @@ var ts; checkIndexConstraints(type); } } - if (symbol && symbol.declarations) { - for (var _b = 0, _c = symbol.declarations; _b < _c.length; _b++) { - var declaration = _c[_b]; - if (declaration.kind === 214 && !ts.isInAmbientContext(declaration)) { - error(node, ts.Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface); - break; - } - } - } } ts.forEach(ts.getInterfaceBaseTypeNodes(node), function (heritageElement) { if (!ts.isSupportedExpressionWithTypeArguments(heritageElement)) { @@ -29852,7 +29952,7 @@ var ts; ts.ioReadTime = 0; ts.ioWriteTime = 0; var emptyArray = []; - ts.version = "1.7.0"; + ts.version = "1.8.0"; function findConfigFile(searchPath) { var fileName = "tsconfig.json"; while (true) { @@ -30768,7 +30868,8 @@ var ts; "amd": 2, "system": 4, "umd": 3, - "es6": 5 + "es6": 5, + "es2015": 5 }, description: ts.Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_or_es6, paramType: ts.Diagnostics.KIND, @@ -30896,7 +30997,12 @@ var ts; { name: "target", shortName: "t", - type: { "es3": 0, "es5": 1, "es6": 2 }, + type: { + "es3": 0, + "es5": 1, + "es6": 2, + "es2015": 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 @@ -31053,10 +31159,10 @@ var ts; catch (e) { return { error: ts.createCompilerDiagnostic(ts.Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message) }; } - return parseConfigFileText(fileName, text); + return parseConfigFileTextToJson(fileName, text); } ts.readConfigFile = readConfigFile; - function parseConfigFileText(fileName, jsonText) { + function parseConfigFileTextToJson(fileName, jsonText) { try { return { config: /\S/.test(jsonText) ? JSON.parse(jsonText) : {} }; } @@ -31064,8 +31170,8 @@ var ts; return { error: ts.createCompilerDiagnostic(ts.Diagnostics.Failed_to_parse_file_0_Colon_1, fileName, e.message) }; } } - ts.parseConfigFileText = parseConfigFileText; - function parseConfigFile(json, host, basePath) { + ts.parseConfigFileTextToJson = parseConfigFileTextToJson; + function parseJsonConfigFileContent(json, host, basePath) { var errors = []; return { options: getCompilerOptions(), @@ -31150,7 +31256,7 @@ var ts; return fileNames; } } - ts.parseConfigFile = parseConfigFile; + ts.parseJsonConfigFileContent = parseJsonConfigFileContent; })(ts || (ts = {})); var ts; (function (ts) { @@ -31263,13 +31369,16 @@ var ts; function executeCommandLine(args) { var commandLine = ts.parseCommandLine(args); var configFileName; + var cachedConfigFileText; var configFileWatcher; + var directoryWatcher; var cachedProgram; var rootFileNames; var compilerOptions; var compilerHost; var hostGetSourceFile; - var timerHandle; + var timerHandleForRecompilation; + var timerHandleForDirectoryChanges; if (commandLine.options.locale) { if (!isJSONSupported()) { reportDiagnostic(ts.createCompilerDiagnostic(ts.Diagnostics.The_current_host_does_not_support_the_0_option, "--locale")); @@ -31322,22 +31431,38 @@ var ts; if (configFileName) { configFileWatcher = ts.sys.watchFile(configFileName, configFileChanged); } + if (ts.sys.watchDirectory && configFileName) { + var directory = ts.getDirectoryPath(configFileName); + directoryWatcher = ts.sys.watchDirectory(directory == "" ? "." : directory, watchedDirectoryChanged, true); + } } performCompilation(); + function parseConfigFile() { + if (!cachedConfigFileText) { + try { + cachedConfigFileText = ts.sys.readFile(configFileName); + } + catch (e) { + var error = ts.createCompilerDiagnostic(ts.Diagnostics.Cannot_read_file_0_Colon_1, configFileName, e.message); + reportWatchDiagnostic(error); + ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); + return; + } + } + var result = ts.parseConfigFileTextToJson(configFileName, cachedConfigFileText); + var configObject = result.config; + var configParseResult = ts.parseJsonConfigFileContent(configObject, ts.sys, ts.getDirectoryPath(configFileName)); + if (configParseResult.errors.length > 0) { + reportDiagnostics(configParseResult.errors); + ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); + return; + } + return configParseResult; + } function performCompilation() { if (!cachedProgram) { if (configFileName) { - var result = ts.readConfigFile(configFileName, ts.sys.readFile); - if (result.error) { - reportWatchDiagnostic(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); - } + var configParseResult = parseConfigFile(); rootFileNames = configParseResult.fileNames; compilerOptions = ts.extend(commandLine.options, configParseResult.options); } @@ -31392,20 +31517,42 @@ var ts; rootFileNames.splice(index, 1); } } - startTimer(); + startTimerForRecompilation(); } function configFileChanged() { setCachedProgram(undefined); - startTimer(); + cachedConfigFileText = undefined; + startTimerForRecompilation(); } - function startTimer() { - if (timerHandle) { - clearTimeout(timerHandle); + function watchedDirectoryChanged(fileName) { + if (fileName && !ts.isSupportedSourceFileName(fileName)) { + return; } - timerHandle = setTimeout(recompile, 250); + startTimerForHandlingDirectoryChanges(); + } + function startTimerForHandlingDirectoryChanges() { + if (timerHandleForDirectoryChanges) { + clearTimeout(timerHandleForDirectoryChanges); + } + timerHandleForDirectoryChanges = setTimeout(directoryChangeHandler, 250); + } + function directoryChangeHandler() { + var parsedCommandLine = parseConfigFile(); + var newFileNames = ts.map(parsedCommandLine.fileNames, compilerHost.getCanonicalFileName); + var canonicalRootFileNames = ts.map(rootFileNames, compilerHost.getCanonicalFileName); + if (!ts.arrayStructurallyIsEqualTo(newFileNames, canonicalRootFileNames)) { + setCachedProgram(undefined); + startTimerForRecompilation(); + } + } + function startTimerForRecompilation() { + if (timerHandleForRecompilation) { + clearTimeout(timerHandleForRecompilation); + } + timerHandleForRecompilation = setTimeout(recompile, 250); } function recompile() { - timerHandle = undefined; + timerHandleForRecompilation = undefined; reportWatchDiagnostic(ts.createCompilerDiagnostic(ts.Diagnostics.File_change_detected_Starting_incremental_compilation)); performCompilation(); } diff --git a/lib/tsserver.js b/lib/tsserver.js index 0368e826f13..af36f5e3d80 100644 --- a/lib/tsserver.js +++ b/lib/tsserver.js @@ -630,6 +630,9 @@ var ts; } ts.getRelativePathToDirectoryOrUrl = getRelativePathToDirectoryOrUrl; function getBaseFileName(path) { + if (!path) { + return undefined; + } var i = path.lastIndexOf(ts.directorySeparator); return i < 0 ? path : path.substring(i + 1); } @@ -654,6 +657,19 @@ var ts; ts.fileExtensionIs = fileExtensionIs; ts.supportedExtensions = [".ts", ".tsx", ".d.ts"]; ts.supportedJsExtensions = ts.supportedExtensions.concat(".js", ".jsx"); + function isSupportedSourceFileName(fileName) { + if (!fileName) { + return false; + } + for (var _i = 0; _i < ts.supportedExtensions.length; _i++) { + var extension = ts.supportedExtensions[_i]; + if (fileExtensionIs(fileName, extension)) { + return true; + } + } + return false; + } + ts.isSupportedSourceFileName = isSupportedSourceFileName; var extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"]; function removeFileExtension(path) { for (var _i = 0; _i < extensionsToRemove.length; _i++) { @@ -730,6 +746,16 @@ var ts; } Debug.fail = fail; })(Debug = ts.Debug || (ts.Debug = {})); + function copyListRemovingItem(item, list) { + var copiedList = []; + for (var i = 0, len = list.length; i < len; i++) { + if (list[i] !== item) { + copiedList.push(list[i]); + } + } + return copiedList; + } + ts.copyListRemovingItem = copyListRemovingItem; })(ts || (ts = {})); var ts; (function (ts) { @@ -868,6 +894,76 @@ var ts; var _fs = require("fs"); var _path = require("path"); var _os = require("os"); + function createWatchedFileSet(interval, chunkSize) { + if (interval === void 0) { interval = 2500; } + if (chunkSize === void 0) { chunkSize = 30; } + var watchedFiles = []; + var nextFileToCheck = 0; + var watchTimer; + function getModifiedTime(fileName) { + return _fs.statSync(fileName).mtime; + } + function poll(checkedIndex) { + var watchedFile = watchedFiles[checkedIndex]; + if (!watchedFile) { + return; + } + _fs.stat(watchedFile.fileName, function (err, stats) { + if (err) { + watchedFile.callback(watchedFile.fileName); + } + else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) { + watchedFile.mtime = getModifiedTime(watchedFile.fileName); + watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0); + } + }); + } + function startWatchTimer() { + watchTimer = setInterval(function () { + var count = 0; + var nextToCheck = nextFileToCheck; + var firstCheck = -1; + while ((count < chunkSize) && (nextToCheck !== firstCheck)) { + poll(nextToCheck); + if (firstCheck < 0) { + firstCheck = nextToCheck; + } + nextToCheck++; + if (nextToCheck === watchedFiles.length) { + nextToCheck = 0; + } + count++; + } + nextFileToCheck = nextToCheck; + }, interval); + } + function addFile(fileName, callback) { + var file = { + fileName: fileName, + callback: callback, + mtime: getModifiedTime(fileName) + }; + watchedFiles.push(file); + if (watchedFiles.length === 1) { + startWatchTimer(); + } + return file; + } + function removeFile(file) { + watchedFiles = ts.copyListRemovingItem(file, watchedFiles); + } + return { + getModifiedTime: getModifiedTime, + poll: poll, + startWatchTimer: startWatchTimer, + addFile: addFile, + removeFile: removeFile + }; + } + var watchedFileSet = createWatchedFileSet(); + function isNode4OrLater() { + return parseInt(process.version.charAt(1)) >= 4; + } var platform = _os.platform(); var useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin"; function readFile(fileName, encoding) { @@ -948,20 +1044,21 @@ var ts; 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.getTime() === 0) { - callback(fileName, true); - return; - } - if (+curr.mtime <= +prev.mtime) { - return; - } - callback(fileName, false); + if (isNode4OrLater()) { + return _fs.watch(fileName, function (eventName, relativeFileName) { return callback(fileName); }); } + var watchedFile = watchedFileSet.addFile(fileName, callback); + return { + close: function () { return watchedFileSet.removeFile(watchedFile); } + }; + }, + watchDirectory: function (path, callback, recursive) { + return _fs.watch(path, { persisten: true, recursive: !!recursive }, function (eventName, relativeFileName) { + if (eventName === "rename") { + callback(!relativeFileName ? relativeFileName : ts.normalizePath(ts.combinePaths(path, relativeFileName))); + } + ; + }); }, resolvePath: function (path) { return _path.resolve(path); @@ -1414,7 +1511,6 @@ var ts; Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2: { code: 2515, category: ts.DiagnosticCategory.Error, key: "Non-abstract class '{0}' does not implement inherited abstract member '{1}' from class '{2}'." }, All_declarations_of_an_abstract_method_must_be_consecutive: { code: 2516, category: ts.DiagnosticCategory.Error, key: "All declarations of an abstract method must be consecutive." }, Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type: { code: 2517, category: ts.DiagnosticCategory.Error, key: "Cannot assign an abstract constructor type to a non-abstract constructor type." }, - Only_an_ambient_class_can_be_merged_with_an_interface: { code: 2518, category: ts.DiagnosticCategory.Error, key: "Only an ambient class can be merged with an interface." }, Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions: { code: 2520, category: ts.DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions." }, Expression_resolves_to_variable_declaration_0_that_compiler_uses_to_support_async_functions: { code: 2521, category: ts.DiagnosticCategory.Error, key: "Expression resolves to variable declaration '{0}' that compiler uses to support async functions." }, The_arguments_object_cannot_be_referenced_in_an_async_arrow_function_Consider_using_a_standard_async_function_expression: { code: 2522, category: ts.DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an async arrow function. Consider using a standard async function expression." }, @@ -3056,7 +3152,8 @@ var ts; "amd": 2, "system": 4, "umd": 3, - "es6": 5 + "es6": 5, + "es2015": 5 }, description: ts.Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_or_es6, paramType: ts.Diagnostics.KIND, @@ -3184,7 +3281,12 @@ var ts; { name: "target", shortName: "t", - type: { "es3": 0, "es5": 1, "es6": 2 }, + type: { + "es3": 0, + "es5": 1, + "es6": 2, + "es2015": 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 @@ -3341,10 +3443,10 @@ var ts; catch (e) { return { error: ts.createCompilerDiagnostic(ts.Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message) }; } - return parseConfigFileText(fileName, text); + return parseConfigFileTextToJson(fileName, text); } ts.readConfigFile = readConfigFile; - function parseConfigFileText(fileName, jsonText) { + function parseConfigFileTextToJson(fileName, jsonText) { try { return { config: /\S/.test(jsonText) ? JSON.parse(jsonText) : {} }; } @@ -3352,8 +3454,8 @@ var ts; return { error: ts.createCompilerDiagnostic(ts.Diagnostics.Failed_to_parse_file_0_Colon_1, fileName, e.message) }; } } - ts.parseConfigFileText = parseConfigFileText; - function parseConfigFile(json, host, basePath) { + ts.parseConfigFileTextToJson = parseConfigFileTextToJson; + function parseJsonConfigFileContent(json, host, basePath) { var errors = []; return { options: getCompilerOptions(), @@ -3438,7 +3540,7 @@ var ts; return fileNames; } } - ts.parseConfigFile = parseConfigFile; + ts.parseJsonConfigFileContent = parseJsonConfigFileContent; })(ts || (ts = {})); var ts; (function (ts) { @@ -4303,7 +4405,8 @@ var ts; return expression.kind === 168 && expression.expression.kind === 69 && expression.expression.text === "require" && - expression.arguments.length === 1; + expression.arguments.length === 1 && + expression.arguments[0].kind === 9; } ts.isRequireCall = isRequireCall; function isExportsPropertyAssignment(expression) { @@ -5444,6 +5547,16 @@ var ts; } } ts.getTypeParameterOwner = getTypeParameterOwner; + function arrayStructurallyIsEqualTo(array1, array2) { + if (!array1 || !array2) { + return false; + } + if (array1.length !== array2.length) { + return false; + } + return ts.arrayIsEqualTo(array1.sort(), array2.sort()); + } + ts.arrayStructurallyIsEqualTo = arrayStructurallyIsEqualTo; })(ts || (ts = {})); var ts; (function (ts) { @@ -13829,7 +13942,9 @@ var ts; function getSignatureFromDeclaration(declaration) { var links = getNodeLinks(declaration); if (!links.resolvedSignature) { - var classType = declaration.kind === 144 ? getDeclaredTypeOfClassOrInterface(declaration.parent.symbol) : undefined; + var classType = declaration.kind === 144 ? + getDeclaredTypeOfClassOrInterface(getMergedSymbol(declaration.parent.symbol)) + : undefined; var typeParameters = classType ? classType.localTypeParameters : declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) : undefined; var parameters = []; @@ -17641,83 +17756,83 @@ var ts; } } function getEffectiveDecoratorFirstArgumentType(node) { - switch (node.kind) { - case 214: - case 186: + if (node.kind === 214) { + var classSymbol = getSymbolOfNode(node); + return getTypeOfSymbol(classSymbol); + } + if (node.kind === 138) { + node = node.parent; + if (node.kind === 144) { var classSymbol = getSymbolOfNode(node); return getTypeOfSymbol(classSymbol); - case 138: - node = node.parent; - if (node.kind === 144) { - var classSymbol_1 = getSymbolOfNode(node); - return getTypeOfSymbol(classSymbol_1); - } - case 141: - case 143: - case 145: - case 146: - return getParentTypeOfClassElement(node); - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + } } + if (node.kind === 141 || + node.kind === 143 || + node.kind === 145 || + node.kind === 146) { + return getParentTypeOfClassElement(node); + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } function getEffectiveDecoratorSecondArgumentType(node) { - switch (node.kind) { - case 214: - ts.Debug.fail("Class decorators should not have a second synthetic argument."); - return unknownType; - case 138: - node = node.parent; - if (node.kind === 144) { - return anyType; - } - case 141: - case 143: - case 145: - case 146: - var element = node; - switch (element.name.kind) { - case 69: - case 8: - case 9: - return getStringLiteralType(element.name); - case 136: - var nameType = checkComputedPropertyName(element.name); - if (allConstituentTypesHaveKind(nameType, 16777216)) { - return nameType; - } - else { - return stringType; - } - default: - ts.Debug.fail("Unsupported property name."); - return unknownType; - } - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + if (node.kind === 214) { + ts.Debug.fail("Class decorators should not have a second synthetic argument."); + return unknownType; } + if (node.kind === 138) { + node = node.parent; + if (node.kind === 144) { + return anyType; + } + } + if (node.kind === 141 || + node.kind === 143 || + node.kind === 145 || + node.kind === 146) { + var element = node; + switch (element.name.kind) { + case 69: + case 8: + case 9: + return getStringLiteralType(element.name); + case 136: + var nameType = checkComputedPropertyName(element.name); + if (allConstituentTypesHaveKind(nameType, 16777216)) { + return nameType; + } + else { + return stringType; + } + default: + ts.Debug.fail("Unsupported property name."); + return unknownType; + } + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } function getEffectiveDecoratorThirdArgumentType(node) { - switch (node.kind) { - case 214: - ts.Debug.fail("Class decorators should not have a third synthetic argument."); - return unknownType; - case 138: - return numberType; - case 141: - ts.Debug.fail("Property decorators should not have a third synthetic argument."); - return unknownType; - case 143: - case 145: - case 146: - var propertyType = getTypeOfNode(node); - return createTypedPropertyDescriptorType(propertyType); - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + if (node.kind === 214) { + ts.Debug.fail("Class decorators should not have a third synthetic argument."); + return unknownType; } + if (node.kind === 138) { + return numberType; + } + if (node.kind === 141) { + ts.Debug.fail("Property decorators should not have a third synthetic argument."); + return unknownType; + } + if (node.kind === 143 || + node.kind === 145 || + node.kind === 146) { + var propertyType = getTypeOfNode(node); + return createTypedPropertyDescriptorType(propertyType); + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } function getEffectiveDecoratorArgumentType(node, argIndex) { if (argIndex === 0) { @@ -19364,7 +19479,10 @@ var ts; } function getEffectiveDeclarationFlags(n, flagsToCheck) { var flags = ts.getCombinedNodeFlags(n); - if (n.parent.kind !== 215 && ts.isInAmbientContext(n)) { + if (n.parent.kind !== 215 && + n.parent.kind !== 214 && + n.parent.kind !== 186 && + ts.isInAmbientContext(n)) { if (!(flags & 2)) { flags |= 1; } @@ -20559,9 +20677,6 @@ var ts; grammarErrorOnFirstToken(node, ts.Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); } checkClassLikeDeclaration(node); - if (getSymbolOfNode(node).flags & 64 && !ts.isInAmbientContext(node)) { - error(node, ts.Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface); - } ts.forEach(node.members, checkSourceElement); } function checkClassLikeDeclaration(node) { @@ -20781,15 +20896,6 @@ var ts; checkIndexConstraints(type); } } - if (symbol && symbol.declarations) { - for (var _b = 0, _c = symbol.declarations; _b < _c.length; _b++) { - var declaration = _c[_b]; - if (declaration.kind === 214 && !ts.isInAmbientContext(declaration)) { - error(node, ts.Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface); - break; - } - } - } } ts.forEach(ts.getInterfaceBaseTypeNodes(node), function (heritageElement) { if (!ts.isSupportedExpressionWithTypeArguments(heritageElement)) { @@ -30309,7 +30415,7 @@ var ts; ts.ioReadTime = 0; ts.ioWriteTime = 0; var emptyArray = []; - ts.version = "1.7.0"; + ts.version = "1.8.0"; function findConfigFile(searchPath) { var fileName = "tsconfig.json"; while (true) { @@ -42148,6 +42254,9 @@ var ts; } }; Session.prototype.closeClientFile = function (fileName) { + if (!fileName) { + return; + } var file = ts.normalizePath(fileName); this.projectService.closeClientFile(file); }; @@ -42504,6 +42613,7 @@ var ts; if (scriptInfo) { this.filenameToScript[info.fileName] = undefined; this.roots = copyListRemovingItem(info, this.roots); + this.resolvedModuleNames.remove(info.fileName); } }; LSHost.prototype.saveTo = function (filename, tmpfilename) { @@ -42597,6 +42707,7 @@ var ts; function Project(projectService, projectOptions) { this.projectService = projectService; this.projectOptions = projectOptions; + this.directoriesWatchedForTsconfig = []; this.filenameToSourceFile = {}; this.updateGraphSeq = 0; this.openRefCount = 0; @@ -42615,6 +42726,9 @@ var ts; Project.prototype.openReferencedFile = function (filename) { return this.projectService.openFile(filename, false); }; + Project.prototype.getRootFiles = function () { + return this.compilerService.host.roots.map(function (info) { return info.fileName; }); + }; Project.prototype.getFileNames = function () { var sourceFiles = this.program.getSourceFiles(); return sourceFiles.map(function (sourceFile) { return sourceFile.fileName; }); @@ -42657,11 +42771,9 @@ var ts; return this.projectFilename; }; Project.prototype.addRoot = function (info) { - info.defaultProject = this; this.compilerService.host.addRoot(info); }; Project.prototype.removeRoot = function (info) { - info.defaultProject = undefined; this.compilerService.host.removeRoot(info); }; Project.prototype.filesToString = function () { @@ -42699,6 +42811,9 @@ var ts; this.configuredProjects = []; this.openFilesReferenced = []; this.openFileRootsConfigured = []; + this.directoryWatchersForTsconfig = {}; + this.directoryWatchersRefCount = {}; + this.timerForDetectingProjectFilelistChanges = {}; this.addDefaultHostConfiguration(); } ProjectService.prototype.addDefaultHostConfiguration = function () { @@ -42730,8 +42845,54 @@ var ts; } } }; + ProjectService.prototype.directoryWatchedForSourceFilesChanged = function (project, fileName) { + if (fileName && !ts.isSupportedSourceFileName(fileName)) { + return; + } + this.log("Detected source file changes: " + fileName); + this.startTimerForDetectingProjectFilelistChanges(project); + }; + ProjectService.prototype.startTimerForDetectingProjectFilelistChanges = function (project) { + var _this = this; + if (this.timerForDetectingProjectFilelistChanges[project.projectFilename]) { + clearTimeout(this.timerForDetectingProjectFilelistChanges[project.projectFilename]); + } + this.timerForDetectingProjectFilelistChanges[project.projectFilename] = setTimeout(function () { return _this.handleProjectFilelistChanges(project); }, 250); + }; + ProjectService.prototype.handleProjectFilelistChanges = function (project) { + var _this = this; + var _a = this.configFileToProjectOptions(project.projectFilename), succeeded = _a.succeeded, projectOptions = _a.projectOptions, error = _a.error; + var newRootFiles = projectOptions.files.map((function (f) { return _this.getCanonicalFileName(f); })); + var currentRootFiles = project.getRootFiles().map((function (f) { return _this.getCanonicalFileName(f); })); + if (!ts.arrayStructurallyIsEqualTo(currentRootFiles, newRootFiles)) { + this.updateConfiguredProject(project); + this.updateProjectStructure(); + } + }; + ProjectService.prototype.directoryWatchedForTsconfigChanged = function (fileName) { + var _this = this; + if (ts.getBaseFileName(fileName) != "tsconfig.json") { + this.log(fileName + " is not tsconfig.json"); + return; + } + this.log("Detected newly added tsconfig file: " + fileName); + var _a = this.configFileToProjectOptions(fileName), succeeded = _a.succeeded, projectOptions = _a.projectOptions, error = _a.error; + var rootFilesInTsconfig = projectOptions.files.map(function (f) { return _this.getCanonicalFileName(f); }); + var openFileRoots = this.openFileRoots.map(function (s) { return _this.getCanonicalFileName(s.fileName); }); + for (var _i = 0; _i < openFileRoots.length; _i++) { + var openFileRoot = openFileRoots[_i]; + if (rootFilesInTsconfig.indexOf(openFileRoot) >= 0) { + this.reloadProjects(); + return; + } + } + }; + ProjectService.prototype.getCanonicalFileName = function (fileName) { + var name = this.host.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(); + return ts.normalizePath(name); + }; ProjectService.prototype.watchedProjectConfigFileChanged = function (project) { - this.log("Config File Changed: " + project.projectFilename); + this.log("Config file changed: " + project.projectFilename); this.updateConfiguredProject(project); this.updateProjectStructure(); }; @@ -42762,11 +42923,28 @@ var ts; this.psLogger.close(); }; ProjectService.prototype.createInferredProject = function (root) { - var iproj = new Project(this); - iproj.addRoot(root); - iproj.finishGraph(); - this.inferredProjects.push(iproj); - return iproj; + var _this = this; + var project = new Project(this); + project.addRoot(root); + var currentPath = ts.getDirectoryPath(root.fileName); + var parentPath = ts.getDirectoryPath(currentPath); + while (currentPath != parentPath) { + if (!project.projectService.directoryWatchersForTsconfig[currentPath]) { + this.log("Add watcher for: " + currentPath); + project.projectService.directoryWatchersForTsconfig[currentPath] = + this.host.watchDirectory(currentPath, function (fileName) { return _this.directoryWatchedForTsconfigChanged(fileName); }); + project.projectService.directoryWatchersRefCount[currentPath] = 1; + } + else { + project.projectService.directoryWatchersRefCount[currentPath] += 1; + } + project.directoriesWatchedForTsconfig.push(currentPath); + currentPath = parentPath; + parentPath = ts.getDirectoryPath(parentPath); + } + project.finishGraph(); + this.inferredProjects.push(project); + return project; }; ProjectService.prototype.fileDeletedInFilesystem = function (info) { this.psLogger.info(info.fileName + " deleted"); @@ -42777,6 +42955,9 @@ var ts; if (!info.isOpen) { this.filenameToScriptInfo[info.fileName] = undefined; var referencingProjects = this.findReferencingProjects(info); + if (info.defaultProject) { + info.defaultProject.removeRoot(info); + } for (var i = 0, len = referencingProjects.length; i < len; i++) { referencingProjects[i].removeReferencedFile(info); } @@ -42804,12 +42985,27 @@ var ts; } this.configuredProjects = configuredProjects; }; - ProjectService.prototype.removeConfiguredProject = function (project) { - project.projectFileWatcher.close(); - this.configuredProjects = copyListRemovingItem(project, this.configuredProjects); + ProjectService.prototype.removeProject = function (project) { + this.log("remove project: " + project.getRootFiles().toString()); + if (project.isConfiguredProject()) { + project.projectFileWatcher.close(); + project.directoryWatcher.close(); + this.configuredProjects = copyListRemovingItem(project, this.configuredProjects); + } + else { + for (var _i = 0, _a = project.directoriesWatchedForTsconfig; _i < _a.length; _i++) { + var directory = _a[_i]; + if (!(--project.projectService.directoryWatchersRefCount[directory])) { + this.log("Close directory watcher for: " + directory); + project.projectService.directoryWatchersForTsconfig[directory].close(); + delete project.projectService.directoryWatchersForTsconfig[directory]; + } + } + this.inferredProjects = copyListRemovingItem(project, this.inferredProjects); + } var fileNames = project.getFileNames(); - for (var _i = 0; _i < fileNames.length; _i++) { - var fileName = fileNames[_i]; + for (var _b = 0; _b < fileNames.length; _b++) { + var fileName = fileNames[_b]; var info = this.getScriptInfo(fileName); if (info.defaultProject == project) { info.defaultProject = undefined; @@ -42842,8 +43038,7 @@ var ts; for (var i = 0, len = this.openFileRoots.length; i < len; i++) { var r = this.openFileRoots[i]; if (info.defaultProject.getSourceFile(r)) { - this.inferredProjects = - copyListRemovingItem(r.defaultProject, this.inferredProjects); + this.removeProject(r.defaultProject); this.openFilesReferenced.push(r); r.defaultProject = info.defaultProject; } @@ -42858,6 +43053,7 @@ var ts; this.updateConfiguredProjectList(); }; ProjectService.prototype.closeOpenFile = function (info) { + info.svc.reloadFromFile(info.fileName); var openFileRoots = []; var removedProject; for (var i = 0, len = this.openFileRoots.length; i < len; i++) { @@ -42884,17 +43080,12 @@ var ts; this.openFileRootsConfigured = openFileRootsConfigured; } if (removedProject) { - if (removedProject.isConfiguredProject()) { - this.configuredProjects = copyListRemovingItem(removedProject, this.configuredProjects); - } - else { - this.inferredProjects = copyListRemovingItem(removedProject, this.inferredProjects); - } + this.removeProject(removedProject); var openFilesReferenced = []; var orphanFiles = []; for (var i = 0, len = this.openFilesReferenced.length; i < len; i++) { var f = this.openFilesReferenced[i]; - if (f.defaultProject === removedProject) { + if (f.defaultProject === removedProject || !f.defaultProject) { f.defaultProject = undefined; orphanFiles.push(f); } @@ -42935,6 +43126,7 @@ var ts; return referencingProjects; }; ProjectService.prototype.reloadProjects = function () { + this.log("reload projects."); for (var _i = 0, _a = this.openFileRoots; _i < _a.length; _i++) { var info = _a[_i]; this.openOrUpdateConfiguredProjectForFile(info.fileName); @@ -42976,13 +43168,21 @@ var ts; var rootFile = this.openFileRoots[i]; var rootedProject = rootFile.defaultProject; var referencingProjects = this.findReferencingProjects(rootFile, rootedProject); - if (referencingProjects.length === 0) { - rootFile.defaultProject = rootedProject; - openFileRoots.push(rootFile); + if (rootFile.defaultProject && rootFile.defaultProject.isConfiguredProject()) { + if (!rootedProject.isConfiguredProject()) { + this.removeProject(rootedProject); + } + this.openFileRootsConfigured.push(rootFile); } else { - this.inferredProjects = copyListRemovingItem(rootedProject, this.inferredProjects); - this.openFilesReferenced.push(rootFile); + if (referencingProjects.length === 0) { + rootFile.defaultProject = rootedProject; + openFileRoots.push(rootFile); + } + else { + this.removeProject(rootedProject); + this.openFilesReferenced.push(rootFile); + } } } this.openFileRoots = openFileRoots; @@ -43153,12 +43353,12 @@ var ts; configFilename = ts.normalizePath(configFilename); var dirPath = ts.getDirectoryPath(configFilename); var contents = this.host.readFile(configFilename); - var rawConfig = ts.parseConfigFileText(configFilename, contents); + var rawConfig = ts.parseConfigFileTextToJson(configFilename, contents); if (rawConfig.error) { return { succeeded: false, error: rawConfig.error }; } else { - var parsedCommandLine = ts.parseConfigFile(rawConfig.config, this.host, dirPath); + var parsedCommandLine = ts.parseJsonConfigFileContent(rawConfig.config, this.host, dirPath); if (parsedCommandLine.errors && (parsedCommandLine.errors.length > 0)) { return { succeeded: false, error: { errorMsg: "tsconfig option errors" } }; } @@ -43181,26 +43381,28 @@ var ts; return error; } else { - var proj = this.createProject(configFilename, projectOptions); - for (var i = 0, len = projectOptions.files.length; i < len; i++) { - var rootFilename = projectOptions.files[i]; + var project = this.createProject(configFilename, projectOptions); + for (var _i = 0, _b = projectOptions.files; _i < _b.length; _i++) { + var rootFilename = _b[_i]; if (this.host.fileExists(rootFilename)) { var info = this.openFile(rootFilename, clientFileName == rootFilename); - proj.addRoot(info); + project.addRoot(info); } else { return { errorMsg: "specified file " + rootFilename + " not found" }; } } - proj.finishGraph(); - proj.projectFileWatcher = this.host.watchFile(configFilename, function (_) { return _this.watchedProjectConfigFileChanged(proj); }); - return { success: true, project: proj }; + project.finishGraph(); + project.projectFileWatcher = this.host.watchFile(configFilename, function (_) { return _this.watchedProjectConfigFileChanged(project); }); + this.log("Add recursive watcher for: " + ts.getDirectoryPath(configFilename)); + project.directoryWatcher = this.host.watchDirectory(ts.getDirectoryPath(configFilename), function (path) { return _this.directoryWatchedForSourceFilesChanged(project, path); }, true); + return { success: true, project: project }; } }; ProjectService.prototype.updateConfiguredProject = function (project) { if (!this.host.fileExists(project.projectFilename)) { this.log("Config file deleted"); - this.removeConfiguredProject(project); + this.removeProject(project); } else { var _a = this.configFileToProjectOptions(project.projectFilename), succeeded = _a.succeeded, projectOptions = _a.projectOptions, error = _a.error; @@ -43215,7 +43417,9 @@ var ts; for (var _i = 0; _i < fileNamesToRemove.length; _i++) { var fileName = fileNamesToRemove[_i]; var info = this.getScriptInfo(fileName); - project.removeRoot(info); + if (info) { + project.removeRoot(info); + } } for (var _b = 0; _b < fileNamesToAdd.length; _b++) { var fileName = fileNamesToAdd[_b]; @@ -44194,79 +44398,6 @@ var ts; }; return Logger; })(); - var WatchedFileSet = (function () { - function WatchedFileSet(interval, chunkSize) { - if (interval === void 0) { interval = 2500; } - if (chunkSize === void 0) { chunkSize = 30; } - this.interval = interval; - this.chunkSize = chunkSize; - this.watchedFiles = []; - this.nextFileToCheck = 0; - } - WatchedFileSet.copyListRemovingItem = function (item, list) { - var copiedList = []; - for (var i = 0, len = list.length; i < len; i++) { - if (list[i] != item) { - copiedList.push(list[i]); - } - } - return copiedList; - }; - WatchedFileSet.getModifiedTime = function (fileName) { - return fs.statSync(fileName).mtime; - }; - WatchedFileSet.prototype.poll = function (checkedIndex) { - var watchedFile = this.watchedFiles[checkedIndex]; - if (!watchedFile) { - return; - } - fs.stat(watchedFile.fileName, function (err, stats) { - if (err) { - watchedFile.callback(watchedFile.fileName, false); - } - else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) { - watchedFile.mtime = WatchedFileSet.getModifiedTime(watchedFile.fileName); - watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0); - } - }); - }; - WatchedFileSet.prototype.startWatchTimer = function () { - var _this = this; - this.watchTimer = setInterval(function () { - var count = 0; - var nextToCheck = _this.nextFileToCheck; - var firstCheck = -1; - while ((count < _this.chunkSize) && (nextToCheck !== firstCheck)) { - _this.poll(nextToCheck); - if (firstCheck < 0) { - firstCheck = nextToCheck; - } - nextToCheck++; - if (nextToCheck === _this.watchedFiles.length) { - nextToCheck = 0; - } - count++; - } - _this.nextFileToCheck = nextToCheck; - }, this.interval); - }; - WatchedFileSet.prototype.addFile = function (fileName, callback) { - var file = { - fileName: fileName, - callback: callback, - mtime: WatchedFileSet.getModifiedTime(fileName) - }; - this.watchedFiles.push(file); - if (this.watchedFiles.length === 1) { - this.startWatchTimer(); - } - return file; - }; - WatchedFileSet.prototype.removeFile = function (file) { - this.watchedFiles = WatchedFileSet.copyListRemovingItem(file, this.watchedFiles); - }; - return WatchedFileSet; - })(); var IOSession = (function (_super) { __extends(IOSession, _super); function IOSession(host, logger) { @@ -44327,13 +44458,6 @@ var ts; return new Logger(fileName, detailLevel); } var logger = createLoggerFromEnv(); - var watchedFileSet = new WatchedFileSet(); - ts.sys.watchFile = function (fileName, callback) { - var watchedFile = watchedFileSet.addFile(fileName, callback); - return { - close: function () { return watchedFileSet.removeFile(watchedFile); } - }; - }; var ioSession = new IOSession(ts.sys, logger); process.on('uncaughtException', function (err) { ioSession.logError(err, "unknown"); @@ -44900,7 +45024,7 @@ var ts; var _this = this; return this.forwardJSONCall("getTSConfigFileInfo('" + fileName + "')", function () { var text = sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()); - var result = ts.parseConfigFileText(fileName, text); + var result = ts.parseConfigFileTextToJson(fileName, text); if (result.error) { return { options: {}, @@ -44908,7 +45032,7 @@ var ts; errors: [realizeDiagnostic(result.error, '\r\n')] }; } - var configFile = ts.parseConfigFile(result.config, _this.host, ts.getDirectoryPath(ts.normalizeSlashes(fileName))); + var configFile = ts.parseJsonConfigFileContent(result.config, _this.host, ts.getDirectoryPath(ts.normalizeSlashes(fileName))); return { options: configFile.options, files: configFile.fileNames, diff --git a/lib/typescript.d.ts b/lib/typescript.d.ts index abfa9a002b5..78f971ccac1 100644 --- a/lib/typescript.d.ts +++ b/lib/typescript.d.ts @@ -1359,6 +1359,7 @@ declare namespace ts { UMD = 3, System = 4, ES6 = 5, + ES2015 = 5, } const enum JsxEmit { None = 0, @@ -1377,6 +1378,7 @@ declare namespace ts { ES3 = 0, ES5 = 1, ES6 = 2, + ES2015 = 2, Latest = 2, } const enum LanguageVariant { @@ -1428,7 +1430,8 @@ declare namespace ts { write(s: string): void; readFile(path: string, encoding?: string): string; writeFile(path: string, data: string, writeByteOrderMark?: boolean): void; - watchFile?(path: string, callback: (path: string, removed: boolean) => void): FileWatcher; + watchFile?(path: string, callback: (path: string, removed?: boolean) => void): FileWatcher; + watchDirectory?(path: string, callback: (path: string) => void, recursive?: boolean): FileWatcher; resolvePath(path: string): string; fileExists(path: string): boolean; directoryExists(path: string): boolean; @@ -1518,6 +1521,7 @@ declare namespace ts { */ function collapseTextChangeRangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange; function getTypeParameterOwner(d: Declaration): Declaration; + function arrayStructurallyIsEqualTo(array1: Array, array2: Array): boolean; } declare namespace ts { function getNodeConstructor(kind: SyntaxKind): new () => Node; @@ -1553,7 +1557,7 @@ declare namespace ts { * @param fileName The path to the config file * @param jsonText The text of the config file */ - function parseConfigFileText(fileName: string, jsonText: string): { + function parseConfigFileTextToJson(fileName: string, jsonText: string): { config?: any; error?: Diagnostic; }; @@ -1563,7 +1567,7 @@ declare namespace ts { * @param basePath A root directory to resolve relative path entries in the config * file to. e.g. outDir */ - function parseConfigFile(json: any, host: ParseConfigHost, basePath: string): ParsedCommandLine; + function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string): ParsedCommandLine; } declare namespace ts { /** The version of the language service API */ diff --git a/lib/typescript.js b/lib/typescript.js index d261ce125fc..5fec75307d0 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -660,6 +660,7 @@ var ts; ModuleKind[ModuleKind["UMD"] = 3] = "UMD"; ModuleKind[ModuleKind["System"] = 4] = "System"; ModuleKind[ModuleKind["ES6"] = 5] = "ES6"; + ModuleKind[ModuleKind["ES2015"] = 5] = "ES2015"; })(ts.ModuleKind || (ts.ModuleKind = {})); var ModuleKind = ts.ModuleKind; (function (JsxEmit) { @@ -677,6 +678,7 @@ var ts; ScriptTarget[ScriptTarget["ES3"] = 0] = "ES3"; ScriptTarget[ScriptTarget["ES5"] = 1] = "ES5"; ScriptTarget[ScriptTarget["ES6"] = 2] = "ES6"; + ScriptTarget[ScriptTarget["ES2015"] = 2] = "ES2015"; ScriptTarget[ScriptTarget["Latest"] = 2] = "Latest"; })(ts.ScriptTarget || (ts.ScriptTarget = {})); var ScriptTarget = ts.ScriptTarget; @@ -1478,6 +1480,9 @@ var ts; } ts.getRelativePathToDirectoryOrUrl = getRelativePathToDirectoryOrUrl; function getBaseFileName(path) { + if (!path) { + return undefined; + } var i = path.lastIndexOf(ts.directorySeparator); return i < 0 ? path : path.substring(i + 1); } @@ -1505,6 +1510,19 @@ var ts; */ ts.supportedExtensions = [".ts", ".tsx", ".d.ts"]; ts.supportedJsExtensions = ts.supportedExtensions.concat(".js", ".jsx"); + function isSupportedSourceFileName(fileName) { + if (!fileName) { + return false; + } + for (var _i = 0; _i < ts.supportedExtensions.length; _i++) { + var extension = ts.supportedExtensions[_i]; + if (fileExtensionIs(fileName, extension)) { + return true; + } + } + return false; + } + ts.isSupportedSourceFileName = isSupportedSourceFileName; var extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"]; function removeFileExtension(path) { for (var _i = 0; _i < extensionsToRemove.length; _i++) { @@ -1588,6 +1606,16 @@ var ts; } Debug.fail = fail; })(Debug = ts.Debug || (ts.Debug = {})); + function copyListRemovingItem(item, list) { + var copiedList = []; + for (var i = 0, len = list.length; i < len; i++) { + if (list[i] !== item) { + copiedList.push(list[i]); + } + } + return copiedList; + } + ts.copyListRemovingItem = copyListRemovingItem; })(ts || (ts = {})); /// var ts; @@ -1734,6 +1762,94 @@ var ts; var _fs = require("fs"); var _path = require("path"); var _os = require("os"); + // average async stat takes about 30 microseconds + // set chunk size to do 30 files in < 1 millisecond + function createWatchedFileSet(interval, chunkSize) { + if (interval === void 0) { interval = 2500; } + if (chunkSize === void 0) { chunkSize = 30; } + var watchedFiles = []; + var nextFileToCheck = 0; + var watchTimer; + function getModifiedTime(fileName) { + return _fs.statSync(fileName).mtime; + } + function poll(checkedIndex) { + var watchedFile = watchedFiles[checkedIndex]; + if (!watchedFile) { + return; + } + _fs.stat(watchedFile.fileName, function (err, stats) { + if (err) { + watchedFile.callback(watchedFile.fileName); + } + else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) { + watchedFile.mtime = getModifiedTime(watchedFile.fileName); + watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0); + } + }); + } + // this implementation uses polling and + // stat due to inconsistencies of fs.watch + // and efficiency of stat on modern filesystems + function startWatchTimer() { + watchTimer = setInterval(function () { + var count = 0; + var nextToCheck = nextFileToCheck; + var firstCheck = -1; + while ((count < chunkSize) && (nextToCheck !== firstCheck)) { + poll(nextToCheck); + if (firstCheck < 0) { + firstCheck = nextToCheck; + } + nextToCheck++; + if (nextToCheck === watchedFiles.length) { + nextToCheck = 0; + } + count++; + } + nextFileToCheck = nextToCheck; + }, interval); + } + function addFile(fileName, callback) { + var file = { + fileName: fileName, + callback: callback, + mtime: getModifiedTime(fileName) + }; + watchedFiles.push(file); + if (watchedFiles.length === 1) { + startWatchTimer(); + } + return file; + } + function removeFile(file) { + watchedFiles = ts.copyListRemovingItem(file, watchedFiles); + } + return { + getModifiedTime: getModifiedTime, + poll: poll, + startWatchTimer: startWatchTimer, + addFile: addFile, + removeFile: removeFile + }; + } + // REVIEW: for now this implementation uses polling. + // The advantage of polling is that it works reliably + // on all os and with network mounted files. + // For 90 referenced files, the average time to detect + // changes is 2*msInterval (by default 5 seconds). + // The overhead of this is .04 percent (1/2500) with + // average pause of < 1 millisecond (and max + // pause less than 1.5 milliseconds); question is + // do we anticipate reference sets in the 100s and + // do we care about waiting 10-20 seconds to detect + // changes for large reference sets? If so, do we want + // to increase the chunk size or decrease the interval + // time dynamically to match the large reference set? + var watchedFileSet = createWatchedFileSet(); + function isNode4OrLater() { + return parseInt(process.version.charAt(1)) >= 4; + } var platform = _os.platform(); // win32\win64 are case insensitive platforms, MacOS (darwin) by default is also case insensitive var useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin"; @@ -1822,22 +1938,32 @@ var ts; readFile: readFile, writeFile: writeFile, watchFile: function (fileName, callback) { - // watchFile polls a file every 250ms, picking up file notifications. - _fs.watchFile(fileName, { persistent: true, interval: 250 }, fileChanged); - return { - close: function () { _fs.unwatchFile(fileName, fileChanged); } - }; - function fileChanged(curr, prev) { - // mtime.getTime() equals 0 if file was removed - if (curr.mtime.getTime() === 0) { - callback(fileName, /* removed */ true); - return; - } - if (+curr.mtime <= +prev.mtime) { - return; - } - callback(fileName, /* removed */ false); + // Node 4.0 stablized the `fs.watch` function on Windows which avoids polling + // and is more efficient than `fs.watchFile` (ref: https://github.com/nodejs/node/pull/2649 + // and https://github.com/Microsoft/TypeScript/issues/4643), therefore + // if the current node.js version is newer than 4, use `fs.watch` instead. + if (isNode4OrLater()) { + // Note: in node the callback of fs.watch is given only the relative file name as a parameter + return _fs.watch(fileName, function (eventName, relativeFileName) { return callback(fileName); }); } + var watchedFile = watchedFileSet.addFile(fileName, callback); + return { + close: function () { return watchedFileSet.removeFile(watchedFile); } + }; + }, + watchDirectory: function (path, callback, recursive) { + // Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows + // (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643) + return _fs.watch(path, { persisten: true, recursive: !!recursive }, function (eventName, relativeFileName) { + // In watchDirectory we only care about adding and removing files (when event name is + // "rename"); changes made within files are handled by corresponding fileWatchers (when + // event name is "change") + if (eventName === "rename") { + // When deleting a file, the passed baseFileName is null + callback(!relativeFileName ? relativeFileName : ts.normalizePath(ts.combinePaths(path, relativeFileName))); + } + ; + }); }, resolvePath: function (path) { return _path.resolve(path); @@ -2295,7 +2421,6 @@ var ts; Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2: { code: 2515, category: ts.DiagnosticCategory.Error, key: "Non-abstract class '{0}' does not implement inherited abstract member '{1}' from class '{2}'." }, All_declarations_of_an_abstract_method_must_be_consecutive: { code: 2516, category: ts.DiagnosticCategory.Error, key: "All declarations of an abstract method must be consecutive." }, Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type: { code: 2517, category: ts.DiagnosticCategory.Error, key: "Cannot assign an abstract constructor type to a non-abstract constructor type." }, - Only_an_ambient_class_can_be_merged_with_an_interface: { code: 2518, category: ts.DiagnosticCategory.Error, key: "Only an ambient class can be merged with an interface." }, Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions: { code: 2520, category: ts.DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions." }, Expression_resolves_to_variable_declaration_0_that_compiler_uses_to_support_async_functions: { code: 2521, category: ts.DiagnosticCategory.Error, key: "Expression resolves to variable declaration '{0}' that compiler uses to support async functions." }, The_arguments_object_cannot_be_referenced_in_an_async_arrow_function_Consider_using_a_standard_async_function_expression: { code: 2522, category: ts.DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an async arrow function. Consider using a standard async function expression." }, @@ -6015,7 +6140,8 @@ var ts; return expression.kind === 168 /* CallExpression */ && expression.expression.kind === 69 /* Identifier */ && expression.expression.text === "require" && - expression.arguments.length === 1; + expression.arguments.length === 1 && + expression.arguments[0].kind === 9 /* StringLiteral */; } ts.isRequireCall = isRequireCall; /** @@ -7343,6 +7469,16 @@ var ts; } } ts.getTypeParameterOwner = getTypeParameterOwner; + function arrayStructurallyIsEqualTo(array1, array2) { + if (!array1 || !array2) { + return false; + } + if (array1.length !== array2.length) { + return false; + } + return ts.arrayIsEqualTo(array1.sort(), array2.sort()); + } + ts.arrayStructurallyIsEqualTo = arrayStructurallyIsEqualTo; })(ts || (ts = {})); /// /// @@ -16615,7 +16751,9 @@ var ts; function getSignatureFromDeclaration(declaration) { var links = getNodeLinks(declaration); if (!links.resolvedSignature) { - var classType = declaration.kind === 144 /* Constructor */ ? getDeclaredTypeOfClassOrInterface(declaration.parent.symbol) : undefined; + var classType = declaration.kind === 144 /* Constructor */ ? + getDeclaredTypeOfClassOrInterface(getMergedSymbol(declaration.parent.symbol)) + : undefined; var typeParameters = classType ? classType.localTypeParameters : declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) : undefined; var parameters = []; @@ -21114,35 +21252,33 @@ var ts; */ function getEffectiveDecoratorFirstArgumentType(node) { // The first argument to a decorator is its `target`. - switch (node.kind) { - case 214 /* ClassDeclaration */: - case 186 /* ClassExpression */: - // For a class decorator, the `target` is the type of the class (e.g. the - // "static" or "constructor" side of the class) + if (node.kind === 214 /* ClassDeclaration */) { + // For a class decorator, the `target` is the type of the class (e.g. the + // "static" or "constructor" side of the class) + var classSymbol = getSymbolOfNode(node); + return getTypeOfSymbol(classSymbol); + } + if (node.kind === 138 /* Parameter */) { + // For a parameter decorator, the `target` is the parent type of the + // parameter's containing method. + node = node.parent; + if (node.kind === 144 /* Constructor */) { var classSymbol = getSymbolOfNode(node); return getTypeOfSymbol(classSymbol); - case 138 /* Parameter */: - // For a parameter decorator, the `target` is the parent type of the - // parameter's containing method. - node = node.parent; - if (node.kind === 144 /* Constructor */) { - var classSymbol_1 = getSymbolOfNode(node); - return getTypeOfSymbol(classSymbol_1); - } - // fall-through - case 141 /* PropertyDeclaration */: - case 143 /* MethodDeclaration */: - case 145 /* GetAccessor */: - case 146 /* SetAccessor */: - // For a property or method decorator, the `target` is the - // "static"-side type of the parent of the member if the member is - // declared "static"; otherwise, it is the "instance"-side type of the - // parent of the member. - return getParentTypeOfClassElement(node); - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + } } + if (node.kind === 141 /* PropertyDeclaration */ || + node.kind === 143 /* MethodDeclaration */ || + node.kind === 145 /* GetAccessor */ || + node.kind === 146 /* SetAccessor */) { + // For a property or method decorator, the `target` is the + // "static"-side type of the parent of the member if the member is + // declared "static"; otherwise, it is the "instance"-side type of the + // parent of the member. + return getParentTypeOfClassElement(node); + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } /** * Returns the effective type for the second argument to a decorator. @@ -21161,49 +21297,46 @@ var ts; */ function getEffectiveDecoratorSecondArgumentType(node) { // The second argument to a decorator is its `propertyKey` - switch (node.kind) { - case 214 /* ClassDeclaration */: - ts.Debug.fail("Class decorators should not have a second synthetic argument."); - return unknownType; - case 138 /* Parameter */: - node = node.parent; - if (node.kind === 144 /* Constructor */) { - // For a constructor parameter decorator, the `propertyKey` will be `undefined`. - return anyType; - } - // For a non-constructor parameter decorator, the `propertyKey` will be either - // a string or a symbol, based on the name of the parameter's containing method. - // fall-through - case 141 /* PropertyDeclaration */: - case 143 /* MethodDeclaration */: - case 145 /* GetAccessor */: - case 146 /* SetAccessor */: - // The `propertyKey` for a property or method decorator will be a - // string literal type if the member name is an identifier, number, or string; - // otherwise, if the member name is a computed property name it will - // be either string or symbol. - var element = node; - switch (element.name.kind) { - case 69 /* Identifier */: - case 8 /* NumericLiteral */: - case 9 /* StringLiteral */: - return getStringLiteralType(element.name); - case 136 /* ComputedPropertyName */: - var nameType = checkComputedPropertyName(element.name); - if (allConstituentTypesHaveKind(nameType, 16777216 /* ESSymbol */)) { - return nameType; - } - else { - return stringType; - } - default: - ts.Debug.fail("Unsupported property name."); - return unknownType; - } - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + if (node.kind === 214 /* ClassDeclaration */) { + ts.Debug.fail("Class decorators should not have a second synthetic argument."); + return unknownType; } + if (node.kind === 138 /* Parameter */) { + node = node.parent; + if (node.kind === 144 /* Constructor */) { + // For a constructor parameter decorator, the `propertyKey` will be `undefined`. + return anyType; + } + } + if (node.kind === 141 /* PropertyDeclaration */ || + node.kind === 143 /* MethodDeclaration */ || + node.kind === 145 /* GetAccessor */ || + node.kind === 146 /* SetAccessor */) { + // The `propertyKey` for a property or method decorator will be a + // string literal type if the member name is an identifier, number, or string; + // otherwise, if the member name is a computed property name it will + // be either string or symbol. + var element = node; + switch (element.name.kind) { + case 69 /* Identifier */: + case 8 /* NumericLiteral */: + case 9 /* StringLiteral */: + return getStringLiteralType(element.name); + case 136 /* ComputedPropertyName */: + var nameType = checkComputedPropertyName(element.name); + if (allConstituentTypesHaveKind(nameType, 16777216 /* ESSymbol */)) { + return nameType; + } + else { + return stringType; + } + default: + ts.Debug.fail("Unsupported property name."); + return unknownType; + } + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } /** * Returns the effective argument type for the third argument to a decorator. @@ -21215,27 +21348,28 @@ var ts; function getEffectiveDecoratorThirdArgumentType(node) { // The third argument to a decorator is either its `descriptor` for a method decorator // or its `parameterIndex` for a paramter decorator - switch (node.kind) { - case 214 /* ClassDeclaration */: - ts.Debug.fail("Class decorators should not have a third synthetic argument."); - return unknownType; - case 138 /* Parameter */: - // The `parameterIndex` for a parameter decorator is always a number - return numberType; - case 141 /* PropertyDeclaration */: - ts.Debug.fail("Property decorators should not have a third synthetic argument."); - return unknownType; - case 143 /* MethodDeclaration */: - case 145 /* GetAccessor */: - case 146 /* SetAccessor */: - // The `descriptor` for a method decorator will be a `TypedPropertyDescriptor` - // for the type of the member. - var propertyType = getTypeOfNode(node); - return createTypedPropertyDescriptorType(propertyType); - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + if (node.kind === 214 /* ClassDeclaration */) { + ts.Debug.fail("Class decorators should not have a third synthetic argument."); + return unknownType; } + if (node.kind === 138 /* Parameter */) { + // The `parameterIndex` for a parameter decorator is always a number + return numberType; + } + if (node.kind === 141 /* PropertyDeclaration */) { + ts.Debug.fail("Property decorators should not have a third synthetic argument."); + return unknownType; + } + if (node.kind === 143 /* MethodDeclaration */ || + node.kind === 145 /* GetAccessor */ || + node.kind === 146 /* SetAccessor */) { + // The `descriptor` for a method decorator will be a `TypedPropertyDescriptor` + // for the type of the member. + var propertyType = getTypeOfNode(node); + return createTypedPropertyDescriptorType(propertyType); + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } /** * Returns the effective argument type for the provided argument to a decorator. @@ -23262,7 +23396,12 @@ var ts; } function getEffectiveDeclarationFlags(n, flagsToCheck) { var flags = ts.getCombinedNodeFlags(n); - if (n.parent.kind !== 215 /* InterfaceDeclaration */ && ts.isInAmbientContext(n)) { + // children of classes (even ambient classes) should not be marked as ambient or export + // because those flags have no useful semantics there. + if (n.parent.kind !== 215 /* InterfaceDeclaration */ && + n.parent.kind !== 214 /* ClassDeclaration */ && + n.parent.kind !== 186 /* ClassExpression */ && + ts.isInAmbientContext(n)) { if (!(flags & 2 /* Ambient */)) { // It is nested in an ambient context, which means it is automatically exported flags |= 1 /* Export */; @@ -24856,10 +24995,6 @@ var ts; grammarErrorOnFirstToken(node, ts.Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); } checkClassLikeDeclaration(node); - // Interfaces cannot be merged with non-ambient classes. - if (getSymbolOfNode(node).flags & 64 /* Interface */ && !ts.isInAmbientContext(node)) { - error(node, ts.Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface); - } ts.forEach(node.members, checkSourceElement); } function checkClassLikeDeclaration(node) { @@ -25116,16 +25251,6 @@ var ts; checkIndexConstraints(type); } } - // Interfaces cannot merge with non-ambient classes. - if (symbol && symbol.declarations) { - for (var _b = 0, _c = symbol.declarations; _b < _c.length; _b++) { - var declaration = _c[_b]; - if (declaration.kind === 214 /* ClassDeclaration */ && !ts.isInAmbientContext(declaration)) { - error(node, ts.Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface); - break; - } - } - } } ts.forEach(ts.getInterfaceBaseTypeNodes(node), function (heritageElement) { if (!ts.isSupportedExpressionWithTypeArguments(heritageElement)) { @@ -35959,7 +36084,7 @@ var ts; /* @internal */ ts.ioWriteTime = 0; /** The version of the TypeScript compiler release */ var emptyArray = []; - ts.version = "1.7.0"; + ts.version = "1.8.0"; function findConfigFile(searchPath) { var fileName = "tsconfig.json"; while (true) { @@ -36963,7 +37088,8 @@ var ts; "amd": 2 /* AMD */, "system": 4 /* System */, "umd": 3 /* UMD */, - "es6": 5 /* ES6 */ + "es6": 5 /* ES6 */, + "es2015": 5 /* ES2015 */ }, description: ts.Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_or_es6, paramType: ts.Diagnostics.KIND, @@ -37092,7 +37218,12 @@ var ts; { name: "target", shortName: "t", - type: { "es3": 0 /* ES3 */, "es5": 1 /* ES5 */, "es6": 2 /* ES6 */ }, + type: { + "es3": 0 /* ES3 */, + "es5": 1 /* ES5 */, + "es6": 2 /* ES6 */, + "es2015": 2 /* ES2015 */ + }, 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 @@ -37257,7 +37388,7 @@ var ts; catch (e) { return { error: ts.createCompilerDiagnostic(ts.Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message) }; } - return parseConfigFileText(fileName, text); + return parseConfigFileTextToJson(fileName, text); } ts.readConfigFile = readConfigFile; /** @@ -37265,7 +37396,7 @@ var ts; * @param fileName The path to the config file * @param jsonText The text of the config file */ - function parseConfigFileText(fileName, jsonText) { + function parseConfigFileTextToJson(fileName, jsonText) { try { return { config: /\S/.test(jsonText) ? JSON.parse(jsonText) : {} }; } @@ -37273,14 +37404,14 @@ var ts; return { error: ts.createCompilerDiagnostic(ts.Diagnostics.Failed_to_parse_file_0_Colon_1, fileName, e.message) }; } } - ts.parseConfigFileText = parseConfigFileText; + ts.parseConfigFileTextToJson = parseConfigFileTextToJson; /** * 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 */ - function parseConfigFile(json, host, basePath) { + function parseJsonConfigFileContent(json, host, basePath) { var errors = []; return { options: getCompilerOptions(), @@ -37365,7 +37496,7 @@ var ts; return fileNames; } } - ts.parseConfigFile = parseConfigFile; + ts.parseJsonConfigFileContent = parseJsonConfigFileContent; })(ts || (ts = {})); /* @internal */ var ts; @@ -50293,7 +50424,7 @@ var ts; var _this = this; return this.forwardJSONCall("getTSConfigFileInfo('" + fileName + "')", function () { var text = sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()); - var result = ts.parseConfigFileText(fileName, text); + var result = ts.parseConfigFileTextToJson(fileName, text); if (result.error) { return { options: {}, @@ -50301,7 +50432,7 @@ var ts; errors: [realizeDiagnostic(result.error, '\r\n')] }; } - var configFile = ts.parseConfigFile(result.config, _this.host, ts.getDirectoryPath(ts.normalizeSlashes(fileName))); + var configFile = ts.parseJsonConfigFileContent(result.config, _this.host, ts.getDirectoryPath(ts.normalizeSlashes(fileName))); return { options: configFile.options, files: configFile.fileNames, diff --git a/lib/typescriptServices.d.ts b/lib/typescriptServices.d.ts index 8e6c6a553a5..3f012c97b5e 100644 --- a/lib/typescriptServices.d.ts +++ b/lib/typescriptServices.d.ts @@ -1359,6 +1359,7 @@ declare namespace ts { UMD = 3, System = 4, ES6 = 5, + ES2015 = 5, } const enum JsxEmit { None = 0, @@ -1377,6 +1378,7 @@ declare namespace ts { ES3 = 0, ES5 = 1, ES6 = 2, + ES2015 = 2, Latest = 2, } const enum LanguageVariant { @@ -1428,7 +1430,8 @@ declare namespace ts { write(s: string): void; readFile(path: string, encoding?: string): string; writeFile(path: string, data: string, writeByteOrderMark?: boolean): void; - watchFile?(path: string, callback: (path: string, removed: boolean) => void): FileWatcher; + watchFile?(path: string, callback: (path: string, removed?: boolean) => void): FileWatcher; + watchDirectory?(path: string, callback: (path: string) => void, recursive?: boolean): FileWatcher; resolvePath(path: string): string; fileExists(path: string): boolean; directoryExists(path: string): boolean; @@ -1518,6 +1521,7 @@ declare namespace ts { */ function collapseTextChangeRangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange; function getTypeParameterOwner(d: Declaration): Declaration; + function arrayStructurallyIsEqualTo(array1: Array, array2: Array): boolean; } declare namespace ts { function getNodeConstructor(kind: SyntaxKind): new () => Node; @@ -1553,7 +1557,7 @@ declare namespace ts { * @param fileName The path to the config file * @param jsonText The text of the config file */ - function parseConfigFileText(fileName: string, jsonText: string): { + function parseConfigFileTextToJson(fileName: string, jsonText: string): { config?: any; error?: Diagnostic; }; @@ -1563,7 +1567,7 @@ declare namespace ts { * @param basePath A root directory to resolve relative path entries in the config * file to. e.g. outDir */ - function parseConfigFile(json: any, host: ParseConfigHost, basePath: string): ParsedCommandLine; + function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string): ParsedCommandLine; } declare namespace ts { /** The version of the language service API */ diff --git a/lib/typescriptServices.js b/lib/typescriptServices.js index d261ce125fc..5fec75307d0 100644 --- a/lib/typescriptServices.js +++ b/lib/typescriptServices.js @@ -660,6 +660,7 @@ var ts; ModuleKind[ModuleKind["UMD"] = 3] = "UMD"; ModuleKind[ModuleKind["System"] = 4] = "System"; ModuleKind[ModuleKind["ES6"] = 5] = "ES6"; + ModuleKind[ModuleKind["ES2015"] = 5] = "ES2015"; })(ts.ModuleKind || (ts.ModuleKind = {})); var ModuleKind = ts.ModuleKind; (function (JsxEmit) { @@ -677,6 +678,7 @@ var ts; ScriptTarget[ScriptTarget["ES3"] = 0] = "ES3"; ScriptTarget[ScriptTarget["ES5"] = 1] = "ES5"; ScriptTarget[ScriptTarget["ES6"] = 2] = "ES6"; + ScriptTarget[ScriptTarget["ES2015"] = 2] = "ES2015"; ScriptTarget[ScriptTarget["Latest"] = 2] = "Latest"; })(ts.ScriptTarget || (ts.ScriptTarget = {})); var ScriptTarget = ts.ScriptTarget; @@ -1478,6 +1480,9 @@ var ts; } ts.getRelativePathToDirectoryOrUrl = getRelativePathToDirectoryOrUrl; function getBaseFileName(path) { + if (!path) { + return undefined; + } var i = path.lastIndexOf(ts.directorySeparator); return i < 0 ? path : path.substring(i + 1); } @@ -1505,6 +1510,19 @@ var ts; */ ts.supportedExtensions = [".ts", ".tsx", ".d.ts"]; ts.supportedJsExtensions = ts.supportedExtensions.concat(".js", ".jsx"); + function isSupportedSourceFileName(fileName) { + if (!fileName) { + return false; + } + for (var _i = 0; _i < ts.supportedExtensions.length; _i++) { + var extension = ts.supportedExtensions[_i]; + if (fileExtensionIs(fileName, extension)) { + return true; + } + } + return false; + } + ts.isSupportedSourceFileName = isSupportedSourceFileName; var extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"]; function removeFileExtension(path) { for (var _i = 0; _i < extensionsToRemove.length; _i++) { @@ -1588,6 +1606,16 @@ var ts; } Debug.fail = fail; })(Debug = ts.Debug || (ts.Debug = {})); + function copyListRemovingItem(item, list) { + var copiedList = []; + for (var i = 0, len = list.length; i < len; i++) { + if (list[i] !== item) { + copiedList.push(list[i]); + } + } + return copiedList; + } + ts.copyListRemovingItem = copyListRemovingItem; })(ts || (ts = {})); /// var ts; @@ -1734,6 +1762,94 @@ var ts; var _fs = require("fs"); var _path = require("path"); var _os = require("os"); + // average async stat takes about 30 microseconds + // set chunk size to do 30 files in < 1 millisecond + function createWatchedFileSet(interval, chunkSize) { + if (interval === void 0) { interval = 2500; } + if (chunkSize === void 0) { chunkSize = 30; } + var watchedFiles = []; + var nextFileToCheck = 0; + var watchTimer; + function getModifiedTime(fileName) { + return _fs.statSync(fileName).mtime; + } + function poll(checkedIndex) { + var watchedFile = watchedFiles[checkedIndex]; + if (!watchedFile) { + return; + } + _fs.stat(watchedFile.fileName, function (err, stats) { + if (err) { + watchedFile.callback(watchedFile.fileName); + } + else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) { + watchedFile.mtime = getModifiedTime(watchedFile.fileName); + watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0); + } + }); + } + // this implementation uses polling and + // stat due to inconsistencies of fs.watch + // and efficiency of stat on modern filesystems + function startWatchTimer() { + watchTimer = setInterval(function () { + var count = 0; + var nextToCheck = nextFileToCheck; + var firstCheck = -1; + while ((count < chunkSize) && (nextToCheck !== firstCheck)) { + poll(nextToCheck); + if (firstCheck < 0) { + firstCheck = nextToCheck; + } + nextToCheck++; + if (nextToCheck === watchedFiles.length) { + nextToCheck = 0; + } + count++; + } + nextFileToCheck = nextToCheck; + }, interval); + } + function addFile(fileName, callback) { + var file = { + fileName: fileName, + callback: callback, + mtime: getModifiedTime(fileName) + }; + watchedFiles.push(file); + if (watchedFiles.length === 1) { + startWatchTimer(); + } + return file; + } + function removeFile(file) { + watchedFiles = ts.copyListRemovingItem(file, watchedFiles); + } + return { + getModifiedTime: getModifiedTime, + poll: poll, + startWatchTimer: startWatchTimer, + addFile: addFile, + removeFile: removeFile + }; + } + // REVIEW: for now this implementation uses polling. + // The advantage of polling is that it works reliably + // on all os and with network mounted files. + // For 90 referenced files, the average time to detect + // changes is 2*msInterval (by default 5 seconds). + // The overhead of this is .04 percent (1/2500) with + // average pause of < 1 millisecond (and max + // pause less than 1.5 milliseconds); question is + // do we anticipate reference sets in the 100s and + // do we care about waiting 10-20 seconds to detect + // changes for large reference sets? If so, do we want + // to increase the chunk size or decrease the interval + // time dynamically to match the large reference set? + var watchedFileSet = createWatchedFileSet(); + function isNode4OrLater() { + return parseInt(process.version.charAt(1)) >= 4; + } var platform = _os.platform(); // win32\win64 are case insensitive platforms, MacOS (darwin) by default is also case insensitive var useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin"; @@ -1822,22 +1938,32 @@ var ts; readFile: readFile, writeFile: writeFile, watchFile: function (fileName, callback) { - // watchFile polls a file every 250ms, picking up file notifications. - _fs.watchFile(fileName, { persistent: true, interval: 250 }, fileChanged); - return { - close: function () { _fs.unwatchFile(fileName, fileChanged); } - }; - function fileChanged(curr, prev) { - // mtime.getTime() equals 0 if file was removed - if (curr.mtime.getTime() === 0) { - callback(fileName, /* removed */ true); - return; - } - if (+curr.mtime <= +prev.mtime) { - return; - } - callback(fileName, /* removed */ false); + // Node 4.0 stablized the `fs.watch` function on Windows which avoids polling + // and is more efficient than `fs.watchFile` (ref: https://github.com/nodejs/node/pull/2649 + // and https://github.com/Microsoft/TypeScript/issues/4643), therefore + // if the current node.js version is newer than 4, use `fs.watch` instead. + if (isNode4OrLater()) { + // Note: in node the callback of fs.watch is given only the relative file name as a parameter + return _fs.watch(fileName, function (eventName, relativeFileName) { return callback(fileName); }); } + var watchedFile = watchedFileSet.addFile(fileName, callback); + return { + close: function () { return watchedFileSet.removeFile(watchedFile); } + }; + }, + watchDirectory: function (path, callback, recursive) { + // Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows + // (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643) + return _fs.watch(path, { persisten: true, recursive: !!recursive }, function (eventName, relativeFileName) { + // In watchDirectory we only care about adding and removing files (when event name is + // "rename"); changes made within files are handled by corresponding fileWatchers (when + // event name is "change") + if (eventName === "rename") { + // When deleting a file, the passed baseFileName is null + callback(!relativeFileName ? relativeFileName : ts.normalizePath(ts.combinePaths(path, relativeFileName))); + } + ; + }); }, resolvePath: function (path) { return _path.resolve(path); @@ -2295,7 +2421,6 @@ var ts; Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2: { code: 2515, category: ts.DiagnosticCategory.Error, key: "Non-abstract class '{0}' does not implement inherited abstract member '{1}' from class '{2}'." }, All_declarations_of_an_abstract_method_must_be_consecutive: { code: 2516, category: ts.DiagnosticCategory.Error, key: "All declarations of an abstract method must be consecutive." }, Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type: { code: 2517, category: ts.DiagnosticCategory.Error, key: "Cannot assign an abstract constructor type to a non-abstract constructor type." }, - Only_an_ambient_class_can_be_merged_with_an_interface: { code: 2518, category: ts.DiagnosticCategory.Error, key: "Only an ambient class can be merged with an interface." }, Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions: { code: 2520, category: ts.DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions." }, Expression_resolves_to_variable_declaration_0_that_compiler_uses_to_support_async_functions: { code: 2521, category: ts.DiagnosticCategory.Error, key: "Expression resolves to variable declaration '{0}' that compiler uses to support async functions." }, The_arguments_object_cannot_be_referenced_in_an_async_arrow_function_Consider_using_a_standard_async_function_expression: { code: 2522, category: ts.DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an async arrow function. Consider using a standard async function expression." }, @@ -6015,7 +6140,8 @@ var ts; return expression.kind === 168 /* CallExpression */ && expression.expression.kind === 69 /* Identifier */ && expression.expression.text === "require" && - expression.arguments.length === 1; + expression.arguments.length === 1 && + expression.arguments[0].kind === 9 /* StringLiteral */; } ts.isRequireCall = isRequireCall; /** @@ -7343,6 +7469,16 @@ var ts; } } ts.getTypeParameterOwner = getTypeParameterOwner; + function arrayStructurallyIsEqualTo(array1, array2) { + if (!array1 || !array2) { + return false; + } + if (array1.length !== array2.length) { + return false; + } + return ts.arrayIsEqualTo(array1.sort(), array2.sort()); + } + ts.arrayStructurallyIsEqualTo = arrayStructurallyIsEqualTo; })(ts || (ts = {})); /// /// @@ -16615,7 +16751,9 @@ var ts; function getSignatureFromDeclaration(declaration) { var links = getNodeLinks(declaration); if (!links.resolvedSignature) { - var classType = declaration.kind === 144 /* Constructor */ ? getDeclaredTypeOfClassOrInterface(declaration.parent.symbol) : undefined; + var classType = declaration.kind === 144 /* Constructor */ ? + getDeclaredTypeOfClassOrInterface(getMergedSymbol(declaration.parent.symbol)) + : undefined; var typeParameters = classType ? classType.localTypeParameters : declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) : undefined; var parameters = []; @@ -21114,35 +21252,33 @@ var ts; */ function getEffectiveDecoratorFirstArgumentType(node) { // The first argument to a decorator is its `target`. - switch (node.kind) { - case 214 /* ClassDeclaration */: - case 186 /* ClassExpression */: - // For a class decorator, the `target` is the type of the class (e.g. the - // "static" or "constructor" side of the class) + if (node.kind === 214 /* ClassDeclaration */) { + // For a class decorator, the `target` is the type of the class (e.g. the + // "static" or "constructor" side of the class) + var classSymbol = getSymbolOfNode(node); + return getTypeOfSymbol(classSymbol); + } + if (node.kind === 138 /* Parameter */) { + // For a parameter decorator, the `target` is the parent type of the + // parameter's containing method. + node = node.parent; + if (node.kind === 144 /* Constructor */) { var classSymbol = getSymbolOfNode(node); return getTypeOfSymbol(classSymbol); - case 138 /* Parameter */: - // For a parameter decorator, the `target` is the parent type of the - // parameter's containing method. - node = node.parent; - if (node.kind === 144 /* Constructor */) { - var classSymbol_1 = getSymbolOfNode(node); - return getTypeOfSymbol(classSymbol_1); - } - // fall-through - case 141 /* PropertyDeclaration */: - case 143 /* MethodDeclaration */: - case 145 /* GetAccessor */: - case 146 /* SetAccessor */: - // For a property or method decorator, the `target` is the - // "static"-side type of the parent of the member if the member is - // declared "static"; otherwise, it is the "instance"-side type of the - // parent of the member. - return getParentTypeOfClassElement(node); - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + } } + if (node.kind === 141 /* PropertyDeclaration */ || + node.kind === 143 /* MethodDeclaration */ || + node.kind === 145 /* GetAccessor */ || + node.kind === 146 /* SetAccessor */) { + // For a property or method decorator, the `target` is the + // "static"-side type of the parent of the member if the member is + // declared "static"; otherwise, it is the "instance"-side type of the + // parent of the member. + return getParentTypeOfClassElement(node); + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } /** * Returns the effective type for the second argument to a decorator. @@ -21161,49 +21297,46 @@ var ts; */ function getEffectiveDecoratorSecondArgumentType(node) { // The second argument to a decorator is its `propertyKey` - switch (node.kind) { - case 214 /* ClassDeclaration */: - ts.Debug.fail("Class decorators should not have a second synthetic argument."); - return unknownType; - case 138 /* Parameter */: - node = node.parent; - if (node.kind === 144 /* Constructor */) { - // For a constructor parameter decorator, the `propertyKey` will be `undefined`. - return anyType; - } - // For a non-constructor parameter decorator, the `propertyKey` will be either - // a string or a symbol, based on the name of the parameter's containing method. - // fall-through - case 141 /* PropertyDeclaration */: - case 143 /* MethodDeclaration */: - case 145 /* GetAccessor */: - case 146 /* SetAccessor */: - // The `propertyKey` for a property or method decorator will be a - // string literal type if the member name is an identifier, number, or string; - // otherwise, if the member name is a computed property name it will - // be either string or symbol. - var element = node; - switch (element.name.kind) { - case 69 /* Identifier */: - case 8 /* NumericLiteral */: - case 9 /* StringLiteral */: - return getStringLiteralType(element.name); - case 136 /* ComputedPropertyName */: - var nameType = checkComputedPropertyName(element.name); - if (allConstituentTypesHaveKind(nameType, 16777216 /* ESSymbol */)) { - return nameType; - } - else { - return stringType; - } - default: - ts.Debug.fail("Unsupported property name."); - return unknownType; - } - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + if (node.kind === 214 /* ClassDeclaration */) { + ts.Debug.fail("Class decorators should not have a second synthetic argument."); + return unknownType; } + if (node.kind === 138 /* Parameter */) { + node = node.parent; + if (node.kind === 144 /* Constructor */) { + // For a constructor parameter decorator, the `propertyKey` will be `undefined`. + return anyType; + } + } + if (node.kind === 141 /* PropertyDeclaration */ || + node.kind === 143 /* MethodDeclaration */ || + node.kind === 145 /* GetAccessor */ || + node.kind === 146 /* SetAccessor */) { + // The `propertyKey` for a property or method decorator will be a + // string literal type if the member name is an identifier, number, or string; + // otherwise, if the member name is a computed property name it will + // be either string or symbol. + var element = node; + switch (element.name.kind) { + case 69 /* Identifier */: + case 8 /* NumericLiteral */: + case 9 /* StringLiteral */: + return getStringLiteralType(element.name); + case 136 /* ComputedPropertyName */: + var nameType = checkComputedPropertyName(element.name); + if (allConstituentTypesHaveKind(nameType, 16777216 /* ESSymbol */)) { + return nameType; + } + else { + return stringType; + } + default: + ts.Debug.fail("Unsupported property name."); + return unknownType; + } + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } /** * Returns the effective argument type for the third argument to a decorator. @@ -21215,27 +21348,28 @@ var ts; function getEffectiveDecoratorThirdArgumentType(node) { // The third argument to a decorator is either its `descriptor` for a method decorator // or its `parameterIndex` for a paramter decorator - switch (node.kind) { - case 214 /* ClassDeclaration */: - ts.Debug.fail("Class decorators should not have a third synthetic argument."); - return unknownType; - case 138 /* Parameter */: - // The `parameterIndex` for a parameter decorator is always a number - return numberType; - case 141 /* PropertyDeclaration */: - ts.Debug.fail("Property decorators should not have a third synthetic argument."); - return unknownType; - case 143 /* MethodDeclaration */: - case 145 /* GetAccessor */: - case 146 /* SetAccessor */: - // The `descriptor` for a method decorator will be a `TypedPropertyDescriptor` - // for the type of the member. - var propertyType = getTypeOfNode(node); - return createTypedPropertyDescriptorType(propertyType); - default: - ts.Debug.fail("Unsupported decorator target."); - return unknownType; + if (node.kind === 214 /* ClassDeclaration */) { + ts.Debug.fail("Class decorators should not have a third synthetic argument."); + return unknownType; } + if (node.kind === 138 /* Parameter */) { + // The `parameterIndex` for a parameter decorator is always a number + return numberType; + } + if (node.kind === 141 /* PropertyDeclaration */) { + ts.Debug.fail("Property decorators should not have a third synthetic argument."); + return unknownType; + } + if (node.kind === 143 /* MethodDeclaration */ || + node.kind === 145 /* GetAccessor */ || + node.kind === 146 /* SetAccessor */) { + // The `descriptor` for a method decorator will be a `TypedPropertyDescriptor` + // for the type of the member. + var propertyType = getTypeOfNode(node); + return createTypedPropertyDescriptorType(propertyType); + } + ts.Debug.fail("Unsupported decorator target."); + return unknownType; } /** * Returns the effective argument type for the provided argument to a decorator. @@ -23262,7 +23396,12 @@ var ts; } function getEffectiveDeclarationFlags(n, flagsToCheck) { var flags = ts.getCombinedNodeFlags(n); - if (n.parent.kind !== 215 /* InterfaceDeclaration */ && ts.isInAmbientContext(n)) { + // children of classes (even ambient classes) should not be marked as ambient or export + // because those flags have no useful semantics there. + if (n.parent.kind !== 215 /* InterfaceDeclaration */ && + n.parent.kind !== 214 /* ClassDeclaration */ && + n.parent.kind !== 186 /* ClassExpression */ && + ts.isInAmbientContext(n)) { if (!(flags & 2 /* Ambient */)) { // It is nested in an ambient context, which means it is automatically exported flags |= 1 /* Export */; @@ -24856,10 +24995,6 @@ var ts; grammarErrorOnFirstToken(node, ts.Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); } checkClassLikeDeclaration(node); - // Interfaces cannot be merged with non-ambient classes. - if (getSymbolOfNode(node).flags & 64 /* Interface */ && !ts.isInAmbientContext(node)) { - error(node, ts.Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface); - } ts.forEach(node.members, checkSourceElement); } function checkClassLikeDeclaration(node) { @@ -25116,16 +25251,6 @@ var ts; checkIndexConstraints(type); } } - // Interfaces cannot merge with non-ambient classes. - if (symbol && symbol.declarations) { - for (var _b = 0, _c = symbol.declarations; _b < _c.length; _b++) { - var declaration = _c[_b]; - if (declaration.kind === 214 /* ClassDeclaration */ && !ts.isInAmbientContext(declaration)) { - error(node, ts.Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface); - break; - } - } - } } ts.forEach(ts.getInterfaceBaseTypeNodes(node), function (heritageElement) { if (!ts.isSupportedExpressionWithTypeArguments(heritageElement)) { @@ -35959,7 +36084,7 @@ var ts; /* @internal */ ts.ioWriteTime = 0; /** The version of the TypeScript compiler release */ var emptyArray = []; - ts.version = "1.7.0"; + ts.version = "1.8.0"; function findConfigFile(searchPath) { var fileName = "tsconfig.json"; while (true) { @@ -36963,7 +37088,8 @@ var ts; "amd": 2 /* AMD */, "system": 4 /* System */, "umd": 3 /* UMD */, - "es6": 5 /* ES6 */ + "es6": 5 /* ES6 */, + "es2015": 5 /* ES2015 */ }, description: ts.Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_or_es6, paramType: ts.Diagnostics.KIND, @@ -37092,7 +37218,12 @@ var ts; { name: "target", shortName: "t", - type: { "es3": 0 /* ES3 */, "es5": 1 /* ES5 */, "es6": 2 /* ES6 */ }, + type: { + "es3": 0 /* ES3 */, + "es5": 1 /* ES5 */, + "es6": 2 /* ES6 */, + "es2015": 2 /* ES2015 */ + }, 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 @@ -37257,7 +37388,7 @@ var ts; catch (e) { return { error: ts.createCompilerDiagnostic(ts.Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message) }; } - return parseConfigFileText(fileName, text); + return parseConfigFileTextToJson(fileName, text); } ts.readConfigFile = readConfigFile; /** @@ -37265,7 +37396,7 @@ var ts; * @param fileName The path to the config file * @param jsonText The text of the config file */ - function parseConfigFileText(fileName, jsonText) { + function parseConfigFileTextToJson(fileName, jsonText) { try { return { config: /\S/.test(jsonText) ? JSON.parse(jsonText) : {} }; } @@ -37273,14 +37404,14 @@ var ts; return { error: ts.createCompilerDiagnostic(ts.Diagnostics.Failed_to_parse_file_0_Colon_1, fileName, e.message) }; } } - ts.parseConfigFileText = parseConfigFileText; + ts.parseConfigFileTextToJson = parseConfigFileTextToJson; /** * 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 */ - function parseConfigFile(json, host, basePath) { + function parseJsonConfigFileContent(json, host, basePath) { var errors = []; return { options: getCompilerOptions(), @@ -37365,7 +37496,7 @@ var ts; return fileNames; } } - ts.parseConfigFile = parseConfigFile; + ts.parseJsonConfigFileContent = parseJsonConfigFileContent; })(ts || (ts = {})); /* @internal */ var ts; @@ -50293,7 +50424,7 @@ var ts; var _this = this; return this.forwardJSONCall("getTSConfigFileInfo('" + fileName + "')", function () { var text = sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()); - var result = ts.parseConfigFileText(fileName, text); + var result = ts.parseConfigFileTextToJson(fileName, text); if (result.error) { return { options: {}, @@ -50301,7 +50432,7 @@ var ts; errors: [realizeDiagnostic(result.error, '\r\n')] }; } - var configFile = ts.parseConfigFile(result.config, _this.host, ts.getDirectoryPath(ts.normalizeSlashes(fileName))); + var configFile = ts.parseJsonConfigFileContent(result.config, _this.host, ts.getDirectoryPath(ts.normalizeSlashes(fileName))); return { options: configFile.options, files: configFile.fileNames, diff --git a/package.json b/package.json index 28f2c1b5755..7b8abfaae43 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "typescript", "author": "Microsoft Corp.", "homepage": "http://typescriptlang.org/", - "version": "1.7.0", + "version": "1.8.0", "license": "Apache-2.0", "description": "TypeScript is a language for application scale JavaScript development", "keywords": [ diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index aa3e9b44815..ac5056bf769 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3729,7 +3729,9 @@ namespace ts { function getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature { let links = getNodeLinks(declaration); if (!links.resolvedSignature) { - let classType = declaration.kind === SyntaxKind.Constructor ? getDeclaredTypeOfClassOrInterface((declaration.parent).symbol) : undefined; + let classType = declaration.kind === SyntaxKind.Constructor ? + getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent).symbol)) + : undefined; let typeParameters = classType ? classType.localTypeParameters : declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) : undefined; let parameters: Symbol[] = []; @@ -8677,39 +8679,36 @@ namespace ts { */ function getEffectiveDecoratorFirstArgumentType(node: Node): Type { // The first argument to a decorator is its `target`. - switch (node.kind) { - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - // For a class decorator, the `target` is the type of the class (e.g. the - // "static" or "constructor" side of the class) + if (node.kind === SyntaxKind.ClassDeclaration) { + // For a class decorator, the `target` is the type of the class (e.g. the + // "static" or "constructor" side of the class) + let classSymbol = getSymbolOfNode(node); + return getTypeOfSymbol(classSymbol); + } + + if (node.kind === SyntaxKind.Parameter) { + // For a parameter decorator, the `target` is the parent type of the + // parameter's containing method. + node = node.parent; + if (node.kind === SyntaxKind.Constructor) { let classSymbol = getSymbolOfNode(node); return getTypeOfSymbol(classSymbol); - - case SyntaxKind.Parameter: - // For a parameter decorator, the `target` is the parent type of the - // parameter's containing method. - node = node.parent; - if (node.kind === SyntaxKind.Constructor) { - let classSymbol = getSymbolOfNode(node); - return getTypeOfSymbol(classSymbol); - } - - // fall-through - - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - // For a property or method decorator, the `target` is the - // "static"-side type of the parent of the member if the member is - // declared "static"; otherwise, it is the "instance"-side type of the - // parent of the member. - return getParentTypeOfClassElement(node); - - default: - Debug.fail("Unsupported decorator target."); - return unknownType; + } } + + if (node.kind === SyntaxKind.PropertyDeclaration || + node.kind === SyntaxKind.MethodDeclaration || + node.kind === SyntaxKind.GetAccessor || + node.kind === SyntaxKind.SetAccessor) { + // For a property or method decorator, the `target` is the + // "static"-side type of the parent of the member if the member is + // declared "static"; otherwise, it is the "instance"-side type of the + // parent of the member. + return getParentTypeOfClassElement(node); + } + + Debug.fail("Unsupported decorator target."); + return unknownType; } /** @@ -8729,57 +8728,54 @@ namespace ts { */ function getEffectiveDecoratorSecondArgumentType(node: Node) { // The second argument to a decorator is its `propertyKey` - switch (node.kind) { - case SyntaxKind.ClassDeclaration: - Debug.fail("Class decorators should not have a second synthetic argument."); - return unknownType; + if (node.kind === SyntaxKind.ClassDeclaration) { + Debug.fail("Class decorators should not have a second synthetic argument."); + return unknownType; + } - case SyntaxKind.Parameter: - node = node.parent; - if (node.kind === SyntaxKind.Constructor) { - // For a constructor parameter decorator, the `propertyKey` will be `undefined`. - return anyType; - } + if (node.kind === SyntaxKind.Parameter) { + node = node.parent; + if (node.kind === SyntaxKind.Constructor) { + // For a constructor parameter decorator, the `propertyKey` will be `undefined`. + return anyType; + } // For a non-constructor parameter decorator, the `propertyKey` will be either // a string or a symbol, based on the name of the parameter's containing method. - - // fall-through - - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - // The `propertyKey` for a property or method decorator will be a - // string literal type if the member name is an identifier, number, or string; - // otherwise, if the member name is a computed property name it will - // be either string or symbol. - let element = node; - switch (element.name.kind) { - case SyntaxKind.Identifier: - case SyntaxKind.NumericLiteral: - case SyntaxKind.StringLiteral: - return getStringLiteralType(element.name); - - case SyntaxKind.ComputedPropertyName: - let nameType = checkComputedPropertyName(element.name); - if (allConstituentTypesHaveKind(nameType, TypeFlags.ESSymbol)) { - return nameType; - } - else { - return stringType; - } - - default: - Debug.fail("Unsupported property name."); - return unknownType; - } - - - default: - Debug.fail("Unsupported decorator target."); - return unknownType; } + + if (node.kind === SyntaxKind.PropertyDeclaration || + node.kind === SyntaxKind.MethodDeclaration || + node.kind === SyntaxKind.GetAccessor || + node.kind === SyntaxKind.SetAccessor) { + // The `propertyKey` for a property or method decorator will be a + // string literal type if the member name is an identifier, number, or string; + // otherwise, if the member name is a computed property name it will + // be either string or symbol. + let element = node; + switch (element.name.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + return getStringLiteralType(element.name); + + case SyntaxKind.ComputedPropertyName: + let nameType = checkComputedPropertyName(element.name); + if (allConstituentTypesHaveKind(nameType, TypeFlags.ESSymbol)) { + return nameType; + } + else { + return stringType; + } + + default: + Debug.fail("Unsupported property name."); + return unknownType; + } + } + + Debug.fail("Unsupported decorator target."); + return unknownType; } /** @@ -8792,31 +8788,32 @@ namespace ts { function getEffectiveDecoratorThirdArgumentType(node: Node) { // The third argument to a decorator is either its `descriptor` for a method decorator // or its `parameterIndex` for a paramter decorator - switch (node.kind) { - case SyntaxKind.ClassDeclaration: - Debug.fail("Class decorators should not have a third synthetic argument."); - return unknownType; - - case SyntaxKind.Parameter: - // The `parameterIndex` for a parameter decorator is always a number - return numberType; - - case SyntaxKind.PropertyDeclaration: - Debug.fail("Property decorators should not have a third synthetic argument."); - return unknownType; - - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - // The `descriptor` for a method decorator will be a `TypedPropertyDescriptor` - // for the type of the member. - let propertyType = getTypeOfNode(node); - return createTypedPropertyDescriptorType(propertyType); - - default: - Debug.fail("Unsupported decorator target."); - return unknownType; + if (node.kind === SyntaxKind.ClassDeclaration) { + Debug.fail("Class decorators should not have a third synthetic argument."); + return unknownType; } + + if (node.kind === SyntaxKind.Parameter) { + // The `parameterIndex` for a parameter decorator is always a number + return numberType; + } + + if (node.kind === SyntaxKind.PropertyDeclaration) { + Debug.fail("Property decorators should not have a third synthetic argument."); + return unknownType; + } + + if (node.kind === SyntaxKind.MethodDeclaration || + node.kind === SyntaxKind.GetAccessor || + node.kind === SyntaxKind.SetAccessor) { + // The `descriptor` for a method decorator will be a `TypedPropertyDescriptor` + // for the type of the member. + let propertyType = getTypeOfNode(node); + return createTypedPropertyDescriptorType(propertyType); + } + + Debug.fail("Unsupported decorator target."); + return unknownType; } /** @@ -11088,7 +11085,13 @@ namespace ts { function getEffectiveDeclarationFlags(n: Node, flagsToCheck: NodeFlags): NodeFlags { let flags = getCombinedNodeFlags(n); - if (n.parent.kind !== SyntaxKind.InterfaceDeclaration && isInAmbientContext(n)) { + + // children of classes (even ambient classes) should not be marked as ambient or export + // because those flags have no useful semantics there. + if (n.parent.kind !== SyntaxKind.InterfaceDeclaration && + n.parent.kind !== SyntaxKind.ClassDeclaration && + n.parent.kind !== SyntaxKind.ClassExpression && + isInAmbientContext(n)) { if (!(flags & NodeFlags.Ambient)) { // It is nested in an ambient context, which means it is automatically exported flags |= NodeFlags.Export; @@ -12911,11 +12914,6 @@ namespace ts { } checkClassLikeDeclaration(node); - // Interfaces cannot be merged with non-ambient classes. - if (getSymbolOfNode(node).flags & SymbolFlags.Interface && !isInAmbientContext(node)) { - error(node, Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface); - } - forEach(node.members, checkSourceElement); } @@ -13201,16 +13199,6 @@ namespace ts { checkIndexConstraints(type); } } - - // Interfaces cannot merge with non-ambient classes. - if (symbol && symbol.declarations) { - for (let declaration of symbol.declarations) { - if (declaration.kind === SyntaxKind.ClassDeclaration && !isInAmbientContext(declaration)) { - error(node, Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface); - break; - } - } - } } forEach(getInterfaceBaseTypeNodes(node), heritageElement => { if (!isSupportedExpressionWithTypeArguments(heritageElement)) { diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 9a8c0ac416f..acf0474b7bf 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -77,6 +77,7 @@ namespace ts { "system": ModuleKind.System, "umd": ModuleKind.UMD, "es6": ModuleKind.ES6, + "es2015": ModuleKind.ES2015, }, description: Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_or_es6, paramType: Diagnostics.KIND, @@ -205,7 +206,12 @@ namespace ts { { name: "target", shortName: "t", - type: { "es3": ScriptTarget.ES3, "es5": ScriptTarget.ES5, "es6": ScriptTarget.ES6 }, + type: { + "es3": ScriptTarget.ES3, + "es5": ScriptTarget.ES5, + "es6": ScriptTarget.ES6, + "es2015": ScriptTarget.ES2015, + }, 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 @@ -384,7 +390,7 @@ namespace ts { catch (e) { return { error: createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message) }; } - return parseConfigFileText(fileName, text); + return parseConfigFileTextToJson(fileName, text); } /** @@ -392,7 +398,7 @@ namespace ts { * @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 } { + export function parseConfigFileTextToJson(fileName: string, jsonText: string): { config?: any; error?: Diagnostic } { try { return { config: /\S/.test(jsonText) ? JSON.parse(jsonText) : {} }; } @@ -407,7 +413,7 @@ namespace ts { * @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 { + export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string): ParsedCommandLine { let errors: Diagnostic[] = []; return { diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 6f0aa363068..9a2fb26df0f 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -704,6 +704,9 @@ namespace ts { } export function getBaseFileName(path: string) { + if (!path) { + return undefined; + } let i = path.lastIndexOf(directorySeparator); return i < 0 ? path : path.substring(i + 1); } @@ -728,6 +731,17 @@ namespace ts { export const supportedExtensions = [".ts", ".tsx", ".d.ts"]; export const supportedJsExtensions = supportedExtensions.concat(".js", ".jsx"); + export function isSupportedSourceFileName(fileName: string) { + if (!fileName) { return false; } + + for (let extension of supportedExtensions) { + if (fileExtensionIs(fileName, extension)) { + return true; + } + } + return false; + } + const extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"]; export function removeFileExtension(path: string): string { for (let ext of extensionsToRemove) { @@ -822,4 +836,14 @@ namespace ts { Debug.assert(false, message); } } -} + + export function copyListRemovingItem(item: T, list: T[]) { + let copiedList: T[] = []; + for (var i = 0, len = list.length; i < len; i++) { + if (list[i] !== item) { + copiedList.push(list[i]); + } + } + return copiedList; + } +} \ No newline at end of file diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a8ed6ac6127..b2c1e6f0d5e 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1620,10 +1620,6 @@ "category": "Error", "code":2517 }, - "Only an ambient class can be merged with an interface.": { - "category": "Error", - "code": 2518 - }, "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions.": { "category": "Error", "code": 2520 diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 08fd94c60d3..13d939c8ac7 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -12,7 +12,7 @@ namespace ts { let emptyArray: any[] = []; - export const version = "1.7.0"; + export const version = "1.8.0"; export function findConfigFile(searchPath: string): string { let fileName = "tsconfig.json"; diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 76f12666878..0872a2e5ba5 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -8,7 +8,8 @@ namespace ts { write(s: string): void; readFile(path: string, encoding?: string): string; writeFile(path: string, data: string, writeByteOrderMark?: boolean): void; - watchFile?(path: string, callback: (path: string, removed: boolean) => void): FileWatcher; + watchFile?(path: string, callback: (path: string, removed?: boolean) => void): FileWatcher; + watchDirectory?(path: string, callback: (path: string) => void, recursive?: boolean): FileWatcher; resolvePath(path: string): string; fileExists(path: string): boolean; directoryExists(path: string): boolean; @@ -20,6 +21,12 @@ namespace ts { exit(exitCode?: number): void; } + interface WatchedFile { + fileName: string; + callback: (fileName: string, removed?: boolean) => void; + mtime: Date; + } + export interface FileWatcher { close(): void; } @@ -192,6 +199,103 @@ namespace ts { const _path = require("path"); const _os = require("os"); + // average async stat takes about 30 microseconds + // set chunk size to do 30 files in < 1 millisecond + function createWatchedFileSet(interval = 2500, chunkSize = 30) { + let watchedFiles: WatchedFile[] = []; + let nextFileToCheck = 0; + let watchTimer: any; + + function getModifiedTime(fileName: string): Date { + return _fs.statSync(fileName).mtime; + } + + function poll(checkedIndex: number) { + let watchedFile = watchedFiles[checkedIndex]; + if (!watchedFile) { + return; + } + + _fs.stat(watchedFile.fileName, (err: any, stats: any) => { + if (err) { + watchedFile.callback(watchedFile.fileName); + } + else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) { + watchedFile.mtime = getModifiedTime(watchedFile.fileName); + watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0); + } + }); + } + + // this implementation uses polling and + // stat due to inconsistencies of fs.watch + // and efficiency of stat on modern filesystems + function startWatchTimer() { + watchTimer = setInterval(() => { + let count = 0; + let nextToCheck = nextFileToCheck; + let firstCheck = -1; + while ((count < chunkSize) && (nextToCheck !== firstCheck)) { + poll(nextToCheck); + if (firstCheck < 0) { + firstCheck = nextToCheck; + } + nextToCheck++; + if (nextToCheck === watchedFiles.length) { + nextToCheck = 0; + } + count++; + } + nextFileToCheck = nextToCheck; + }, interval); + } + + function addFile(fileName: string, callback: (fileName: string, removed?: boolean) => void): WatchedFile { + let file: WatchedFile = { + fileName, + callback, + mtime: getModifiedTime(fileName) + }; + + watchedFiles.push(file); + if (watchedFiles.length === 1) { + startWatchTimer(); + } + return file; + } + + function removeFile(file: WatchedFile) { + watchedFiles = copyListRemovingItem(file, watchedFiles); + } + + return { + getModifiedTime: getModifiedTime, + poll: poll, + startWatchTimer: startWatchTimer, + addFile: addFile, + removeFile: removeFile + }; + } + + // REVIEW: for now this implementation uses polling. + // The advantage of polling is that it works reliably + // on all os and with network mounted files. + // For 90 referenced files, the average time to detect + // changes is 2*msInterval (by default 5 seconds). + // The overhead of this is .04 percent (1/2500) with + // average pause of < 1 millisecond (and max + // pause less than 1.5 milliseconds); question is + // do we anticipate reference sets in the 100s and + // do we care about waiting 10-20 seconds to detect + // changes for large reference sets? If so, do we want + // to increase the chunk size or decrease the interval + // time dynamically to match the large reference set? + let watchedFileSet = createWatchedFileSet(); + + function isNode4OrLater(): Boolean { + return parseInt(process.version.charAt(1)) >= 4; + } + const platform: string = _os.platform(); // win32\win64 are case insensitive platforms, MacOS (darwin) by default is also case insensitive const useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin"; @@ -284,25 +388,36 @@ namespace ts { 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) { - // mtime.getTime() equals 0 if file was removed - if (curr.mtime.getTime() === 0) { - callback(fileName, /* removed */ true); - return; - } - if (+curr.mtime <= +prev.mtime) { - return; - } - - callback(fileName, /* removed */ false); + // Node 4.0 stablized the `fs.watch` function on Windows which avoids polling + // and is more efficient than `fs.watchFile` (ref: https://github.com/nodejs/node/pull/2649 + // and https://github.com/Microsoft/TypeScript/issues/4643), therefore + // if the current node.js version is newer than 4, use `fs.watch` instead. + if (isNode4OrLater()) { + // Note: in node the callback of fs.watch is given only the relative file name as a parameter + return _fs.watch(fileName, (eventName: string, relativeFileName: string) => callback(fileName)); } + + let watchedFile = watchedFileSet.addFile(fileName, callback); + return { + close: () => watchedFileSet.removeFile(watchedFile) + }; + }, + watchDirectory: (path, callback, recursive) => { + // Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows + // (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643) + return _fs.watch( + path, + { persisten: true, recursive: !!recursive }, + (eventName: string, relativeFileName: string) => { + // In watchDirectory we only care about adding and removing files (when event name is + // "rename"); changes made within files are handled by corresponding fileWatchers (when + // event name is "change") + if (eventName === "rename") { + // When deleting a file, the passed baseFileName is null + callback(!relativeFileName ? relativeFileName : normalizePath(ts.combinePaths(path, relativeFileName))); + }; + } + ); }, resolvePath: function (path: string): string { return _path.resolve(path); diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 7b74024aec4..9d79d435a04 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -147,14 +147,17 @@ namespace ts { export function executeCommandLine(args: string[]): void { let commandLine = parseCommandLine(args); - let configFileName: string; // Configuration file name (if any) - let configFileWatcher: FileWatcher; // Configuration file watcher - let cachedProgram: Program; // Program cached from last compilation - let rootFileNames: string[]; // Root fileNames for compilation - let compilerOptions: CompilerOptions; // Compiler options for compilation - let compilerHost: CompilerHost; // Compiler host - let hostGetSourceFile: typeof compilerHost.getSourceFile; // getSourceFile method from default host - let timerHandle: number; // Handle for 0.25s wait timer + let configFileName: string; // Configuration file name (if any) + let cachedConfigFileText: string; // Cached configuration file text, used for reparsing (if any) + let configFileWatcher: FileWatcher; // Configuration file watcher + let directoryWatcher: FileWatcher; // Directory watcher to monitor source file addition/removal + let cachedProgram: Program; // Program cached from last compilation + let rootFileNames: string[]; // Root fileNames for compilation + let compilerOptions: CompilerOptions; // Compiler options for compilation + let compilerHost: CompilerHost; // Compiler host + let hostGetSourceFile: typeof compilerHost.getSourceFile; // getSourceFile method from default host + let timerHandleForRecompilation: number; // Handle for 0.25s wait timer to trigger recompilation + let timerHandleForDirectoryChanges: number; // Handle for 0.25s wait timer to trigger directory change handler if (commandLine.options.locale) { if (!isJSONSupported()) { @@ -218,28 +221,49 @@ namespace ts { if (configFileName) { configFileWatcher = sys.watchFile(configFileName, configFileChanged); } + if (sys.watchDirectory && configFileName) { + let directory = ts.getDirectoryPath(configFileName); + directoryWatcher = sys.watchDirectory( + // When the configFileName is just "tsconfig.json", the watched directory should be + // the current direcotry; if there is a given "project" parameter, then the configFileName + // is an absolute file name. + directory == "" ? "." : directory, + watchedDirectoryChanged, /*recursive*/ true); + } } performCompilation(); + function parseConfigFile(): ParsedCommandLine { + if (!cachedConfigFileText) { + try { + cachedConfigFileText = sys.readFile(configFileName); + } + catch (e) { + let error = createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, configFileName, e.message); + reportWatchDiagnostic(error); + sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); + return; + } + } + + let result = parseConfigFileTextToJson(configFileName, cachedConfigFileText); + let configObject = result.config; + let configParseResult = parseJsonConfigFileContent(configObject, sys, getDirectoryPath(configFileName)); + if (configParseResult.errors.length > 0) { + reportDiagnostics(configParseResult.errors); + sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); + return; + } + return configParseResult; + } + // Invoked to perform initial compilation or re-compilation in watch mode function performCompilation() { if (!cachedProgram) { if (configFileName) { - - let result = readConfigFile(configFileName, sys.readFile); - if (result.error) { - reportWatchDiagnostic(result.error); - return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); - } - - let configObject = result.config; - let configParseResult = parseConfigFile(configObject, sys, getDirectoryPath(configFileName)); - if (configParseResult.errors.length > 0) { - reportDiagnostics(configParseResult.errors); - return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); - } + let configParseResult = parseConfigFile(); rootFileNames = configParseResult.fileNames; compilerOptions = extend(commandLine.options, configParseResult.options); } @@ -275,7 +299,7 @@ namespace ts { let sourceFile = hostGetSourceFile(fileName, languageVersion, onError); if (sourceFile && compilerOptions.watch) { // Attach a file watcher - sourceFile.fileWatcher = sys.watchFile(sourceFile.fileName, (fileName, removed) => sourceFileChanged(sourceFile, removed)); + sourceFile.fileWatcher = sys.watchFile(sourceFile.fileName, (fileName: string, removed?: boolean) => sourceFileChanged(sourceFile, removed)); } return sourceFile; } @@ -297,7 +321,7 @@ namespace ts { } // If a source file changes, mark it as unwatched and start the recompilation timer - function sourceFileChanged(sourceFile: SourceFile, removed: boolean) { + function sourceFileChanged(sourceFile: SourceFile, removed?: boolean) { sourceFile.fileWatcher.close(); sourceFile.fileWatcher = undefined; if (removed) { @@ -306,27 +330,54 @@ namespace ts { rootFileNames.splice(index, 1); } } - startTimer(); + startTimerForRecompilation(); } // If the configuration file changes, forget cached program and start the recompilation timer function configFileChanged() { setCachedProgram(undefined); - startTimer(); + cachedConfigFileText = undefined; + startTimerForRecompilation(); + } + + function watchedDirectoryChanged(fileName: string) { + if (fileName && !ts.isSupportedSourceFileName(fileName)) { + return; + } + + startTimerForHandlingDirectoryChanges(); + } + + function startTimerForHandlingDirectoryChanges() { + if (timerHandleForDirectoryChanges) { + clearTimeout(timerHandleForDirectoryChanges); + } + timerHandleForDirectoryChanges = setTimeout(directoryChangeHandler, 250); + } + + function directoryChangeHandler() { + let parsedCommandLine = parseConfigFile(); + let newFileNames = ts.map(parsedCommandLine.fileNames, compilerHost.getCanonicalFileName); + let canonicalRootFileNames = ts.map(rootFileNames, compilerHost.getCanonicalFileName); + + if (!arrayStructurallyIsEqualTo(newFileNames, canonicalRootFileNames)) { + setCachedProgram(undefined); + startTimerForRecompilation(); + } } // Upon detecting a file change, wait for 250ms and then perform a recompilation. This gives batch // operations (such as saving all modified files in an editor) a chance to complete before we kick // off a new compilation. - function startTimer() { - if (timerHandle) { - clearTimeout(timerHandle); + function startTimerForRecompilation() { + if (timerHandleForRecompilation) { + clearTimeout(timerHandleForRecompilation); } - timerHandle = setTimeout(recompile, 250); + timerHandleForRecompilation = setTimeout(recompile, 250); } function recompile() { - timerHandle = undefined; + timerHandleForRecompilation = undefined; reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation)); performCompilation(); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a1665d081ae..5e8de9a3fb4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2106,6 +2106,7 @@ namespace ts { UMD = 3, System = 4, ES6 = 5, + ES2015 = ES6, } export const enum JsxEmit { @@ -2131,12 +2132,13 @@ namespace ts { ES3 = 0, ES5 = 1, ES6 = 2, + ES2015 = ES6, Latest = ES6, } export const enum LanguageVariant { Standard, - JSX + JSX, } export interface ParsedCommandLine { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 1c875ec1b51..9eff4370ec2 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2469,4 +2469,16 @@ namespace ts { } } } + + export function arrayStructurallyIsEqualTo(array1: Array, array2: Array): boolean { + if (!array1 || !array2) { + return false; + } + + if (array1.length !== array2.length) { + return false; + } + + return arrayIsEqualTo(array1.sort(), array2.sort()); + } } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 688b7f0b906..eb60a47388e 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -572,6 +572,10 @@ namespace Harness.LanguageService { return { close() { } }; } + watchDirectory(path: string, callback: (path: string) => void, recursive?: boolean): ts.FileWatcher { + return { close() { } }; + } + close(): void { } @@ -614,7 +618,9 @@ namespace Harness.LanguageService { // This host is just a proxy for the clientHost, it uses the client // host to answer server queries about files on disk let serverHost = new SessionServerHost(clientHost); - let server = new ts.server.Session(serverHost, Buffer.byteLength, process.hrtime, serverHost); + let server = new ts.server.Session(serverHost, + Buffer ? Buffer.byteLength : (string: string, encoding?: string) => string.length, + process.hrtime, serverHost); // Fake the connection between the client and the server serverHost.writeMessage = client.onMessage.bind(client); diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index 3027afae9dc..19c989bcd6f 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -78,8 +78,8 @@ namespace RWC { let tsconfigFile = ts.forEach(ioLog.filesRead, f => isTsConfigFile(f) ? f : undefined); if (tsconfigFile) { let tsconfigFileContents = getHarnessCompilerInputUnit(tsconfigFile.path); - let parsedTsconfigFileContents = ts.parseConfigFileText(tsconfigFile.path, tsconfigFileContents.content); - let configParseResult = ts.parseConfigFile(parsedTsconfigFileContents.config, Harness.IO, ts.getDirectoryPath(tsconfigFile.path)); + let parsedTsconfigFileContents = ts.parseConfigFileTextToJson(tsconfigFile.path, tsconfigFileContents.content); + let configParseResult = ts.parseJsonConfigFileContent(parsedTsconfigFileContents.config, Harness.IO, ts.getDirectoryPath(tsconfigFile.path)); fileNames = configParseResult.fileNames; opts.options = ts.extend(opts.options, configParseResult.options); } diff --git a/src/lib/core.d.ts b/src/lib/core.d.ts index 7259ff5081c..12df449931e 100644 --- a/src/lib/core.d.ts +++ b/src/lib/core.d.ts @@ -1210,7 +1210,7 @@ interface ArrayBuffer { interface ArrayBufferConstructor { prototype: ArrayBuffer; new (byteLength: number): ArrayBuffer; - isView(arg: any): boolean; + isView(arg: any): arg is ArrayBufferView; } declare var ArrayBuffer: ArrayBufferConstructor; diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 8ea216eefe6..056443415c8 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -78,19 +78,19 @@ namespace ts.server { return this.snap().getChangeRange(oldSnapshot); } } - + interface TimestampedResolvedModule extends ResolvedModuleWithFailedLookupLocations { - lastCheckTime: number; + lastCheckTime: number; } - + export class LSHost implements ts.LanguageServiceHost { ls: ts.LanguageService = null; compilationSettings: ts.CompilerOptions; filenameToScript: ts.Map = {}; roots: ScriptInfo[] = []; - private resolvedModuleNames: ts.FileMap>; + private resolvedModuleNames: ts.FileMap>; private moduleResolutionHost: ts.ModuleResolutionHost; - + constructor(public host: ServerHost, public project: Project) { this.resolvedModuleNames = ts.createFileMap>(ts.createGetCanonicalFileName(host.useCaseSensitiveFileNames)) this.moduleResolutionHost = { @@ -98,15 +98,15 @@ namespace ts.server { readFile: fileName => this.host.readFile(fileName) } } - + resolveModuleNames(moduleNames: string[], containingFile: string): ResolvedModule[] { let currentResolutionsInFile = this.resolvedModuleNames.get(containingFile); - + let newResolutions: Map = {}; let resolvedModules: ResolvedModule[] = []; - + let compilerOptions = this.getCompilationSettings(); - + for (let moduleName of moduleNames) { // check if this is a duplicate entry in the list let resolution = lookUp(newResolutions, moduleName); @@ -122,21 +122,21 @@ namespace ts.server { newResolutions[moduleName] = resolution; } } - + ts.Debug.assert(resolution !== undefined); - + resolvedModules.push(resolution.resolvedModule); } // replace old results with a new one this.resolvedModuleNames.set(containingFile, newResolutions); return resolvedModules; - + function moduleResolutionIsValid(resolution: TimestampedResolvedModule): boolean { if (!resolution) { return false; } - + if (resolution.resolvedModule) { // TODO: consider checking failedLookupLocations // TODO: use lastCheckTime to track expiration for module name resolution @@ -147,7 +147,7 @@ namespace ts.server { // after all there is no point to invalidate it if we have no idea where to look for the module. return resolution.failedLookupLocations.length === 0; } - } + } getDefaultLibFileName() { var nodeModuleBinDir = ts.getDirectoryPath(ts.normalizePath(this.host.getExecutingFilePath())); @@ -224,12 +224,13 @@ namespace ts.server { this.roots.push(info); } } - + removeRoot(info: ScriptInfo) { var scriptInfo = ts.lookUp(this.filenameToScript, info.fileName); if (scriptInfo) { this.filenameToScript[info.fileName] = undefined; this.roots = copyListRemovingItem(info, this.roots); + this.resolvedModuleNames.remove(info.fileName); } } @@ -354,6 +355,9 @@ namespace ts.server { compilerService: CompilerService; projectFilename: string; projectFileWatcher: FileWatcher; + directoryWatcher: FileWatcher; + // Used to keep track of what directories are watched for this project + directoriesWatchedForTsconfig: string[] = []; program: ts.Program; filenameToSourceFile: ts.Map = {}; updateGraphSeq = 0; @@ -381,6 +385,10 @@ namespace ts.server { return this.projectService.openFile(filename, false); } + getRootFiles() { + return this.compilerService.host.roots.map(info => info.fileName); + } + getFileNames() { let sourceFiles = this.program.getSourceFiles(); return sourceFiles.map(sourceFile => sourceFile.fileName); @@ -433,13 +441,11 @@ namespace ts.server { // add a root file to project addRoot(info: ScriptInfo) { - info.defaultProject = this; this.compilerService.host.addRoot(info); } // remove a root file from project removeRoot(info: ScriptInfo) { - info.defaultProject = undefined; this.compilerService.host.removeRoot(info); } @@ -496,7 +502,13 @@ namespace ts.server { openFilesReferenced: ScriptInfo[] = []; // open files that are roots of a configured project openFileRootsConfigured: ScriptInfo[] = []; + // a path to directory watcher map that detects added tsconfig files + directoryWatchersForTsconfig: ts.Map = {}; + // count of how many projects are using the directory watcher. If the + // number becomes 0 for a watcher, then we should close it. + directoryWatchersRefCount: ts.Map = {}; hostConfiguration: HostConfiguration; + timerForDetectingProjectFilelistChanges: Map = {}; constructor(public host: ServerHost, public psLogger: Logger, public eventHandler?: ProjectServiceEventHandler) { // ts.disableIncrementalParsing = true; @@ -537,8 +549,82 @@ namespace ts.server { } } + /** + * This is the callback function when a watched directory has added or removed source code files. + * @param project the project that associates with this directory watcher + * @param fileName the absolute file name that changed in watched directory + */ + directoryWatchedForSourceFilesChanged(project: Project, fileName: string) { + // If a change was made inside "folder/file", node will trigger the callback twice: + // one with the fileName being "folder/file", and the other one with "folder". + // We don't respond to the second one. + if (fileName && !ts.isSupportedSourceFileName(fileName)) { + return; + } + + this.log("Detected source file changes: " + fileName); + this.startTimerForDetectingProjectFilelistChanges(project); + } + + startTimerForDetectingProjectFilelistChanges(project: Project) { + if (this.timerForDetectingProjectFilelistChanges[project.projectFilename]) { + clearTimeout(this.timerForDetectingProjectFilelistChanges[project.projectFilename]); + } + this.timerForDetectingProjectFilelistChanges[project.projectFilename] = setTimeout( + () => this.handleProjectFilelistChanges(project), + 250 + ); + } + + handleProjectFilelistChanges(project: Project) { + let { succeeded, projectOptions, error } = this.configFileToProjectOptions(project.projectFilename); + let newRootFiles = projectOptions.files.map((f => this.getCanonicalFileName(f))); + let currentRootFiles = project.getRootFiles().map((f => this.getCanonicalFileName(f))); + + if (!arrayStructurallyIsEqualTo(currentRootFiles, newRootFiles)) { + // For configured projects, the change is made outside the tsconfig file, and + // it is not likely to affect the project for other files opened by the client. We can + // just update the current project. + this.updateConfiguredProject(project); + + // Call updateProjectStructure to clean up inferred projects we may have + // created for the new files + this.updateProjectStructure(); + } + } + + /** + * This is the callback function when a watched directory has an added tsconfig file. + */ + directoryWatchedForTsconfigChanged(fileName: string) { + if (ts.getBaseFileName(fileName) != "tsconfig.json") { + this.log(fileName + " is not tsconfig.json"); + return; + } + + this.log("Detected newly added tsconfig file: " + fileName); + + let { succeeded, projectOptions, error } = this.configFileToProjectOptions(fileName); + let rootFilesInTsconfig = projectOptions.files.map(f => this.getCanonicalFileName(f)); + let openFileRoots = this.openFileRoots.map(s => this.getCanonicalFileName(s.fileName)); + + // We should only care about the new tsconfig file if it contains any + // opened root files of existing inferred projects + for (let openFileRoot of openFileRoots) { + if (rootFilesInTsconfig.indexOf(openFileRoot) >= 0) { + this.reloadProjects(); + return; + } + } + } + + getCanonicalFileName(fileName: string) { + let name = this.host.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(); + return ts.normalizePath(name); + } + watchedProjectConfigFileChanged(project: Project) { - this.log("Config File Changed: " + project.projectFilename); + this.log("Config file changed: " + project.projectFilename); this.updateConfiguredProject(project); this.updateProjectStructure(); } @@ -572,11 +658,29 @@ namespace ts.server { } createInferredProject(root: ScriptInfo) { - var iproj = new Project(this); - iproj.addRoot(root); - iproj.finishGraph(); - this.inferredProjects.push(iproj); - return iproj; + var project = new Project(this); + project.addRoot(root); + + let currentPath = ts.getDirectoryPath(root.fileName); + let parentPath = ts.getDirectoryPath(currentPath); + while (currentPath != parentPath) { + if (!project.projectService.directoryWatchersForTsconfig[currentPath]) { + this.log("Add watcher for: " + currentPath); + project.projectService.directoryWatchersForTsconfig[currentPath] = + this.host.watchDirectory(currentPath, fileName => this.directoryWatchedForTsconfigChanged(fileName)); + project.projectService.directoryWatchersRefCount[currentPath] = 1; + } + else { + project.projectService.directoryWatchersRefCount[currentPath] += 1; + } + project.directoriesWatchedForTsconfig.push(currentPath); + currentPath = parentPath; + parentPath = ts.getDirectoryPath(parentPath); + } + + project.finishGraph(); + this.inferredProjects.push(project); + return project; } fileDeletedInFilesystem(info: ScriptInfo) { @@ -590,6 +694,9 @@ namespace ts.server { if (!info.isOpen) { this.filenameToScriptInfo[info.fileName] = undefined; var referencingProjects = this.findReferencingProjects(info); + if (info.defaultProject) { + info.defaultProject.removeRoot(info); + } for (var i = 0, len = referencingProjects.length; i < len; i++) { referencingProjects[i].removeReferencedFile(info); } @@ -620,9 +727,24 @@ namespace ts.server { this.configuredProjects = configuredProjects; } - removeConfiguredProject(project: Project) { - project.projectFileWatcher.close(); - this.configuredProjects = copyListRemovingItem(project, this.configuredProjects); + removeProject(project: Project) { + this.log("remove project: " + project.getRootFiles().toString()); + if (project.isConfiguredProject()) { + project.projectFileWatcher.close(); + project.directoryWatcher.close(); + this.configuredProjects = copyListRemovingItem(project, this.configuredProjects); + } + else { + for (let directory of project.directoriesWatchedForTsconfig) { + // if the ref count for this directory watcher drops to 0, it's time to close it + if (!(--project.projectService.directoryWatchersRefCount[directory])) { + this.log("Close directory watcher for: " + directory); + project.projectService.directoryWatchersForTsconfig[directory].close(); + delete project.projectService.directoryWatchersForTsconfig[directory]; + } + } + this.inferredProjects = copyListRemovingItem(project, this.inferredProjects); + } let fileNames = project.getFileNames(); for (let fileName of fileNames) { @@ -664,8 +786,7 @@ namespace ts.server { // if r referenced by the new project if (info.defaultProject.getSourceFile(r)) { // remove project rooted at r - this.inferredProjects = - copyListRemovingItem(r.defaultProject, this.inferredProjects); + this.removeProject(r.defaultProject); // put r in referenced open file list this.openFilesReferenced.push(r); // set default project of r to the new project @@ -688,6 +809,11 @@ namespace ts.server { * @param info The file that has been closed or newly configured */ closeOpenFile(info: ScriptInfo) { + // Closing file should trigger re-reading the file content from disk. This is + // because the user may chose to discard the buffer content before saving + // to the disk, and the server's version of the file can be out of sync. + info.svc.reloadFromFile(info.fileName); + var openFileRoots: ScriptInfo[] = []; var removedProject: Project; for (var i = 0, len = this.openFileRoots.length; i < len; i++) { @@ -718,19 +844,14 @@ namespace ts.server { this.openFileRootsConfigured = openFileRootsConfigured; } if (removedProject) { - if (removedProject.isConfiguredProject()) { - this.configuredProjects = copyListRemovingItem(removedProject, this.configuredProjects); - } - else { - this.inferredProjects = copyListRemovingItem(removedProject, this.inferredProjects); - } + this.removeProject(removedProject); var openFilesReferenced: ScriptInfo[] = []; var orphanFiles: ScriptInfo[] = []; // for all open, referenced files f for (var i = 0, len = this.openFilesReferenced.length; i < len; i++) { var f = this.openFilesReferenced[i]; // if f was referenced by the removed project, remember it - if (f.defaultProject === removedProject) { + if (f.defaultProject === removedProject || !f.defaultProject) { f.defaultProject = undefined; orphanFiles.push(f); } @@ -774,7 +895,11 @@ namespace ts.server { return referencingProjects; } + /** + * This function rebuilds the project for every file opened by the client + */ reloadProjects() { + this.log("reload projects."); // First check if there is new tsconfig file added for inferred project roots for (let info of this.openFileRoots) { this.openOrUpdateConfiguredProjectForFile(info.fileName); @@ -835,14 +960,25 @@ namespace ts.server { var rootFile = this.openFileRoots[i]; var rootedProject = rootFile.defaultProject; var referencingProjects = this.findReferencingProjects(rootFile, rootedProject); - if (referencingProjects.length === 0) { - rootFile.defaultProject = rootedProject; - openFileRoots.push(rootFile); + + if (rootFile.defaultProject && rootFile.defaultProject.isConfiguredProject()) { + // If the root file has already been added into a configured project, + // meaning the original inferred project is gone already. + if (!rootedProject.isConfiguredProject()) { + this.removeProject(rootedProject); + } + this.openFileRootsConfigured.push(rootFile); } else { - // remove project from inferred projects list because root captured - this.inferredProjects = copyListRemovingItem(rootedProject, this.inferredProjects); - this.openFilesReferenced.push(rootFile); + if (referencingProjects.length === 0) { + rootFile.defaultProject = rootedProject; + openFileRoots.push(rootFile); + } + else { + // remove project from inferred projects list because root captured + this.removeProject(rootedProject); + this.openFilesReferenced.push(rootFile); + } } } this.openFileRoots = openFileRoots; @@ -927,6 +1063,11 @@ namespace ts.server { return info; } + /** + * This function tries to search for a tsconfig.json for the given file. If we found it, + * we first detect if there is already a configured project created for it: if so, we re-read + * the tsconfig file content and update the project; otherwise we create a new one. + */ openOrUpdateConfiguredProjectForFile(fileName: string) { let searchPath = ts.normalizePath(getDirectoryPath(fileName)); this.log("Search path: " + searchPath, "Info"); @@ -1046,17 +1187,17 @@ namespace ts.server { // file references will be relative to dirPath (or absolute) var dirPath = ts.getDirectoryPath(configFilename); var contents = this.host.readFile(configFilename) - var rawConfig: { config?: ProjectOptions; error?: Diagnostic; } = ts.parseConfigFileText(configFilename, contents); + var rawConfig: { config?: ProjectOptions; error?: Diagnostic; } = ts.parseConfigFileTextToJson(configFilename, contents); if (rawConfig.error) { return { succeeded: false, error: rawConfig.error }; } else { - var parsedCommandLine = ts.parseConfigFile(rawConfig.config, this.host, dirPath); + var parsedCommandLine = ts.parseJsonConfigFileContent(rawConfig.config, this.host, dirPath); if (parsedCommandLine.errors && (parsedCommandLine.errors.length > 0)) { return { succeeded: false, error: { errorMsg: "tsconfig option errors" } }; } else if (parsedCommandLine.fileNames == null) { - return { succeeded: false, error: { errorMsg: "no files found" } } + return { succeeded: false, error: { errorMsg: "no files found" } }; } else { var projectOptions: ProjectOptions = { @@ -1075,27 +1216,32 @@ namespace ts.server { return error; } else { - let proj = this.createProject(configFilename, projectOptions); - for (let i = 0, len = projectOptions.files.length; i < len; i++) { - let rootFilename = projectOptions.files[i]; + let project = this.createProject(configFilename, projectOptions); + for (let rootFilename of projectOptions.files) { if (this.host.fileExists(rootFilename)) { let info = this.openFile(rootFilename, /*openedByClient*/ clientFileName == rootFilename); - proj.addRoot(info); + project.addRoot(info); } else { return { errorMsg: "specified file " + rootFilename + " not found" }; } } - proj.finishGraph(); - proj.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(proj)); - return { success: true, project: proj }; + project.finishGraph(); + project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project)); + this.log("Add recursive watcher for: " + ts.getDirectoryPath(configFilename)); + project.directoryWatcher = this.host.watchDirectory( + ts.getDirectoryPath(configFilename), + path => this.directoryWatchedForSourceFilesChanged(project, path), + /*recursive*/ true + ); + return { success: true, project: project }; } } updateConfiguredProject(project: Project) { if (!this.host.fileExists(project.projectFilename)) { this.log("Config file deleted"); - this.removeConfiguredProject(project); + this.removeProject(project); } else { let { succeeded, projectOptions, error } = this.configFileToProjectOptions(project.projectFilename); @@ -1110,7 +1256,9 @@ namespace ts.server { for (let fileName of fileNamesToRemove) { let info = this.getScriptInfo(fileName); - project.removeRoot(info); + if (info) { + project.removeRoot(info); + } } for (let fileName of fileNamesToAdd) { @@ -1224,9 +1372,9 @@ namespace ts.server { goSubtree: boolean; done: boolean; leaf(relativeStart: number, relativeLength: number, lineCollection: LineLeaf): void; - pre? (relativeStart: number, relativeLength: number, lineCollection: LineCollection, + pre?(relativeStart: number, relativeLength: number, lineCollection: LineCollection, parent: LineNode, nodeType: CharRangeSection): LineCollection; - post? (relativeStart: number, relativeLength: number, lineCollection: LineCollection, + post?(relativeStart: number, relativeLength: number, lineCollection: LineCollection, parent: LineNode, nodeType: CharRangeSection): LineCollection; } diff --git a/src/server/server.ts b/src/server/server.ts index c3942b01a39..39864fc8477 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -11,7 +11,7 @@ namespace ts.server { input: process.stdin, output: process.stdout, terminal: false, - }); + }); class Logger implements ts.server.Logger { fd = -1; @@ -58,7 +58,7 @@ namespace ts.server { isVerbose() { return this.loggingEnabled() && (this.level == "verbose"); } - + msg(s: string, type = "Err") { if (this.fd < 0) { @@ -83,95 +83,6 @@ namespace ts.server { } } - interface WatchedFile { - fileName: string; - callback: (fileName: string, removed: boolean) => void; - mtime: Date; - } - - class WatchedFileSet { - private watchedFiles: WatchedFile[] = []; - private nextFileToCheck = 0; - private watchTimer: NodeJS.Timer; - - // average async stat takes about 30 microseconds - // set chunk size to do 30 files in < 1 millisecond - constructor(public interval = 2500, public chunkSize = 30) { - } - - private static copyListRemovingItem(item: T, list: T[]) { - var copiedList: T[] = []; - for (var i = 0, len = list.length; i < len; i++) { - if (list[i] != item) { - copiedList.push(list[i]); - } - } - return copiedList; - } - - private static getModifiedTime(fileName: string): Date { - return fs.statSync(fileName).mtime; - } - - private poll(checkedIndex: number) { - var watchedFile = this.watchedFiles[checkedIndex]; - if (!watchedFile) { - return; - } - - fs.stat(watchedFile.fileName,(err, stats) => { - if (err) { - watchedFile.callback(watchedFile.fileName, /* removed */ false); - } - else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) { - watchedFile.mtime = WatchedFileSet.getModifiedTime(watchedFile.fileName); - watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0); - } - }); - } - - // this implementation uses polling and - // stat due to inconsistencies of fs.watch - // and efficiency of stat on modern filesystems - private startWatchTimer() { - this.watchTimer = setInterval(() => { - var count = 0; - var nextToCheck = this.nextFileToCheck; - var firstCheck = -1; - while ((count < this.chunkSize) && (nextToCheck !== firstCheck)) { - this.poll(nextToCheck); - if (firstCheck < 0) { - firstCheck = nextToCheck; - } - nextToCheck++; - if (nextToCheck === this.watchedFiles.length) { - nextToCheck = 0; - } - count++; - } - this.nextFileToCheck = nextToCheck; - }, this.interval); - } - - addFile(fileName: string, callback: (fileName: string, removed: boolean) => void ): WatchedFile { - var file: WatchedFile = { - fileName, - callback, - mtime: WatchedFileSet.getModifiedTime(fileName) - }; - - this.watchedFiles.push(file); - if (this.watchedFiles.length === 1) { - this.startWatchTimer(); - } - return file; - } - - removeFile(file: WatchedFile) { - this.watchedFiles = WatchedFileSet.copyListRemovingItem(file, this.watchedFiles); - } - } - class IOSession extends Session { constructor(host: ServerHost, logger: ts.server.Logger) { super(host, Buffer.byteLength, process.hrtime, logger); @@ -244,31 +155,10 @@ namespace ts.server { var logger = createLoggerFromEnv(); - // REVIEW: for now this implementation uses polling. - // The advantage of polling is that it works reliably - // on all os and with network mounted files. - // For 90 referenced files, the average time to detect - // changes is 2*msInterval (by default 5 seconds). - // The overhead of this is .04 percent (1/2500) with - // average pause of < 1 millisecond (and max - // pause less than 1.5 milliseconds); question is - // do we anticipate reference sets in the 100s and - // do we care about waiting 10-20 seconds to detect - // changes for large reference sets? If so, do we want - // to increase the chunk size or decrease the interval - // time dynamically to match the large reference set? - var watchedFileSet = new WatchedFileSet(); - ts.sys.watchFile = function (fileName, callback) { - var watchedFile = watchedFileSet.addFile(fileName, callback); - return { - close: () => watchedFileSet.removeFile(watchedFile) - } - - }; var ioSession = new IOSession(ts.sys, logger); process.on('uncaughtException', function(err: Error) { ioSession.logError(err, "unknown"); }); // Start listening ioSession.listen(); -} +} \ No newline at end of file diff --git a/src/server/session.ts b/src/server/session.ts index 56d4011de5b..550b551e51a 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -793,6 +793,7 @@ namespace ts.server { } private closeClientFile(fileName: string) { + if (!fileName) { return; } var file = ts.normalizePath(fileName); this.projectService.closeClientFile(file); } diff --git a/src/services/shims.ts b/src/services/shims.ts index 686faf0e1bd..def15459c3b 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -991,7 +991,7 @@ namespace ts { () => { let text = sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()); - let result = parseConfigFileText(fileName, text); + let result = parseConfigFileTextToJson(fileName, text); if (result.error) { return { @@ -1001,7 +1001,7 @@ namespace ts { }; } - var configFile = parseConfigFile(result.config, this.host, getDirectoryPath(normalizeSlashes(fileName))); + var configFile = parseJsonConfigFileContent(result.config, this.host, getDirectoryPath(normalizeSlashes(fileName))); return { options: configFile.options, diff --git a/tests/baselines/reference/ambientClassMergesOverloadsWithInterface.js b/tests/baselines/reference/ambientClassMergesOverloadsWithInterface.js new file mode 100644 index 00000000000..417aedc4abc --- /dev/null +++ b/tests/baselines/reference/ambientClassMergesOverloadsWithInterface.js @@ -0,0 +1,12 @@ +//// [ambientClassMergesOverloadsWithInterface.ts] +declare class C { + baz(): any; + foo(n: number): any; +} +interface C { + foo(n: number): any; + bar(): any; +} + + +//// [ambientClassMergesOverloadsWithInterface.js] diff --git a/tests/baselines/reference/ambientClassMergesOverloadsWithInterface.symbols b/tests/baselines/reference/ambientClassMergesOverloadsWithInterface.symbols new file mode 100644 index 00000000000..9a5eb13d21d --- /dev/null +++ b/tests/baselines/reference/ambientClassMergesOverloadsWithInterface.symbols @@ -0,0 +1,22 @@ +=== tests/cases/compiler/ambientClassMergesOverloadsWithInterface.ts === +declare class C { +>C : Symbol(C, Decl(ambientClassMergesOverloadsWithInterface.ts, 0, 0), Decl(ambientClassMergesOverloadsWithInterface.ts, 3, 1)) + + baz(): any; +>baz : Symbol(baz, Decl(ambientClassMergesOverloadsWithInterface.ts, 0, 17)) + + foo(n: number): any; +>foo : Symbol(foo, Decl(ambientClassMergesOverloadsWithInterface.ts, 1, 15), Decl(ambientClassMergesOverloadsWithInterface.ts, 4, 13)) +>n : Symbol(n, Decl(ambientClassMergesOverloadsWithInterface.ts, 2, 8)) +} +interface C { +>C : Symbol(C, Decl(ambientClassMergesOverloadsWithInterface.ts, 0, 0), Decl(ambientClassMergesOverloadsWithInterface.ts, 3, 1)) + + foo(n: number): any; +>foo : Symbol(foo, Decl(ambientClassMergesOverloadsWithInterface.ts, 1, 15), Decl(ambientClassMergesOverloadsWithInterface.ts, 4, 13)) +>n : Symbol(n, Decl(ambientClassMergesOverloadsWithInterface.ts, 5, 8)) + + bar(): any; +>bar : Symbol(bar, Decl(ambientClassMergesOverloadsWithInterface.ts, 5, 24)) +} + diff --git a/tests/baselines/reference/ambientClassMergesOverloadsWithInterface.types b/tests/baselines/reference/ambientClassMergesOverloadsWithInterface.types new file mode 100644 index 00000000000..7a271b82865 --- /dev/null +++ b/tests/baselines/reference/ambientClassMergesOverloadsWithInterface.types @@ -0,0 +1,22 @@ +=== tests/cases/compiler/ambientClassMergesOverloadsWithInterface.ts === +declare class C { +>C : C + + baz(): any; +>baz : () => any + + foo(n: number): any; +>foo : { (n: number): any; (n: number): any; } +>n : number +} +interface C { +>C : C + + foo(n: number): any; +>foo : { (n: number): any; (n: number): any; } +>n : number + + bar(): any; +>bar : () => any +} + diff --git a/tests/baselines/reference/arrayBufferIsViewNarrowsType.js b/tests/baselines/reference/arrayBufferIsViewNarrowsType.js new file mode 100644 index 00000000000..fcda4d5976b --- /dev/null +++ b/tests/baselines/reference/arrayBufferIsViewNarrowsType.js @@ -0,0 +1,13 @@ +//// [arrayBufferIsViewNarrowsType.ts] +var obj: Object; +if (ArrayBuffer.isView(obj)) { + // isView should be a guard that narrows type to ArrayBufferView. + var ab: ArrayBufferView = obj; +} + +//// [arrayBufferIsViewNarrowsType.js] +var obj; +if (ArrayBuffer.isView(obj)) { + // isView should be a guard that narrows type to ArrayBufferView. + var ab = obj; +} diff --git a/tests/baselines/reference/arrayBufferIsViewNarrowsType.symbols b/tests/baselines/reference/arrayBufferIsViewNarrowsType.symbols new file mode 100644 index 00000000000..eb7ffe7479e --- /dev/null +++ b/tests/baselines/reference/arrayBufferIsViewNarrowsType.symbols @@ -0,0 +1,17 @@ +=== tests/cases/compiler/arrayBufferIsViewNarrowsType.ts === +var obj: Object; +>obj : Symbol(obj, Decl(arrayBufferIsViewNarrowsType.ts, 0, 3)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +if (ArrayBuffer.isView(obj)) { +>ArrayBuffer.isView : Symbol(ArrayBufferConstructor.isView, Decl(lib.d.ts, --, --)) +>ArrayBuffer : Symbol(ArrayBuffer, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>isView : Symbol(ArrayBufferConstructor.isView, Decl(lib.d.ts, --, --)) +>obj : Symbol(obj, Decl(arrayBufferIsViewNarrowsType.ts, 0, 3)) + + // isView should be a guard that narrows type to ArrayBufferView. + var ab: ArrayBufferView = obj; +>ab : Symbol(ab, Decl(arrayBufferIsViewNarrowsType.ts, 3, 7)) +>ArrayBufferView : Symbol(ArrayBufferView, Decl(lib.d.ts, --, --)) +>obj : Symbol(obj, Decl(arrayBufferIsViewNarrowsType.ts, 0, 3)) +} diff --git a/tests/baselines/reference/arrayBufferIsViewNarrowsType.types b/tests/baselines/reference/arrayBufferIsViewNarrowsType.types new file mode 100644 index 00000000000..129b7d601d8 --- /dev/null +++ b/tests/baselines/reference/arrayBufferIsViewNarrowsType.types @@ -0,0 +1,18 @@ +=== tests/cases/compiler/arrayBufferIsViewNarrowsType.ts === +var obj: Object; +>obj : Object +>Object : Object + +if (ArrayBuffer.isView(obj)) { +>ArrayBuffer.isView(obj) : boolean +>ArrayBuffer.isView : (arg: any) => arg is ArrayBufferView +>ArrayBuffer : ArrayBufferConstructor +>isView : (arg: any) => arg is ArrayBufferView +>obj : Object + + // isView should be a guard that narrows type to ArrayBufferView. + var ab: ArrayBufferView = obj; +>ab : ArrayBufferView +>ArrayBufferView : ArrayBufferView +>obj : ArrayBufferView +} diff --git a/tests/baselines/reference/augmentedTypesClass2.errors.txt b/tests/baselines/reference/augmentedTypesClass2.errors.txt index 278dca816fa..a27189cf2c2 100644 --- a/tests/baselines/reference/augmentedTypesClass2.errors.txt +++ b/tests/baselines/reference/augmentedTypesClass2.errors.txt @@ -1,24 +1,18 @@ -tests/cases/compiler/augmentedTypesClass2.ts(4,7): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/augmentedTypesClass2.ts(10,11): error TS2518: Only an ambient class can be merged with an interface. tests/cases/compiler/augmentedTypesClass2.ts(16,7): error TS2300: Duplicate identifier 'c33'. tests/cases/compiler/augmentedTypesClass2.ts(21,6): error TS2300: Duplicate identifier 'c33'. -==== tests/cases/compiler/augmentedTypesClass2.ts (4 errors) ==== +==== tests/cases/compiler/augmentedTypesClass2.ts (2 errors) ==== // Checking class with other things in type space not value space // class then interface - class c11 { // error - ~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. + class c11 { foo() { return 1; } } - interface c11 { // error - ~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. + interface c11 { bar(): void; } diff --git a/tests/baselines/reference/augmentedTypesClass2.js b/tests/baselines/reference/augmentedTypesClass2.js index f75c08a5920..4a919913ce0 100644 --- a/tests/baselines/reference/augmentedTypesClass2.js +++ b/tests/baselines/reference/augmentedTypesClass2.js @@ -2,13 +2,13 @@ // Checking class with other things in type space not value space // class then interface -class c11 { // error +class c11 { foo() { return 1; } } -interface c11 { // error +interface c11 { bar(): void; } diff --git a/tests/baselines/reference/augmentedTypesInterface.errors.txt b/tests/baselines/reference/augmentedTypesInterface.errors.txt index 690bf8b7a99..51092e1d27f 100644 --- a/tests/baselines/reference/augmentedTypesInterface.errors.txt +++ b/tests/baselines/reference/augmentedTypesInterface.errors.txt @@ -1,10 +1,8 @@ -tests/cases/compiler/augmentedTypesInterface.ts(12,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/augmentedTypesInterface.ts(16,7): error TS2518: Only an ambient class can be merged with an interface. tests/cases/compiler/augmentedTypesInterface.ts(23,11): error TS2300: Duplicate identifier 'i3'. tests/cases/compiler/augmentedTypesInterface.ts(26,6): error TS2300: Duplicate identifier 'i3'. -==== tests/cases/compiler/augmentedTypesInterface.ts (4 errors) ==== +==== tests/cases/compiler/augmentedTypesInterface.ts (2 errors) ==== // interface then interface interface i { @@ -16,15 +14,11 @@ tests/cases/compiler/augmentedTypesInterface.ts(26,6): error TS2300: Duplicate i } // interface then class - interface i2 { // error - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. + interface i2 { foo(): void; } - class i2 { // error - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. + class i2 { bar() { return 1; } diff --git a/tests/baselines/reference/augmentedTypesInterface.js b/tests/baselines/reference/augmentedTypesInterface.js index e28864fd547..330fc035a9e 100644 --- a/tests/baselines/reference/augmentedTypesInterface.js +++ b/tests/baselines/reference/augmentedTypesInterface.js @@ -10,11 +10,11 @@ interface i { } // interface then class -interface i2 { // error +interface i2 { foo(): void; } -class i2 { // error +class i2 { bar() { return 1; } diff --git a/tests/baselines/reference/classAbstractMergedDeclaration.errors.txt b/tests/baselines/reference/classAbstractMergedDeclaration.errors.txt index b3a2dec5e9c..3e18d8796fb 100644 --- a/tests/baselines/reference/classAbstractMergedDeclaration.errors.txt +++ b/tests/baselines/reference/classAbstractMergedDeclaration.errors.txt @@ -1,7 +1,3 @@ -tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(7,16): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(8,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(10,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(11,16): error TS2518: Only an ambient class can be merged with an interface. tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(13,16): error TS2300: Duplicate identifier 'CC1'. tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(14,7): error TS2300: Duplicate identifier 'CC1'. tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(16,7): error TS2300: Duplicate identifier 'CC2'. @@ -20,7 +16,7 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(39,1): error TS2511: Cannot create an instance of the abstract class 'DCC1'. -==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts (20 errors) ==== +==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts (16 errors) ==== abstract class CM {} module CM {} @@ -28,18 +24,10 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst abstract class MC {} abstract class CI {} - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. interface CI {} - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. interface IC {} - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. abstract class IC {} - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. abstract class CC1 {} ~~~ diff --git a/tests/baselines/reference/classAndInterfaceWithSameName.errors.txt b/tests/baselines/reference/classAndInterfaceWithSameName.errors.txt index 332024b74fd..f1f26f50f3e 100644 --- a/tests/baselines/reference/classAndInterfaceWithSameName.errors.txt +++ b/tests/baselines/reference/classAndInterfaceWithSameName.errors.txt @@ -1,37 +1,25 @@ -tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts(1,7): error TS2518: Only an ambient class can be merged with an interface. tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts(1,11): error TS2300: Duplicate identifier 'foo'. -tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts(2,11): error TS2518: Only an ambient class can be merged with an interface. tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts(2,15): error TS2300: Duplicate identifier 'foo'. -tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts(5,11): error TS2518: Only an ambient class can be merged with an interface. tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts(6,9): error TS2300: Duplicate identifier 'bar'. -tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts(9,15): error TS2518: Only an ambient class can be merged with an interface. tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts(10,9): error TS2300: Duplicate identifier 'bar'. -==== tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts (8 errors) ==== +==== tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts (4 errors) ==== class C { foo: string; } - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. ~~~ !!! error TS2300: Duplicate identifier 'foo'. - interface C { foo: string; } // error - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. + interface C { foo: string; } ~~~ !!! error TS2300: Duplicate identifier 'foo'. module M { class D { - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. bar: string; ~~~ !!! error TS2300: Duplicate identifier 'bar'. } - interface D { // error - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. + interface D { bar: string; ~~~ !!! error TS2300: Duplicate identifier 'bar'. diff --git a/tests/baselines/reference/classAndInterfaceWithSameName.js b/tests/baselines/reference/classAndInterfaceWithSameName.js index 09886e34bc8..bca0c96892c 100644 --- a/tests/baselines/reference/classAndInterfaceWithSameName.js +++ b/tests/baselines/reference/classAndInterfaceWithSameName.js @@ -1,13 +1,13 @@ //// [classAndInterfaceWithSameName.ts] class C { foo: string; } -interface C { foo: string; } // error +interface C { foo: string; } module M { class D { bar: string; } - interface D { // error + interface D { bar: string; } } diff --git a/tests/baselines/reference/clinterfaces.errors.txt b/tests/baselines/reference/clinterfaces.errors.txt deleted file mode 100644 index 5960e6ae32b..00000000000 --- a/tests/baselines/reference/clinterfaces.errors.txt +++ /dev/null @@ -1,52 +0,0 @@ -tests/cases/compiler/clinterfaces.ts(2,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/clinterfaces.ts(3,15): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/clinterfaces.ts(4,15): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/clinterfaces.ts(5,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/clinterfaces.ts(8,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/clinterfaces.ts(12,7): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/clinterfaces.ts(16,7): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/clinterfaces.ts(20,11): error TS2518: Only an ambient class can be merged with an interface. - - -==== tests/cases/compiler/clinterfaces.ts (8 errors) ==== - module M { - class C { } - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. - interface C { } - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. - interface D { } - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. - class D { } - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. - } - - interface Foo { - ~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - a: string; - } - - class Foo{ - ~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - b: number; - } - - class Bar{ - ~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - b: number; - } - - interface Bar { - ~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - a: string; - } - - export = Foo; - \ No newline at end of file diff --git a/tests/baselines/reference/clinterfaces.symbols b/tests/baselines/reference/clinterfaces.symbols new file mode 100644 index 00000000000..76c7d74b521 --- /dev/null +++ b/tests/baselines/reference/clinterfaces.symbols @@ -0,0 +1,52 @@ +=== tests/cases/compiler/clinterfaces.ts === +module M { +>M : Symbol(M, Decl(clinterfaces.ts, 0, 0)) + + class C { } +>C : Symbol(C, Decl(clinterfaces.ts, 0, 10), Decl(clinterfaces.ts, 1, 15)) + + interface C { } +>C : Symbol(C, Decl(clinterfaces.ts, 0, 10), Decl(clinterfaces.ts, 1, 15)) + + interface D { } +>D : Symbol(D, Decl(clinterfaces.ts, 2, 19), Decl(clinterfaces.ts, 3, 19)) + + class D { } +>D : Symbol(D, Decl(clinterfaces.ts, 2, 19), Decl(clinterfaces.ts, 3, 19)) +} + +interface Foo { +>Foo : Symbol(Foo, Decl(clinterfaces.ts, 5, 1), Decl(clinterfaces.ts, 9, 1)) +>T : Symbol(T, Decl(clinterfaces.ts, 7, 14), Decl(clinterfaces.ts, 11, 10)) + + a: string; +>a : Symbol(a, Decl(clinterfaces.ts, 7, 18)) +} + +class Foo{ +>Foo : Symbol(Foo, Decl(clinterfaces.ts, 5, 1), Decl(clinterfaces.ts, 9, 1)) +>T : Symbol(T, Decl(clinterfaces.ts, 7, 14), Decl(clinterfaces.ts, 11, 10)) + + b: number; +>b : Symbol(b, Decl(clinterfaces.ts, 11, 13)) +} + +class Bar{ +>Bar : Symbol(Bar, Decl(clinterfaces.ts, 13, 1), Decl(clinterfaces.ts, 17, 1)) +>T : Symbol(T, Decl(clinterfaces.ts, 15, 10), Decl(clinterfaces.ts, 19, 14)) + + b: number; +>b : Symbol(b, Decl(clinterfaces.ts, 15, 13)) +} + +interface Bar { +>Bar : Symbol(Bar, Decl(clinterfaces.ts, 13, 1), Decl(clinterfaces.ts, 17, 1)) +>T : Symbol(T, Decl(clinterfaces.ts, 15, 10), Decl(clinterfaces.ts, 19, 14)) + + a: string; +>a : Symbol(a, Decl(clinterfaces.ts, 19, 18)) +} + +export = Foo; +>Foo : Symbol(Foo, Decl(clinterfaces.ts, 5, 1), Decl(clinterfaces.ts, 9, 1)) + diff --git a/tests/baselines/reference/clinterfaces.types b/tests/baselines/reference/clinterfaces.types new file mode 100644 index 00000000000..18c27f33e55 --- /dev/null +++ b/tests/baselines/reference/clinterfaces.types @@ -0,0 +1,52 @@ +=== tests/cases/compiler/clinterfaces.ts === +module M { +>M : typeof M + + class C { } +>C : C + + interface C { } +>C : C + + interface D { } +>D : D + + class D { } +>D : D +} + +interface Foo { +>Foo : Foo +>T : T + + a: string; +>a : string +} + +class Foo{ +>Foo : Foo +>T : T + + b: number; +>b : number +} + +class Bar{ +>Bar : Bar +>T : T + + b: number; +>b : number +} + +interface Bar { +>Bar : Bar +>T : T + + a: string; +>a : string +} + +export = Foo; +>Foo : Foo + diff --git a/tests/baselines/reference/declInput.errors.txt b/tests/baselines/reference/declInput.errors.txt deleted file mode 100644 index 179db3598ab..00000000000 --- a/tests/baselines/reference/declInput.errors.txt +++ /dev/null @@ -1,19 +0,0 @@ -tests/cases/compiler/declInput.ts(1,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/declInput.ts(5,7): error TS2518: Only an ambient class can be merged with an interface. - - -==== tests/cases/compiler/declInput.ts (2 errors) ==== - interface bar { - ~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - - } - - class bar { - ~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - public f() { return ''; } - public g() { return {a: null, b: undefined, c: void 4 }; } - public h(x = 4, y = null, z = '') { x++; } - } - \ No newline at end of file diff --git a/tests/baselines/reference/declInput.symbols b/tests/baselines/reference/declInput.symbols new file mode 100644 index 00000000000..90f075218c0 --- /dev/null +++ b/tests/baselines/reference/declInput.symbols @@ -0,0 +1,28 @@ +=== tests/cases/compiler/declInput.ts === +interface bar { +>bar : Symbol(bar, Decl(declInput.ts, 0, 0), Decl(declInput.ts, 2, 1)) + +} + +class bar { +>bar : Symbol(bar, Decl(declInput.ts, 0, 0), Decl(declInput.ts, 2, 1)) + + public f() { return ''; } +>f : Symbol(f, Decl(declInput.ts, 4, 11)) + + public g() { return {a: null, b: undefined, c: void 4 }; } +>g : Symbol(g, Decl(declInput.ts, 5, 27)) +>a : Symbol(a, Decl(declInput.ts, 6, 23)) +>bar : Symbol(bar, Decl(declInput.ts, 0, 0), Decl(declInput.ts, 2, 1)) +>b : Symbol(b, Decl(declInput.ts, 6, 36)) +>undefined : Symbol(undefined) +>c : Symbol(c, Decl(declInput.ts, 6, 50)) + + public h(x = 4, y = null, z = '') { x++; } +>h : Symbol(h, Decl(declInput.ts, 6, 65)) +>x : Symbol(x, Decl(declInput.ts, 7, 11)) +>y : Symbol(y, Decl(declInput.ts, 7, 17)) +>z : Symbol(z, Decl(declInput.ts, 7, 27)) +>x : Symbol(x, Decl(declInput.ts, 7, 11)) +} + diff --git a/tests/baselines/reference/declInput.types b/tests/baselines/reference/declInput.types new file mode 100644 index 00000000000..e59e3811fdf --- /dev/null +++ b/tests/baselines/reference/declInput.types @@ -0,0 +1,38 @@ +=== tests/cases/compiler/declInput.ts === +interface bar { +>bar : bar + +} + +class bar { +>bar : bar + + public f() { return ''; } +>f : () => string +>'' : string + + public g() { return {a: null, b: undefined, c: void 4 }; } +>g : () => { a: bar; b: any; c: any; } +>{a: null, b: undefined, c: void 4 } : { a: bar; b: undefined; c: undefined; } +>a : bar +>null : bar +>bar : bar +>null : null +>b : undefined +>undefined : undefined +>c : undefined +>void 4 : undefined +>4 : number + + public h(x = 4, y = null, z = '') { x++; } +>h : (x?: number, y?: any, z?: string) => void +>x : number +>4 : number +>y : any +>null : null +>z : string +>'' : string +>x++ : number +>x : number +} + diff --git a/tests/baselines/reference/defaultExportsCannotMerge03.errors.txt b/tests/baselines/reference/defaultExportsCannotMerge03.errors.txt index 11e9c63b893..e8782abedd6 100644 --- a/tests/baselines/reference/defaultExportsCannotMerge03.errors.txt +++ b/tests/baselines/reference/defaultExportsCannotMerge03.errors.txt @@ -1,10 +1,9 @@ tests/cases/conformance/es6/modules/m1.ts(2,22): error TS2652: Merged declaration 'Decl' cannot include a default export declaration. Consider adding a separate 'export default Decl' declaration instead. -tests/cases/conformance/es6/modules/m1.ts(5,11): error TS2518: Only an ambient class can be merged with an interface. tests/cases/conformance/es6/modules/m1.ts(5,11): error TS2652: Merged declaration 'Decl' cannot include a default export declaration. Consider adding a separate 'export default Decl' declaration instead. tests/cases/conformance/es6/modules/m2.ts(1,20): error TS2307: Cannot find module 'm1'. -==== tests/cases/conformance/es6/modules/m1.ts (3 errors) ==== +==== tests/cases/conformance/es6/modules/m1.ts (2 errors) ==== export default class Decl { ~~~~ @@ -13,8 +12,6 @@ tests/cases/conformance/es6/modules/m2.ts(1,20): error TS2307: Cannot find modul interface Decl { ~~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - ~~~~ !!! error TS2652: Merged declaration 'Decl' cannot include a default export declaration. Consider adding a separate 'export default Decl' declaration instead. p1: number; p2: number; diff --git a/tests/baselines/reference/duplicateIdentifiersAcrossContainerBoundaries.errors.txt b/tests/baselines/reference/duplicateIdentifiersAcrossContainerBoundaries.errors.txt index 731e9748203..684c123ebd7 100644 --- a/tests/baselines/reference/duplicateIdentifiersAcrossContainerBoundaries.errors.txt +++ b/tests/baselines/reference/duplicateIdentifiersAcrossContainerBoundaries.errors.txt @@ -1,21 +1,15 @@ -tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts(2,22): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts(5,18): error TS2518: Only an ambient class can be merged with an interface. tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts(9,21): error TS2300: Duplicate identifier 'f'. tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts(12,18): error TS2300: Duplicate identifier 'f'. tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts(37,12): error TS2300: Duplicate identifier 'x'. tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts(41,16): error TS2300: Duplicate identifier 'x'. -==== tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts (6 errors) ==== +==== tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts (4 errors) ==== module M { export interface I { } - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. } module M { - export class I { } // error - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. + export class I { } } module M { diff --git a/tests/baselines/reference/duplicateIdentifiersAcrossContainerBoundaries.js b/tests/baselines/reference/duplicateIdentifiersAcrossContainerBoundaries.js index 944ef4e3d5f..ad96e55a507 100644 --- a/tests/baselines/reference/duplicateIdentifiersAcrossContainerBoundaries.js +++ b/tests/baselines/reference/duplicateIdentifiersAcrossContainerBoundaries.js @@ -3,7 +3,7 @@ module M { export interface I { } } module M { - export class I { } // error + export class I { } } module M { @@ -60,7 +60,7 @@ var M; } return I; })(); - M.I = I; // error + M.I = I; })(M || (M = {})); var M; (function (M) { diff --git a/tests/baselines/reference/duplicateIdentifiersAcrossFileBoundaries.errors.txt b/tests/baselines/reference/duplicateIdentifiersAcrossFileBoundaries.errors.txt index 9867441f770..db7d0205fc9 100644 --- a/tests/baselines/reference/duplicateIdentifiersAcrossFileBoundaries.errors.txt +++ b/tests/baselines/reference/duplicateIdentifiersAcrossFileBoundaries.errors.txt @@ -1,24 +1,16 @@ -tests/cases/compiler/file1.ts(2,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/file1.ts(3,7): error TS2518: Only an ambient class can be merged with an interface. tests/cases/compiler/file1.ts(4,7): error TS2300: Duplicate identifier 'C2'. tests/cases/compiler/file1.ts(5,10): error TS2300: Duplicate identifier 'f'. tests/cases/compiler/file1.ts(9,12): error TS2300: Duplicate identifier 'x'. -tests/cases/compiler/file2.ts(1,7): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/file2.ts(2,11): error TS2518: Only an ambient class can be merged with an interface. tests/cases/compiler/file2.ts(3,10): error TS2300: Duplicate identifier 'C2'. tests/cases/compiler/file2.ts(4,7): error TS2300: Duplicate identifier 'f'. tests/cases/compiler/file2.ts(7,8): error TS2433: A namespace declaration cannot be in a different file from a class or function with which it is merged tests/cases/compiler/file2.ts(8,16): error TS2300: Duplicate identifier 'x'. -==== tests/cases/compiler/file1.ts (5 errors) ==== +==== tests/cases/compiler/file1.ts (3 errors) ==== interface I { } - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. class C1 { } - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. class C2 { } ~~ !!! error TS2300: Duplicate identifier 'C2'. @@ -39,13 +31,9 @@ tests/cases/compiler/file2.ts(8,16): error TS2300: Duplicate identifier 'x'. } } -==== tests/cases/compiler/file2.ts (6 errors) ==== +==== tests/cases/compiler/file2.ts (4 errors) ==== class I { } // error -- cannot merge interface with non-ambient class - ~ -!!! error TS2518: Only an ambient class can be merged with an interface. interface C1 { } // error -- cannot merge interface with non-ambient class - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. function C2() { } // error -- cannot merge function with non-ambient class ~~ !!! error TS2300: Duplicate identifier 'C2'. diff --git a/tests/baselines/reference/es2015modulekind.js b/tests/baselines/reference/es2015modulekind.js new file mode 100644 index 00000000000..af638557fde --- /dev/null +++ b/tests/baselines/reference/es2015modulekind.js @@ -0,0 +1,23 @@ +//// [es2015modulekind.ts] + +export default class A +{ + constructor () + { + + } + + public B() + { + return 42; + } +} + +//// [es2015modulekind.js] +export default class A { + constructor() { + } + B() { + return 42; + } +} diff --git a/tests/baselines/reference/es2015modulekind.symbols b/tests/baselines/reference/es2015modulekind.symbols new file mode 100644 index 00000000000..227443ac06b --- /dev/null +++ b/tests/baselines/reference/es2015modulekind.symbols @@ -0,0 +1,16 @@ +=== tests/cases/compiler/es2015modulekind.ts === + +export default class A +>A : Symbol(A, Decl(es2015modulekind.ts, 0, 0)) +{ + constructor () + { + + } + + public B() +>B : Symbol(B, Decl(es2015modulekind.ts, 6, 5)) + { + return 42; + } +} diff --git a/tests/baselines/reference/es2015modulekind.types b/tests/baselines/reference/es2015modulekind.types new file mode 100644 index 00000000000..e77cf095aed --- /dev/null +++ b/tests/baselines/reference/es2015modulekind.types @@ -0,0 +1,17 @@ +=== tests/cases/compiler/es2015modulekind.ts === + +export default class A +>A : A +{ + constructor () + { + + } + + public B() +>B : () => number + { + return 42; +>42 : number + } +} diff --git a/tests/baselines/reference/es2015modulekindWithES6Target.js b/tests/baselines/reference/es2015modulekindWithES6Target.js new file mode 100644 index 00000000000..b76ab2a02a2 --- /dev/null +++ b/tests/baselines/reference/es2015modulekindWithES6Target.js @@ -0,0 +1,23 @@ +//// [es2015modulekindWithES6Target.ts] + +export default class A +{ + constructor () + { + + } + + public B() + { + return 42; + } +} + +//// [es2015modulekindWithES6Target.js] +export default class A { + constructor() { + } + B() { + return 42; + } +} diff --git a/tests/baselines/reference/es2015modulekindWithES6Target.symbols b/tests/baselines/reference/es2015modulekindWithES6Target.symbols new file mode 100644 index 00000000000..2ff208ac704 --- /dev/null +++ b/tests/baselines/reference/es2015modulekindWithES6Target.symbols @@ -0,0 +1,16 @@ +=== tests/cases/compiler/es2015modulekindWithES6Target.ts === + +export default class A +>A : Symbol(A, Decl(es2015modulekindWithES6Target.ts, 0, 0)) +{ + constructor () + { + + } + + public B() +>B : Symbol(B, Decl(es2015modulekindWithES6Target.ts, 6, 5)) + { + return 42; + } +} diff --git a/tests/baselines/reference/es2015modulekindWithES6Target.types b/tests/baselines/reference/es2015modulekindWithES6Target.types new file mode 100644 index 00000000000..50b85921b0e --- /dev/null +++ b/tests/baselines/reference/es2015modulekindWithES6Target.types @@ -0,0 +1,17 @@ +=== tests/cases/compiler/es2015modulekindWithES6Target.ts === + +export default class A +>A : A +{ + constructor () + { + + } + + public B() +>B : () => number + { + return 42; +>42 : number + } +} diff --git a/tests/baselines/reference/es6modulekindWithES2015Target.js b/tests/baselines/reference/es6modulekindWithES2015Target.js new file mode 100644 index 00000000000..98808fd1c65 --- /dev/null +++ b/tests/baselines/reference/es6modulekindWithES2015Target.js @@ -0,0 +1,23 @@ +//// [es6modulekindWithES2015Target.ts] + +export default class A +{ + constructor () + { + + } + + public B() + { + return 42; + } +} + +//// [es6modulekindWithES2015Target.js] +export default class A { + constructor() { + } + B() { + return 42; + } +} diff --git a/tests/baselines/reference/es6modulekindWithES2015Target.symbols b/tests/baselines/reference/es6modulekindWithES2015Target.symbols new file mode 100644 index 00000000000..98b91a0411b --- /dev/null +++ b/tests/baselines/reference/es6modulekindWithES2015Target.symbols @@ -0,0 +1,16 @@ +=== tests/cases/compiler/es6modulekindWithES2015Target.ts === + +export default class A +>A : Symbol(A, Decl(es6modulekindWithES2015Target.ts, 0, 0)) +{ + constructor () + { + + } + + public B() +>B : Symbol(B, Decl(es6modulekindWithES2015Target.ts, 6, 5)) + { + return 42; + } +} diff --git a/tests/baselines/reference/es6modulekindWithES2015Target.types b/tests/baselines/reference/es6modulekindWithES2015Target.types new file mode 100644 index 00000000000..63acdae43d1 --- /dev/null +++ b/tests/baselines/reference/es6modulekindWithES2015Target.types @@ -0,0 +1,17 @@ +=== tests/cases/compiler/es6modulekindWithES2015Target.ts === + +export default class A +>A : A +{ + constructor () + { + + } + + public B() +>B : () => number + { + return 42; +>42 : number + } +} diff --git a/tests/baselines/reference/interfaceClassMerging.js b/tests/baselines/reference/interfaceClassMerging.js new file mode 100644 index 00000000000..565884e95ef --- /dev/null +++ b/tests/baselines/reference/interfaceClassMerging.js @@ -0,0 +1,76 @@ +//// [interfaceClassMerging.ts] +interface Foo { + method(a: number): string; + optionalMethod?(a: number): string; + property: string; + optionalProperty?: string; +} + +class Foo { + additionalProperty: string; + + additionalMethod(a: number): string { + return this.method(0); + } +} + +class Bar extends Foo { + method(a: number) { + return this.optionalProperty; + } +} + + +var bar = new Bar(); +bar.method(0); +bar.optionalMethod(1); +bar.property; +bar.optionalProperty; +bar.additionalProperty; +bar.additionalMethod(2); + +var obj: { + method(a: number): string; + property: string; + additionalProperty: string; + additionalMethod(a: number): string; +}; + +bar = obj; +obj = bar; + + +//// [interfaceClassMerging.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var Foo = (function () { + function Foo() { + } + Foo.prototype.additionalMethod = function (a) { + return this.method(0); + }; + return Foo; +})(); +var Bar = (function (_super) { + __extends(Bar, _super); + function Bar() { + _super.apply(this, arguments); + } + Bar.prototype.method = function (a) { + return this.optionalProperty; + }; + return Bar; +})(Foo); +var bar = new Bar(); +bar.method(0); +bar.optionalMethod(1); +bar.property; +bar.optionalProperty; +bar.additionalProperty; +bar.additionalMethod(2); +var obj; +bar = obj; +obj = bar; diff --git a/tests/baselines/reference/interfaceClassMerging.symbols b/tests/baselines/reference/interfaceClassMerging.symbols new file mode 100644 index 00000000000..eda94cedafd --- /dev/null +++ b/tests/baselines/reference/interfaceClassMerging.symbols @@ -0,0 +1,113 @@ +=== tests/cases/compiler/interfaceClassMerging.ts === +interface Foo { +>Foo : Symbol(Foo, Decl(interfaceClassMerging.ts, 0, 0), Decl(interfaceClassMerging.ts, 5, 1)) + + method(a: number): string; +>method : Symbol(method, Decl(interfaceClassMerging.ts, 0, 15)) +>a : Symbol(a, Decl(interfaceClassMerging.ts, 1, 11)) + + optionalMethod?(a: number): string; +>optionalMethod : Symbol(optionalMethod, Decl(interfaceClassMerging.ts, 1, 30)) +>a : Symbol(a, Decl(interfaceClassMerging.ts, 2, 20)) + + property: string; +>property : Symbol(property, Decl(interfaceClassMerging.ts, 2, 39)) + + optionalProperty?: string; +>optionalProperty : Symbol(optionalProperty, Decl(interfaceClassMerging.ts, 3, 21)) +} + +class Foo { +>Foo : Symbol(Foo, Decl(interfaceClassMerging.ts, 0, 0), Decl(interfaceClassMerging.ts, 5, 1)) + + additionalProperty: string; +>additionalProperty : Symbol(additionalProperty, Decl(interfaceClassMerging.ts, 7, 11)) + + additionalMethod(a: number): string { +>additionalMethod : Symbol(additionalMethod, Decl(interfaceClassMerging.ts, 8, 31)) +>a : Symbol(a, Decl(interfaceClassMerging.ts, 10, 21)) + + return this.method(0); +>this.method : Symbol(method, Decl(interfaceClassMerging.ts, 0, 15)) +>this : Symbol(Foo, Decl(interfaceClassMerging.ts, 0, 0), Decl(interfaceClassMerging.ts, 5, 1)) +>method : Symbol(method, Decl(interfaceClassMerging.ts, 0, 15)) + } +} + +class Bar extends Foo { +>Bar : Symbol(Bar, Decl(interfaceClassMerging.ts, 13, 1)) +>Foo : Symbol(Foo, Decl(interfaceClassMerging.ts, 0, 0), Decl(interfaceClassMerging.ts, 5, 1)) + + method(a: number) { +>method : Symbol(method, Decl(interfaceClassMerging.ts, 15, 23)) +>a : Symbol(a, Decl(interfaceClassMerging.ts, 16, 11)) + + return this.optionalProperty; +>this.optionalProperty : Symbol(Foo.optionalProperty, Decl(interfaceClassMerging.ts, 3, 21)) +>this : Symbol(Bar, Decl(interfaceClassMerging.ts, 13, 1)) +>optionalProperty : Symbol(Foo.optionalProperty, Decl(interfaceClassMerging.ts, 3, 21)) + } +} + + +var bar = new Bar(); +>bar : Symbol(bar, Decl(interfaceClassMerging.ts, 22, 3)) +>Bar : Symbol(Bar, Decl(interfaceClassMerging.ts, 13, 1)) + +bar.method(0); +>bar.method : Symbol(Bar.method, Decl(interfaceClassMerging.ts, 15, 23)) +>bar : Symbol(bar, Decl(interfaceClassMerging.ts, 22, 3)) +>method : Symbol(Bar.method, Decl(interfaceClassMerging.ts, 15, 23)) + +bar.optionalMethod(1); +>bar.optionalMethod : Symbol(Foo.optionalMethod, Decl(interfaceClassMerging.ts, 1, 30)) +>bar : Symbol(bar, Decl(interfaceClassMerging.ts, 22, 3)) +>optionalMethod : Symbol(Foo.optionalMethod, Decl(interfaceClassMerging.ts, 1, 30)) + +bar.property; +>bar.property : Symbol(Foo.property, Decl(interfaceClassMerging.ts, 2, 39)) +>bar : Symbol(bar, Decl(interfaceClassMerging.ts, 22, 3)) +>property : Symbol(Foo.property, Decl(interfaceClassMerging.ts, 2, 39)) + +bar.optionalProperty; +>bar.optionalProperty : Symbol(Foo.optionalProperty, Decl(interfaceClassMerging.ts, 3, 21)) +>bar : Symbol(bar, Decl(interfaceClassMerging.ts, 22, 3)) +>optionalProperty : Symbol(Foo.optionalProperty, Decl(interfaceClassMerging.ts, 3, 21)) + +bar.additionalProperty; +>bar.additionalProperty : Symbol(Foo.additionalProperty, Decl(interfaceClassMerging.ts, 7, 11)) +>bar : Symbol(bar, Decl(interfaceClassMerging.ts, 22, 3)) +>additionalProperty : Symbol(Foo.additionalProperty, Decl(interfaceClassMerging.ts, 7, 11)) + +bar.additionalMethod(2); +>bar.additionalMethod : Symbol(Foo.additionalMethod, Decl(interfaceClassMerging.ts, 8, 31)) +>bar : Symbol(bar, Decl(interfaceClassMerging.ts, 22, 3)) +>additionalMethod : Symbol(Foo.additionalMethod, Decl(interfaceClassMerging.ts, 8, 31)) + +var obj: { +>obj : Symbol(obj, Decl(interfaceClassMerging.ts, 30, 3)) + + method(a: number): string; +>method : Symbol(method, Decl(interfaceClassMerging.ts, 30, 10)) +>a : Symbol(a, Decl(interfaceClassMerging.ts, 31, 11)) + + property: string; +>property : Symbol(property, Decl(interfaceClassMerging.ts, 31, 30)) + + additionalProperty: string; +>additionalProperty : Symbol(additionalProperty, Decl(interfaceClassMerging.ts, 32, 21)) + + additionalMethod(a: number): string; +>additionalMethod : Symbol(additionalMethod, Decl(interfaceClassMerging.ts, 33, 31)) +>a : Symbol(a, Decl(interfaceClassMerging.ts, 34, 21)) + +}; + +bar = obj; +>bar : Symbol(bar, Decl(interfaceClassMerging.ts, 22, 3)) +>obj : Symbol(obj, Decl(interfaceClassMerging.ts, 30, 3)) + +obj = bar; +>obj : Symbol(obj, Decl(interfaceClassMerging.ts, 30, 3)) +>bar : Symbol(bar, Decl(interfaceClassMerging.ts, 22, 3)) + diff --git a/tests/baselines/reference/interfaceClassMerging.types b/tests/baselines/reference/interfaceClassMerging.types new file mode 100644 index 00000000000..0b17005c868 --- /dev/null +++ b/tests/baselines/reference/interfaceClassMerging.types @@ -0,0 +1,124 @@ +=== tests/cases/compiler/interfaceClassMerging.ts === +interface Foo { +>Foo : Foo + + method(a: number): string; +>method : (a: number) => string +>a : number + + optionalMethod?(a: number): string; +>optionalMethod : (a: number) => string +>a : number + + property: string; +>property : string + + optionalProperty?: string; +>optionalProperty : string +} + +class Foo { +>Foo : Foo + + additionalProperty: string; +>additionalProperty : string + + additionalMethod(a: number): string { +>additionalMethod : (a: number) => string +>a : number + + return this.method(0); +>this.method(0) : string +>this.method : (a: number) => string +>this : this +>method : (a: number) => string +>0 : number + } +} + +class Bar extends Foo { +>Bar : Bar +>Foo : Foo + + method(a: number) { +>method : (a: number) => string +>a : number + + return this.optionalProperty; +>this.optionalProperty : string +>this : this +>optionalProperty : string + } +} + + +var bar = new Bar(); +>bar : Bar +>new Bar() : Bar +>Bar : typeof Bar + +bar.method(0); +>bar.method(0) : string +>bar.method : (a: number) => string +>bar : Bar +>method : (a: number) => string +>0 : number + +bar.optionalMethod(1); +>bar.optionalMethod(1) : string +>bar.optionalMethod : (a: number) => string +>bar : Bar +>optionalMethod : (a: number) => string +>1 : number + +bar.property; +>bar.property : string +>bar : Bar +>property : string + +bar.optionalProperty; +>bar.optionalProperty : string +>bar : Bar +>optionalProperty : string + +bar.additionalProperty; +>bar.additionalProperty : string +>bar : Bar +>additionalProperty : string + +bar.additionalMethod(2); +>bar.additionalMethod(2) : string +>bar.additionalMethod : (a: number) => string +>bar : Bar +>additionalMethod : (a: number) => string +>2 : number + +var obj: { +>obj : { method(a: number): string; property: string; additionalProperty: string; additionalMethod(a: number): string; } + + method(a: number): string; +>method : (a: number) => string +>a : number + + property: string; +>property : string + + additionalProperty: string; +>additionalProperty : string + + additionalMethod(a: number): string; +>additionalMethod : (a: number) => string +>a : number + +}; + +bar = obj; +>bar = obj : { method(a: number): string; property: string; additionalProperty: string; additionalMethod(a: number): string; } +>bar : Bar +>obj : { method(a: number): string; property: string; additionalProperty: string; additionalMethod(a: number): string; } + +obj = bar; +>obj = bar : Bar +>obj : { method(a: number): string; property: string; additionalProperty: string; additionalMethod(a: number): string; } +>bar : Bar + diff --git a/tests/baselines/reference/interfaceClassMerging2.js b/tests/baselines/reference/interfaceClassMerging2.js new file mode 100644 index 00000000000..0b40067640c --- /dev/null +++ b/tests/baselines/reference/interfaceClassMerging2.js @@ -0,0 +1,66 @@ +//// [interfaceClassMerging2.ts] +interface Foo { + interfaceFooMethod(): this; + interfaceFooProperty: this; +} + +class Foo { + classFooProperty: this; + + classFooMethod(): this { + return this; + } +} + + +interface Bar { + interfaceBarMethod(): this; + interfaceBarProperty: this; +} + +class Bar extends Foo { + classBarProperty: this; + + classBarMethod(): this { + return this; + } +} + + +var bar = new Bar(); +bar.interfaceBarMethod().interfaceFooMethod().classBarMethod().classFooMethod(); + + +var foo = new Foo(); + +foo = bar; + + +//// [interfaceClassMerging2.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var Foo = (function () { + function Foo() { + } + Foo.prototype.classFooMethod = function () { + return this; + }; + return Foo; +})(); +var Bar = (function (_super) { + __extends(Bar, _super); + function Bar() { + _super.apply(this, arguments); + } + Bar.prototype.classBarMethod = function () { + return this; + }; + return Bar; +})(Foo); +var bar = new Bar(); +bar.interfaceBarMethod().interfaceFooMethod().classBarMethod().classFooMethod(); +var foo = new Foo(); +foo = bar; diff --git a/tests/baselines/reference/interfaceClassMerging2.symbols b/tests/baselines/reference/interfaceClassMerging2.symbols new file mode 100644 index 00000000000..290b49fdb3d --- /dev/null +++ b/tests/baselines/reference/interfaceClassMerging2.symbols @@ -0,0 +1,76 @@ +=== tests/cases/compiler/interfaceClassMerging2.ts === +interface Foo { +>Foo : Symbol(Foo, Decl(interfaceClassMerging2.ts, 0, 0), Decl(interfaceClassMerging2.ts, 3, 1)) + + interfaceFooMethod(): this; +>interfaceFooMethod : Symbol(interfaceFooMethod, Decl(interfaceClassMerging2.ts, 0, 15)) + + interfaceFooProperty: this; +>interfaceFooProperty : Symbol(interfaceFooProperty, Decl(interfaceClassMerging2.ts, 1, 31)) +} + +class Foo { +>Foo : Symbol(Foo, Decl(interfaceClassMerging2.ts, 0, 0), Decl(interfaceClassMerging2.ts, 3, 1)) + + classFooProperty: this; +>classFooProperty : Symbol(classFooProperty, Decl(interfaceClassMerging2.ts, 5, 11)) + + classFooMethod(): this { +>classFooMethod : Symbol(classFooMethod, Decl(interfaceClassMerging2.ts, 6, 27)) + + return this; +>this : Symbol(Foo, Decl(interfaceClassMerging2.ts, 0, 0), Decl(interfaceClassMerging2.ts, 3, 1)) + } +} + + +interface Bar { +>Bar : Symbol(Bar, Decl(interfaceClassMerging2.ts, 11, 1), Decl(interfaceClassMerging2.ts, 17, 1)) + + interfaceBarMethod(): this; +>interfaceBarMethod : Symbol(interfaceBarMethod, Decl(interfaceClassMerging2.ts, 14, 15)) + + interfaceBarProperty: this; +>interfaceBarProperty : Symbol(interfaceBarProperty, Decl(interfaceClassMerging2.ts, 15, 31)) +} + +class Bar extends Foo { +>Bar : Symbol(Bar, Decl(interfaceClassMerging2.ts, 11, 1), Decl(interfaceClassMerging2.ts, 17, 1)) +>Foo : Symbol(Foo, Decl(interfaceClassMerging2.ts, 0, 0), Decl(interfaceClassMerging2.ts, 3, 1)) + + classBarProperty: this; +>classBarProperty : Symbol(classBarProperty, Decl(interfaceClassMerging2.ts, 19, 23)) + + classBarMethod(): this { +>classBarMethod : Symbol(classBarMethod, Decl(interfaceClassMerging2.ts, 20, 27)) + + return this; +>this : Symbol(Bar, Decl(interfaceClassMerging2.ts, 11, 1), Decl(interfaceClassMerging2.ts, 17, 1)) + } +} + + +var bar = new Bar(); +>bar : Symbol(bar, Decl(interfaceClassMerging2.ts, 28, 3)) +>Bar : Symbol(Bar, Decl(interfaceClassMerging2.ts, 11, 1), Decl(interfaceClassMerging2.ts, 17, 1)) + +bar.interfaceBarMethod().interfaceFooMethod().classBarMethod().classFooMethod(); +>bar.interfaceBarMethod().interfaceFooMethod().classBarMethod().classFooMethod : Symbol(Foo.classFooMethod, Decl(interfaceClassMerging2.ts, 6, 27)) +>bar.interfaceBarMethod().interfaceFooMethod().classBarMethod : Symbol(Bar.classBarMethod, Decl(interfaceClassMerging2.ts, 20, 27)) +>bar.interfaceBarMethod().interfaceFooMethod : Symbol(Foo.interfaceFooMethod, Decl(interfaceClassMerging2.ts, 0, 15)) +>bar.interfaceBarMethod : Symbol(Bar.interfaceBarMethod, Decl(interfaceClassMerging2.ts, 14, 15)) +>bar : Symbol(bar, Decl(interfaceClassMerging2.ts, 28, 3)) +>interfaceBarMethod : Symbol(Bar.interfaceBarMethod, Decl(interfaceClassMerging2.ts, 14, 15)) +>interfaceFooMethod : Symbol(Foo.interfaceFooMethod, Decl(interfaceClassMerging2.ts, 0, 15)) +>classBarMethod : Symbol(Bar.classBarMethod, Decl(interfaceClassMerging2.ts, 20, 27)) +>classFooMethod : Symbol(Foo.classFooMethod, Decl(interfaceClassMerging2.ts, 6, 27)) + + +var foo = new Foo(); +>foo : Symbol(foo, Decl(interfaceClassMerging2.ts, 32, 3)) +>Foo : Symbol(Foo, Decl(interfaceClassMerging2.ts, 0, 0), Decl(interfaceClassMerging2.ts, 3, 1)) + +foo = bar; +>foo : Symbol(foo, Decl(interfaceClassMerging2.ts, 32, 3)) +>bar : Symbol(bar, Decl(interfaceClassMerging2.ts, 28, 3)) + diff --git a/tests/baselines/reference/interfaceClassMerging2.types b/tests/baselines/reference/interfaceClassMerging2.types new file mode 100644 index 00000000000..68da86b8821 --- /dev/null +++ b/tests/baselines/reference/interfaceClassMerging2.types @@ -0,0 +1,83 @@ +=== tests/cases/compiler/interfaceClassMerging2.ts === +interface Foo { +>Foo : Foo + + interfaceFooMethod(): this; +>interfaceFooMethod : () => this + + interfaceFooProperty: this; +>interfaceFooProperty : this +} + +class Foo { +>Foo : Foo + + classFooProperty: this; +>classFooProperty : this + + classFooMethod(): this { +>classFooMethod : () => this + + return this; +>this : this + } +} + + +interface Bar { +>Bar : Bar + + interfaceBarMethod(): this; +>interfaceBarMethod : () => this + + interfaceBarProperty: this; +>interfaceBarProperty : this +} + +class Bar extends Foo { +>Bar : Bar +>Foo : Foo + + classBarProperty: this; +>classBarProperty : this + + classBarMethod(): this { +>classBarMethod : () => this + + return this; +>this : this + } +} + + +var bar = new Bar(); +>bar : Bar +>new Bar() : Bar +>Bar : typeof Bar + +bar.interfaceBarMethod().interfaceFooMethod().classBarMethod().classFooMethod(); +>bar.interfaceBarMethod().interfaceFooMethod().classBarMethod().classFooMethod() : Bar +>bar.interfaceBarMethod().interfaceFooMethod().classBarMethod().classFooMethod : () => Bar +>bar.interfaceBarMethod().interfaceFooMethod().classBarMethod() : Bar +>bar.interfaceBarMethod().interfaceFooMethod().classBarMethod : () => Bar +>bar.interfaceBarMethod().interfaceFooMethod() : Bar +>bar.interfaceBarMethod().interfaceFooMethod : () => Bar +>bar.interfaceBarMethod() : Bar +>bar.interfaceBarMethod : () => Bar +>bar : Bar +>interfaceBarMethod : () => Bar +>interfaceFooMethod : () => Bar +>classBarMethod : () => Bar +>classFooMethod : () => Bar + + +var foo = new Foo(); +>foo : Foo +>new Foo() : Foo +>Foo : typeof Foo + +foo = bar; +>foo = bar : Bar +>foo : Foo +>bar : Bar + diff --git a/tests/baselines/reference/interfaceDeclaration2.errors.txt b/tests/baselines/reference/interfaceDeclaration2.errors.txt deleted file mode 100644 index db525e6f21f..00000000000 --- a/tests/baselines/reference/interfaceDeclaration2.errors.txt +++ /dev/null @@ -1,22 +0,0 @@ -tests/cases/compiler/interfaceDeclaration2.ts(4,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/interfaceDeclaration2.ts(5,7): error TS2518: Only an ambient class can be merged with an interface. - - -==== tests/cases/compiler/interfaceDeclaration2.ts (2 errors) ==== - interface I1 { } - module I1 { } - - interface I2 { } - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - class I2 { } - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - - interface I3 { } - function I3() { } - - interface I4 { } - var I4:number; - - \ No newline at end of file diff --git a/tests/baselines/reference/interfaceDeclaration2.symbols b/tests/baselines/reference/interfaceDeclaration2.symbols new file mode 100644 index 00000000000..e8588107355 --- /dev/null +++ b/tests/baselines/reference/interfaceDeclaration2.symbols @@ -0,0 +1,26 @@ +=== tests/cases/compiler/interfaceDeclaration2.ts === +interface I1 { } +>I1 : Symbol(I1, Decl(interfaceDeclaration2.ts, 0, 0), Decl(interfaceDeclaration2.ts, 0, 16)) + +module I1 { } +>I1 : Symbol(I1, Decl(interfaceDeclaration2.ts, 0, 0), Decl(interfaceDeclaration2.ts, 0, 16)) + +interface I2 { } +>I2 : Symbol(I2, Decl(interfaceDeclaration2.ts, 1, 13), Decl(interfaceDeclaration2.ts, 3, 16)) + +class I2 { } +>I2 : Symbol(I2, Decl(interfaceDeclaration2.ts, 1, 13), Decl(interfaceDeclaration2.ts, 3, 16)) + +interface I3 { } +>I3 : Symbol(I3, Decl(interfaceDeclaration2.ts, 4, 12), Decl(interfaceDeclaration2.ts, 6, 16)) + +function I3() { } +>I3 : Symbol(I3, Decl(interfaceDeclaration2.ts, 4, 12), Decl(interfaceDeclaration2.ts, 6, 16)) + +interface I4 { } +>I4 : Symbol(I4, Decl(interfaceDeclaration2.ts, 7, 17), Decl(interfaceDeclaration2.ts, 10, 3)) + +var I4:number; +>I4 : Symbol(I4, Decl(interfaceDeclaration2.ts, 7, 17), Decl(interfaceDeclaration2.ts, 10, 3)) + + diff --git a/tests/baselines/reference/interfaceDeclaration2.types b/tests/baselines/reference/interfaceDeclaration2.types new file mode 100644 index 00000000000..78e7a990ee6 --- /dev/null +++ b/tests/baselines/reference/interfaceDeclaration2.types @@ -0,0 +1,26 @@ +=== tests/cases/compiler/interfaceDeclaration2.ts === +interface I1 { } +>I1 : I1 + +module I1 { } +>I1 : any + +interface I2 { } +>I2 : I2 + +class I2 { } +>I2 : I2 + +interface I3 { } +>I3 : I3 + +function I3() { } +>I3 : () => void + +interface I4 { } +>I4 : I4 + +var I4:number; +>I4 : number + + diff --git a/tests/baselines/reference/mergedClassInterface.errors.txt b/tests/baselines/reference/mergedClassInterface.errors.txt deleted file mode 100644 index 5b23b046db7..00000000000 --- a/tests/baselines/reference/mergedClassInterface.errors.txt +++ /dev/null @@ -1,67 +0,0 @@ -tests/cases/conformance/classes/classDeclarations/file1.ts(11,7): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/conformance/classes/classDeclarations/file1.ts(13,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/conformance/classes/classDeclarations/file1.ts(15,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/conformance/classes/classDeclarations/file1.ts(17,7): error TS2518: Only an ambient class can be merged with an interface. - - -==== tests/cases/conformance/classes/classDeclarations/file1.ts (4 errors) ==== - - - declare class C1 { } - - interface C1 { } - - interface C2 { } - - declare class C2 { } - - class C3 { } // error -- cannot merge non-ambient class and interface - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - - interface C3 { } // error -- cannot merge non-ambient class and interface - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - - interface C4 { } // error -- cannot merge non-ambient class and interface - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - - class C4 { } // error -- cannot merge non-ambient class and interface - ~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - - interface C5 { - x1: number; - } - - declare class C5 { - x2: number; - } - - interface C5 { - x3: number; - } - - interface C5 { - x4: number; - } - - // checks if properties actually were merged - var c5 : C5; - c5.x1; - c5.x2; - c5.x3; - c5.x4; - -==== tests/cases/conformance/classes/classDeclarations/file2.ts (0 errors) ==== - - declare class C6 { } - - interface C7 { } - -==== tests/cases/conformance/classes/classDeclarations/file3.ts (0 errors) ==== - - interface C6 { } - - declare class C7 { } \ No newline at end of file diff --git a/tests/baselines/reference/mergedClassInterface.js b/tests/baselines/reference/mergedClassInterface.js index 7176255655d..64b52c23713 100644 --- a/tests/baselines/reference/mergedClassInterface.js +++ b/tests/baselines/reference/mergedClassInterface.js @@ -11,13 +11,13 @@ interface C2 { } declare class C2 { } -class C3 { } // error -- cannot merge non-ambient class and interface +class C3 { } -interface C3 { } // error -- cannot merge non-ambient class and interface +interface C3 { } -interface C4 { } // error -- cannot merge non-ambient class and interface +interface C4 { } -class C4 { } // error -- cannot merge non-ambient class and interface +class C4 { } interface C5 { x1: number; @@ -59,12 +59,12 @@ var C3 = (function () { function C3() { } return C3; -})(); // error -- cannot merge non-ambient class and interface +})(); var C4 = (function () { function C4() { } return C4; -})(); // error -- cannot merge non-ambient class and interface +})(); // checks if properties actually were merged var c5; c5.x1; diff --git a/tests/baselines/reference/mergedClassInterface.symbols b/tests/baselines/reference/mergedClassInterface.symbols new file mode 100644 index 00000000000..1c452851780 --- /dev/null +++ b/tests/baselines/reference/mergedClassInterface.symbols @@ -0,0 +1,96 @@ +=== tests/cases/conformance/classes/classDeclarations/file1.ts === + + +declare class C1 { } +>C1 : Symbol(C1, Decl(file1.ts, 0, 0), Decl(file1.ts, 2, 20)) + +interface C1 { } +>C1 : Symbol(C1, Decl(file1.ts, 0, 0), Decl(file1.ts, 2, 20)) + +interface C2 { } +>C2 : Symbol(C2, Decl(file1.ts, 4, 16), Decl(file1.ts, 6, 16)) + +declare class C2 { } +>C2 : Symbol(C2, Decl(file1.ts, 4, 16), Decl(file1.ts, 6, 16)) + +class C3 { } +>C3 : Symbol(C3, Decl(file1.ts, 8, 20), Decl(file1.ts, 10, 12)) + +interface C3 { } +>C3 : Symbol(C3, Decl(file1.ts, 8, 20), Decl(file1.ts, 10, 12)) + +interface C4 { } +>C4 : Symbol(C4, Decl(file1.ts, 12, 16), Decl(file1.ts, 14, 16)) + +class C4 { } +>C4 : Symbol(C4, Decl(file1.ts, 12, 16), Decl(file1.ts, 14, 16)) + +interface C5 { +>C5 : Symbol(C5, Decl(file1.ts, 16, 12), Decl(file1.ts, 20, 1), Decl(file1.ts, 24, 1), Decl(file1.ts, 28, 1)) + + x1: number; +>x1 : Symbol(x1, Decl(file1.ts, 18, 14)) +} + +declare class C5 { +>C5 : Symbol(C5, Decl(file1.ts, 16, 12), Decl(file1.ts, 20, 1), Decl(file1.ts, 24, 1), Decl(file1.ts, 28, 1)) + + x2: number; +>x2 : Symbol(x2, Decl(file1.ts, 22, 18)) +} + +interface C5 { +>C5 : Symbol(C5, Decl(file1.ts, 16, 12), Decl(file1.ts, 20, 1), Decl(file1.ts, 24, 1), Decl(file1.ts, 28, 1)) + + x3: number; +>x3 : Symbol(x3, Decl(file1.ts, 26, 14)) +} + +interface C5 { +>C5 : Symbol(C5, Decl(file1.ts, 16, 12), Decl(file1.ts, 20, 1), Decl(file1.ts, 24, 1), Decl(file1.ts, 28, 1)) + + x4: number; +>x4 : Symbol(x4, Decl(file1.ts, 30, 14)) +} + +// checks if properties actually were merged +var c5 : C5; +>c5 : Symbol(c5, Decl(file1.ts, 35, 3)) +>C5 : Symbol(C5, Decl(file1.ts, 16, 12), Decl(file1.ts, 20, 1), Decl(file1.ts, 24, 1), Decl(file1.ts, 28, 1)) + +c5.x1; +>c5.x1 : Symbol(C5.x1, Decl(file1.ts, 18, 14)) +>c5 : Symbol(c5, Decl(file1.ts, 35, 3)) +>x1 : Symbol(C5.x1, Decl(file1.ts, 18, 14)) + +c5.x2; +>c5.x2 : Symbol(C5.x2, Decl(file1.ts, 22, 18)) +>c5 : Symbol(c5, Decl(file1.ts, 35, 3)) +>x2 : Symbol(C5.x2, Decl(file1.ts, 22, 18)) + +c5.x3; +>c5.x3 : Symbol(C5.x3, Decl(file1.ts, 26, 14)) +>c5 : Symbol(c5, Decl(file1.ts, 35, 3)) +>x3 : Symbol(C5.x3, Decl(file1.ts, 26, 14)) + +c5.x4; +>c5.x4 : Symbol(C5.x4, Decl(file1.ts, 30, 14)) +>c5 : Symbol(c5, Decl(file1.ts, 35, 3)) +>x4 : Symbol(C5.x4, Decl(file1.ts, 30, 14)) + +=== tests/cases/conformance/classes/classDeclarations/file2.ts === + +declare class C6 { } +>C6 : Symbol(C6, Decl(file2.ts, 0, 0), Decl(file3.ts, 0, 0)) + +interface C7 { } +>C7 : Symbol(C7, Decl(file2.ts, 1, 20), Decl(file3.ts, 1, 16)) + +=== tests/cases/conformance/classes/classDeclarations/file3.ts === + +interface C6 { } +>C6 : Symbol(C6, Decl(file2.ts, 0, 0), Decl(file3.ts, 0, 0)) + +declare class C7 { } +>C7 : Symbol(C7, Decl(file2.ts, 1, 20), Decl(file3.ts, 1, 16)) + diff --git a/tests/baselines/reference/mergedClassInterface.types b/tests/baselines/reference/mergedClassInterface.types new file mode 100644 index 00000000000..4c3a6cca6a9 --- /dev/null +++ b/tests/baselines/reference/mergedClassInterface.types @@ -0,0 +1,96 @@ +=== tests/cases/conformance/classes/classDeclarations/file1.ts === + + +declare class C1 { } +>C1 : C1 + +interface C1 { } +>C1 : C1 + +interface C2 { } +>C2 : C2 + +declare class C2 { } +>C2 : C2 + +class C3 { } +>C3 : C3 + +interface C3 { } +>C3 : C3 + +interface C4 { } +>C4 : C4 + +class C4 { } +>C4 : C4 + +interface C5 { +>C5 : C5 + + x1: number; +>x1 : number +} + +declare class C5 { +>C5 : C5 + + x2: number; +>x2 : number +} + +interface C5 { +>C5 : C5 + + x3: number; +>x3 : number +} + +interface C5 { +>C5 : C5 + + x4: number; +>x4 : number +} + +// checks if properties actually were merged +var c5 : C5; +>c5 : C5 +>C5 : C5 + +c5.x1; +>c5.x1 : number +>c5 : C5 +>x1 : number + +c5.x2; +>c5.x2 : number +>c5 : C5 +>x2 : number + +c5.x3; +>c5.x3 : number +>c5 : C5 +>x3 : number + +c5.x4; +>c5.x4 : number +>c5 : C5 +>x4 : number + +=== tests/cases/conformance/classes/classDeclarations/file2.ts === + +declare class C6 { } +>C6 : C6 + +interface C7 { } +>C7 : C7 + +=== tests/cases/conformance/classes/classDeclarations/file3.ts === + +interface C6 { } +>C6 : C6 + +declare class C7 { } +>C7 : C7 + diff --git a/tests/baselines/reference/moduleMergeConstructor.js b/tests/baselines/reference/moduleMergeConstructor.js new file mode 100644 index 00000000000..f47e5791117 --- /dev/null +++ b/tests/baselines/reference/moduleMergeConstructor.js @@ -0,0 +1,38 @@ +//// [tests/cases/compiler/moduleMergeConstructor.ts] //// + +//// [foo.d.ts] + +declare module "foo" { + export class Foo { + constructor(); + method1(): any; + } +} + +//// [foo-ext.d.ts] +declare module "foo" { + export interface Foo { + method2(): any; + } +} + +//// [index.ts] +import * as foo from "foo"; + +class Test { + bar: foo.Foo; + constructor() { + this.bar = new foo.Foo(); + } +} + + +//// [index.js] +define(["require", "exports", "foo"], function (require, exports, foo) { + var Test = (function () { + function Test() { + this.bar = new foo.Foo(); + } + return Test; + })(); +}); diff --git a/tests/baselines/reference/moduleMergeConstructor.symbols b/tests/baselines/reference/moduleMergeConstructor.symbols new file mode 100644 index 00000000000..a960ad07e7e --- /dev/null +++ b/tests/baselines/reference/moduleMergeConstructor.symbols @@ -0,0 +1,45 @@ +=== tests/cases/compiler/foo.d.ts === + +declare module "foo" { + export class Foo { +>Foo : Symbol(Foo, Decl(foo.d.ts, 1, 22), Decl(foo-ext.d.ts, 0, 22)) + + constructor(); + method1(): any; +>method1 : Symbol(method1, Decl(foo.d.ts, 3, 22)) + } +} + +=== tests/cases/compiler/foo-ext.d.ts === +declare module "foo" { + export interface Foo { +>Foo : Symbol(Foo, Decl(foo.d.ts, 1, 22), Decl(foo-ext.d.ts, 0, 22)) + + method2(): any; +>method2 : Symbol(method2, Decl(foo-ext.d.ts, 1, 26)) + } +} + +=== tests/cases/compiler/index.ts === +import * as foo from "foo"; +>foo : Symbol(foo, Decl(index.ts, 0, 6)) + +class Test { +>Test : Symbol(Test, Decl(index.ts, 0, 27)) + + bar: foo.Foo; +>bar : Symbol(bar, Decl(index.ts, 2, 12)) +>foo : Symbol(foo, Decl(index.ts, 0, 6)) +>Foo : Symbol(foo.Foo, Decl(foo.d.ts, 1, 22), Decl(foo-ext.d.ts, 0, 22)) + + constructor() { + this.bar = new foo.Foo(); +>this.bar : Symbol(bar, Decl(index.ts, 2, 12)) +>this : Symbol(Test, Decl(index.ts, 0, 27)) +>bar : Symbol(bar, Decl(index.ts, 2, 12)) +>foo.Foo : Symbol(foo.Foo, Decl(foo.d.ts, 1, 22), Decl(foo-ext.d.ts, 0, 22)) +>foo : Symbol(foo, Decl(index.ts, 0, 6)) +>Foo : Symbol(foo.Foo, Decl(foo.d.ts, 1, 22), Decl(foo-ext.d.ts, 0, 22)) + } +} + diff --git a/tests/baselines/reference/moduleMergeConstructor.types b/tests/baselines/reference/moduleMergeConstructor.types new file mode 100644 index 00000000000..48a2f010293 --- /dev/null +++ b/tests/baselines/reference/moduleMergeConstructor.types @@ -0,0 +1,47 @@ +=== tests/cases/compiler/foo.d.ts === + +declare module "foo" { + export class Foo { +>Foo : Foo + + constructor(); + method1(): any; +>method1 : () => any + } +} + +=== tests/cases/compiler/foo-ext.d.ts === +declare module "foo" { + export interface Foo { +>Foo : Foo + + method2(): any; +>method2 : () => any + } +} + +=== tests/cases/compiler/index.ts === +import * as foo from "foo"; +>foo : typeof foo + +class Test { +>Test : Test + + bar: foo.Foo; +>bar : foo.Foo +>foo : any +>Foo : foo.Foo + + constructor() { + this.bar = new foo.Foo(); +>this.bar = new foo.Foo() : foo.Foo +>this.bar : foo.Foo +>this : this +>bar : foo.Foo +>new foo.Foo() : foo.Foo +>foo.Foo : typeof foo.Foo +>foo : typeof foo +>Foo : typeof foo.Foo + } +} + diff --git a/tests/baselines/reference/nameCollisions.errors.txt b/tests/baselines/reference/nameCollisions.errors.txt index 5c32d464070..e3c1b691371 100644 --- a/tests/baselines/reference/nameCollisions.errors.txt +++ b/tests/baselines/reference/nameCollisions.errors.txt @@ -11,13 +11,9 @@ tests/cases/compiler/nameCollisions.ts(33,11): error TS2300: Duplicate identifie tests/cases/compiler/nameCollisions.ts(34,14): error TS2300: Duplicate identifier 'C'. tests/cases/compiler/nameCollisions.ts(36,14): error TS2300: Duplicate identifier 'C2'. tests/cases/compiler/nameCollisions.ts(37,11): error TS2300: Duplicate identifier 'C2'. -tests/cases/compiler/nameCollisions.ts(42,11): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/nameCollisions.ts(43,15): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/nameCollisions.ts(45,15): error TS2518: Only an ambient class can be merged with an interface. -tests/cases/compiler/nameCollisions.ts(46,11): error TS2518: Only an ambient class can be merged with an interface. -==== tests/cases/compiler/nameCollisions.ts (17 errors) ==== +==== tests/cases/compiler/nameCollisions.ts (13 errors) ==== module T { var x = 2; ~ @@ -86,16 +82,8 @@ tests/cases/compiler/nameCollisions.ts(46,11): error TS2518: Only an ambient cla interface fi { } // ok class cli { } - ~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - interface cli { } // error - ~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. + interface cli { } interface cli2 { } - ~~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. - class cli2 { } // error - ~~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. + class cli2 { } } \ No newline at end of file diff --git a/tests/baselines/reference/nameCollisions.js b/tests/baselines/reference/nameCollisions.js index 2cfaba94993..96ae2e9838b 100644 --- a/tests/baselines/reference/nameCollisions.js +++ b/tests/baselines/reference/nameCollisions.js @@ -41,10 +41,10 @@ module T { interface fi { } // ok class cli { } - interface cli { } // error + interface cli { } interface cli2 { } - class cli2 { } // error + class cli2 { } } //// [nameCollisions.js] @@ -102,5 +102,5 @@ var T; function cli2() { } return cli2; - })(); // error + })(); })(T || (T = {})); diff --git a/tests/baselines/reference/templateStringsArrayTypeDefinedInES5Mode.errors.txt b/tests/baselines/reference/templateStringsArrayTypeDefinedInES5Mode.errors.txt index 69d686c3156..94ab5028647 100644 --- a/tests/baselines/reference/templateStringsArrayTypeDefinedInES5Mode.errors.txt +++ b/tests/baselines/reference/templateStringsArrayTypeDefinedInES5Mode.errors.txt @@ -1,13 +1,10 @@ -tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts(2,7): error TS2518: Only an ambient class can be merged with an interface. tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts(8,3): error TS2345: Argument of type '{}' is not assignable to parameter of type 'TemplateStringsArray'. Property 'raw' is missing in type '{}'. -==== tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts (2 errors) ==== +==== tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts (1 errors) ==== class TemplateStringsArray { - ~~~~~~~~~~~~~~~~~~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. } function f(x: TemplateStringsArray, y: number, z: number) { diff --git a/tests/baselines/reference/templateStringsArrayTypeRedefinedInES6Mode.errors.txt b/tests/baselines/reference/templateStringsArrayTypeRedefinedInES6Mode.errors.txt index 02ccd7f2413..f410d408482 100644 --- a/tests/baselines/reference/templateStringsArrayTypeRedefinedInES6Mode.errors.txt +++ b/tests/baselines/reference/templateStringsArrayTypeRedefinedInES6Mode.errors.txt @@ -1,13 +1,10 @@ -tests/cases/compiler/templateStringsArrayTypeRedefinedInES6Mode.ts(2,7): error TS2518: Only an ambient class can be merged with an interface. tests/cases/compiler/templateStringsArrayTypeRedefinedInES6Mode.ts(8,3): error TS2345: Argument of type '{}' is not assignable to parameter of type 'TemplateStringsArray'. Property 'raw' is missing in type '{}'. -==== tests/cases/compiler/templateStringsArrayTypeRedefinedInES6Mode.ts (2 errors) ==== +==== tests/cases/compiler/templateStringsArrayTypeRedefinedInES6Mode.ts (1 errors) ==== class TemplateStringsArray { - ~~~~~~~~~~~~~~~~~~~~ -!!! error TS2518: Only an ambient class can be merged with an interface. } function f(x: TemplateStringsArray, y: number, z: number) { diff --git a/tests/cases/compiler/ambientClassMergesOverloadsWithInterface.ts b/tests/cases/compiler/ambientClassMergesOverloadsWithInterface.ts new file mode 100644 index 00000000000..6a6d3658b63 --- /dev/null +++ b/tests/cases/compiler/ambientClassMergesOverloadsWithInterface.ts @@ -0,0 +1,8 @@ +declare class C { + baz(): any; + foo(n: number): any; +} +interface C { + foo(n: number): any; + bar(): any; +} diff --git a/tests/cases/compiler/arrayBufferIsViewNarrowsType.ts b/tests/cases/compiler/arrayBufferIsViewNarrowsType.ts new file mode 100644 index 00000000000..ba653408c20 --- /dev/null +++ b/tests/cases/compiler/arrayBufferIsViewNarrowsType.ts @@ -0,0 +1,5 @@ +var obj: Object; +if (ArrayBuffer.isView(obj)) { + // isView should be a guard that narrows type to ArrayBufferView. + var ab: ArrayBufferView = obj; +} \ No newline at end of file diff --git a/tests/cases/compiler/augmentedTypesClass2.ts b/tests/cases/compiler/augmentedTypesClass2.ts index c6d64e2bf82..b3be1378fb8 100644 --- a/tests/cases/compiler/augmentedTypesClass2.ts +++ b/tests/cases/compiler/augmentedTypesClass2.ts @@ -1,13 +1,13 @@ // Checking class with other things in type space not value space // class then interface -class c11 { // error +class c11 { foo() { return 1; } } -interface c11 { // error +interface c11 { bar(): void; } diff --git a/tests/cases/compiler/augmentedTypesInterface.ts b/tests/cases/compiler/augmentedTypesInterface.ts index 72c85d6619d..7a51a21736f 100644 --- a/tests/cases/compiler/augmentedTypesInterface.ts +++ b/tests/cases/compiler/augmentedTypesInterface.ts @@ -9,11 +9,11 @@ interface i { } // interface then class -interface i2 { // error +interface i2 { foo(): void; } -class i2 { // error +class i2 { bar() { return 1; } diff --git a/tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts b/tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts index e62dc5c7f97..93d69444362 100644 --- a/tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts +++ b/tests/cases/compiler/duplicateIdentifiersAcrossContainerBoundaries.ts @@ -2,7 +2,7 @@ module M { export interface I { } } module M { - export class I { } // error + export class I { } } module M { diff --git a/tests/cases/compiler/es2015modulekind.ts b/tests/cases/compiler/es2015modulekind.ts new file mode 100644 index 00000000000..6e1f584844a --- /dev/null +++ b/tests/cases/compiler/es2015modulekind.ts @@ -0,0 +1,17 @@ +// @target: es2015 +// @sourcemap: false +// @declaration: false +// @module: es2015 + +export default class A +{ + constructor () + { + + } + + public B() + { + return 42; + } +} \ No newline at end of file diff --git a/tests/cases/compiler/es2015modulekindWithES6Target.ts b/tests/cases/compiler/es2015modulekindWithES6Target.ts new file mode 100644 index 00000000000..78809d3835f --- /dev/null +++ b/tests/cases/compiler/es2015modulekindWithES6Target.ts @@ -0,0 +1,17 @@ +// @target: es6 +// @sourcemap: false +// @declaration: false +// @module: es2015 + +export default class A +{ + constructor () + { + + } + + public B() + { + return 42; + } +} \ No newline at end of file diff --git a/tests/cases/compiler/es6modulekindWithES2015Target.ts b/tests/cases/compiler/es6modulekindWithES2015Target.ts new file mode 100644 index 00000000000..aaf79e6607d --- /dev/null +++ b/tests/cases/compiler/es6modulekindWithES2015Target.ts @@ -0,0 +1,17 @@ +// @target: es2015 +// @sourcemap: false +// @declaration: false +// @module: es6 + +export default class A +{ + constructor () + { + + } + + public B() + { + return 42; + } +} \ No newline at end of file diff --git a/tests/cases/compiler/interfaceClassMerging.ts b/tests/cases/compiler/interfaceClassMerging.ts new file mode 100644 index 00000000000..266dc35b1e5 --- /dev/null +++ b/tests/cases/compiler/interfaceClassMerging.ts @@ -0,0 +1,39 @@ +interface Foo { + method(a: number): string; + optionalMethod?(a: number): string; + property: string; + optionalProperty?: string; +} + +class Foo { + additionalProperty: string; + + additionalMethod(a: number): string { + return this.method(0); + } +} + +class Bar extends Foo { + method(a: number) { + return this.optionalProperty; + } +} + + +var bar = new Bar(); +bar.method(0); +bar.optionalMethod(1); +bar.property; +bar.optionalProperty; +bar.additionalProperty; +bar.additionalMethod(2); + +var obj: { + method(a: number): string; + property: string; + additionalProperty: string; + additionalMethod(a: number): string; +}; + +bar = obj; +obj = bar; diff --git a/tests/cases/compiler/interfaceClassMerging2.ts b/tests/cases/compiler/interfaceClassMerging2.ts new file mode 100644 index 00000000000..b214dc1e793 --- /dev/null +++ b/tests/cases/compiler/interfaceClassMerging2.ts @@ -0,0 +1,35 @@ +interface Foo { + interfaceFooMethod(): this; + interfaceFooProperty: this; +} + +class Foo { + classFooProperty: this; + + classFooMethod(): this { + return this; + } +} + + +interface Bar { + interfaceBarMethod(): this; + interfaceBarProperty: this; +} + +class Bar extends Foo { + classBarProperty: this; + + classBarMethod(): this { + return this; + } +} + + +var bar = new Bar(); +bar.interfaceBarMethod().interfaceFooMethod().classBarMethod().classFooMethod(); + + +var foo = new Foo(); + +foo = bar; diff --git a/tests/cases/compiler/moduleMergeConstructor.ts b/tests/cases/compiler/moduleMergeConstructor.ts new file mode 100644 index 00000000000..018dc867df6 --- /dev/null +++ b/tests/cases/compiler/moduleMergeConstructor.ts @@ -0,0 +1,26 @@ +// @module: amd + +// @filename: foo.d.ts +declare module "foo" { + export class Foo { + constructor(); + method1(): any; + } +} + +// @filename: foo-ext.d.ts +declare module "foo" { + export interface Foo { + method2(): any; + } +} + +// @filename: index.ts +import * as foo from "foo"; + +class Test { + bar: foo.Foo; + constructor() { + this.bar = new foo.Foo(); + } +} diff --git a/tests/cases/compiler/nameCollisions.ts b/tests/cases/compiler/nameCollisions.ts index 25b3efae26f..90b2967fa5f 100644 --- a/tests/cases/compiler/nameCollisions.ts +++ b/tests/cases/compiler/nameCollisions.ts @@ -40,8 +40,8 @@ module T { interface fi { } // ok class cli { } - interface cli { } // error + interface cli { } interface cli2 { } - class cli2 { } // error + class cli2 { } } \ No newline at end of file diff --git a/tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts b/tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts index 314c1e2c8f6..27ea77644a6 100644 --- a/tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts +++ b/tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts @@ -1,12 +1,12 @@ class C { foo: string; } -interface C { foo: string; } // error +interface C { foo: string; } module M { class D { bar: string; } - interface D { // error + interface D { bar: string; } } \ No newline at end of file diff --git a/tests/cases/conformance/classes/classDeclarations/mergedClassInterface.ts b/tests/cases/conformance/classes/classDeclarations/mergedClassInterface.ts index 29400c63808..d64a0df3661 100644 --- a/tests/cases/conformance/classes/classDeclarations/mergedClassInterface.ts +++ b/tests/cases/conformance/classes/classDeclarations/mergedClassInterface.ts @@ -10,13 +10,13 @@ interface C2 { } declare class C2 { } -class C3 { } // error -- cannot merge non-ambient class and interface +class C3 { } -interface C3 { } // error -- cannot merge non-ambient class and interface +interface C3 { } -interface C4 { } // error -- cannot merge non-ambient class and interface +interface C4 { } -class C4 { } // error -- cannot merge non-ambient class and interface +class C4 { } interface C5 { x1: number; diff --git a/tests/cases/unittests/cachingInServerLSHost.ts b/tests/cases/unittests/cachingInServerLSHost.ts index ff2da76ba4f..88b44a693b9 100644 --- a/tests/cases/unittests/cachingInServerLSHost.ts +++ b/tests/cases/unittests/cachingInServerLSHost.ts @@ -45,6 +45,11 @@ module ts { return { close: () => { } } + }, + watchDirectory: (path, callback, recursive?) => { + return { + close: () => { } + } } }; }