From e67574446a56bbf5ceb8a3fd8f416ad8ca0c2907 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Wed, 9 Dec 2015 16:21:04 -0800 Subject: [PATCH 01/28] Fix too many watcher instances issue --- src/compiler/sys.ts | 59 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index cd7580119b5..5482e549ebf 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -24,7 +24,7 @@ namespace ts { interface WatchedFile { fileName: string; callback: (fileName: string, removed?: boolean) => void; - mtime: Date; + mtime?: Date; } export interface FileWatcher { @@ -218,7 +218,7 @@ namespace ts { // average async stat takes about 30 microseconds // set chunk size to do 30 files in < 1 millisecond - function createWatchedFileSet(interval = 2500, chunkSize = 30) { + function createPollingWatchedFileSet(interval = 2500, chunkSize = 30) { let watchedFiles: WatchedFile[] = []; let nextFileToCheck = 0; let watchTimer: any; @@ -293,6 +293,50 @@ namespace ts { removeFile: removeFile }; } + + function createWatchedFileSet() { + let watchedDirectories: { [path: string]: FileWatcher } = {}; + let watchedFiles: { [fileName: string]: (fileName: string, removed?: boolean) => void; } = {}; + + function addFile(fileName: string, callback: (fileName: string, removed?: boolean) => void): WatchedFile { + const file: WatchedFile = { fileName, callback }; + let watchedPaths = Object.keys(watchedDirectories); + // Try to find parent paths that are already watched. If found, don't add directory watchers + let watchedParentPaths = watchedPaths.filter(path => fileName.indexOf(path) === 0); + // If adding new watchers, try to find children paths that are already watched. If found, close them. + if (watchedParentPaths.length === 0) { + let pathToWatch = ts.getDirectoryPath(fileName); + for (let watchedPath in watchedDirectories) { + if (watchedPath.indexOf(pathToWatch) === 0) { + watchedDirectories[watchedPath].close(); + delete watchedDirectories[watchedPath]; + } + } + watchedDirectories[pathToWatch] = _fs.watch( + pathToWatch, + (eventName: string, relativeFileName: string) => fileEventHandler(eventName, ts.normalizePath(ts.combinePaths(pathToWatch, relativeFileName))) + ); + } + watchedFiles[fileName] = callback; + return { fileName, callback } + } + + function removeFile(file: WatchedFile) { + delete watchedFiles[file.fileName]; + } + + function fileEventHandler(eventName: string, fileName: string) { + if (watchedFiles[fileName]) { + let callback = watchedFiles[fileName]; + callback(fileName); + } + } + + return { + addFile: addFile, + removeFile: removeFile + } + } // REVIEW: for now this implementation uses polling. // The advantage of polling is that it works reliably @@ -307,6 +351,7 @@ namespace ts { // 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? + const pollingWatchedFileSet = createPollingWatchedFileSet(); const watchedFileSet = createWatchedFileSet(); function isNode4OrLater(): Boolean { @@ -411,14 +456,10 @@ namespace ts { // 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)); - } - - const watchedFile = watchedFileSet.addFile(fileName, callback); + let fileSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet; + const watchedFile = fileSet.addFile(fileName, callback); return { - close: () => watchedFileSet.removeFile(watchedFile) + close: () => fileSet.removeFile(watchedFile) }; }, watchDirectory: (path, callback, recursive) => { From 5fa7bec22688fd81c191abc430ecb7424abf144b Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Thu, 10 Dec 2015 17:52:25 -0800 Subject: [PATCH 02/28] revert back to polling watching for approaching release --- src/compiler/sys.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 5482e549ebf..0cb0258de3f 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -352,7 +352,7 @@ namespace ts { // to increase the chunk size or decrease the interval // time dynamically to match the large reference set? const pollingWatchedFileSet = createPollingWatchedFileSet(); - const watchedFileSet = createWatchedFileSet(); + // const watchedFileSet = createWatchedFileSet(); function isNode4OrLater(): Boolean { return parseInt(process.version.charAt(1)) >= 4; @@ -456,7 +456,8 @@ namespace ts { // 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. - let fileSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet; + // let fileSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet; + let fileSet = pollingWatchedFileSet; const watchedFile = fileSet.addFile(fileName, callback); return { close: () => fileSet.removeFile(watchedFile) From 36cc0e017b7199e87a7bb1d18580f8380fd42107 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Thu, 10 Dec 2015 17:59:07 -0800 Subject: [PATCH 03/28] fix linter errors --- src/compiler/sys.ts | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 0cb0258de3f..cbb7e320780 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -293,49 +293,49 @@ namespace ts { removeFile: removeFile }; } - + function createWatchedFileSet() { - let watchedDirectories: { [path: string]: FileWatcher } = {}; - let watchedFiles: { [fileName: string]: (fileName: string, removed?: boolean) => void; } = {}; - + const watchedDirectories: { [path: string]: FileWatcher } = {}; + const watchedFiles: { [fileName: string]: (fileName: string, removed?: boolean) => void; } = {}; + function addFile(fileName: string, callback: (fileName: string, removed?: boolean) => void): WatchedFile { const file: WatchedFile = { fileName, callback }; - let watchedPaths = Object.keys(watchedDirectories); + const watchedPaths = Object.keys(watchedDirectories); // Try to find parent paths that are already watched. If found, don't add directory watchers - let watchedParentPaths = watchedPaths.filter(path => fileName.indexOf(path) === 0); + const watchedParentPaths = watchedPaths.filter(path => fileName.indexOf(path) === 0); // If adding new watchers, try to find children paths that are already watched. If found, close them. if (watchedParentPaths.length === 0) { - let pathToWatch = ts.getDirectoryPath(fileName); - for (let watchedPath in watchedDirectories) { + const pathToWatch = ts.getDirectoryPath(fileName); + for (const watchedPath in watchedDirectories) { if (watchedPath.indexOf(pathToWatch) === 0) { watchedDirectories[watchedPath].close(); delete watchedDirectories[watchedPath]; } } watchedDirectories[pathToWatch] = _fs.watch( - pathToWatch, + pathToWatch, (eventName: string, relativeFileName: string) => fileEventHandler(eventName, ts.normalizePath(ts.combinePaths(pathToWatch, relativeFileName))) ); } watchedFiles[fileName] = callback; - return { fileName, callback } + return { fileName, callback }; } - + function removeFile(file: WatchedFile) { delete watchedFiles[file.fileName]; } - + function fileEventHandler(eventName: string, fileName: string) { if (watchedFiles[fileName]) { - let callback = watchedFiles[fileName]; + const callback = watchedFiles[fileName]; callback(fileName); } } - + return { addFile: addFile, removeFile: removeFile - } + }; } // REVIEW: for now this implementation uses polling. @@ -456,11 +456,9 @@ namespace ts { // 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. - // let fileSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet; - let fileSet = pollingWatchedFileSet; - const watchedFile = fileSet.addFile(fileName, callback); + const watchedFile = pollingWatchedFileSet.addFile(fileName, callback); return { - close: () => fileSet.removeFile(watchedFile) + close: () => pollingWatchedFileSet.removeFile(watchedFile) }; }, watchDirectory: (path, callback, recursive) => { From d41901576a7c697e79594fc518dfb0fef6ce4b63 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 15 Dec 2015 08:39:51 -0800 Subject: [PATCH 04/28] Use FileMap instead of string array --- src/compiler/sys.ts | 72 ++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index cbb7e320780..91371e62ec8 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -295,47 +295,52 @@ namespace ts { } function createWatchedFileSet() { - const watchedDirectories: { [path: string]: FileWatcher } = {}; - const watchedFiles: { [fileName: string]: (fileName: string, removed?: boolean) => void; } = {}; + const watchedDirectories = createFileMap(); + const watchedFiles = createFileMap<(fileName: string, removed?: boolean) => void>(); + const currentDirectory = process.cwd(); + + return { addFile, removeFile }; function addFile(fileName: string, callback: (fileName: string, removed?: boolean) => void): WatchedFile { - const file: WatchedFile = { fileName, callback }; - const watchedPaths = Object.keys(watchedDirectories); - // Try to find parent paths that are already watched. If found, don't add directory watchers - const watchedParentPaths = watchedPaths.filter(path => fileName.indexOf(path) === 0); - // If adding new watchers, try to find children paths that are already watched. If found, close them. - if (watchedParentPaths.length === 0) { - const pathToWatch = ts.getDirectoryPath(fileName); - for (const watchedPath in watchedDirectories) { - if (watchedPath.indexOf(pathToWatch) === 0) { - watchedDirectories[watchedPath].close(); - delete watchedDirectories[watchedPath]; - } - } - watchedDirectories[pathToWatch] = _fs.watch( - pathToWatch, - (eventName: string, relativeFileName: string) => fileEventHandler(eventName, ts.normalizePath(ts.combinePaths(pathToWatch, relativeFileName))) - ); + const path = toPath(fileName, currentDirectory, getCanonicalPath); + const parentDirPath = toPath(ts.getDirectoryPath(fileName), currentDirectory, getCanonicalPath); + + if (!watchedDirectories.contains(parentDirPath)) { + watchedDirectories.set(parentDirPath, _fs.watch( + parentDirPath, + (eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, parentDirPath) + )); } - watchedFiles[fileName] = callback; + watchedFiles.set(path, callback); return { fileName, callback }; } function removeFile(file: WatchedFile) { - delete watchedFiles[file.fileName]; - } + const path = toPath(file.fileName, currentDirectory, getCanonicalPath); + watchedFiles.remove(path); - function fileEventHandler(eventName: string, fileName: string) { - if (watchedFiles[fileName]) { - const callback = watchedFiles[fileName]; - callback(fileName); + const parentDirPath = toPath(ts.getDirectoryPath(path), currentDirectory, getCanonicalPath); + if (watchedDirectories.contains(parentDirPath)) { + let hasWatchedChildren = false; + watchedFiles.forEachValue((key, _) => { + if (ts.getDirectoryPath(key) === parentDirPath) { + hasWatchedChildren = true; + } + }); + if (!hasWatchedChildren) { + watchedDirectories.get(parentDirPath).close(); + watchedDirectories.remove(parentDirPath); + } } } - return { - addFile: addFile, - removeFile: removeFile - }; + function fileEventHandler(eventName: string, fileName: string, basePath: string) { + const path = ts.toPath(fileName, basePath, getCanonicalPath); + if (watchedFiles.contains(path)) { + const callback = watchedFiles.get(path); + callback(fileName); + } + } } // REVIEW: for now this implementation uses polling. @@ -352,7 +357,7 @@ namespace ts { // to increase the chunk size or decrease the interval // time dynamically to match the large reference set? const pollingWatchedFileSet = createPollingWatchedFileSet(); - // const watchedFileSet = createWatchedFileSet(); + const watchedFileSet = createWatchedFileSet(); function isNode4OrLater(): Boolean { return parseInt(process.version.charAt(1)) >= 4; @@ -456,9 +461,10 @@ namespace ts { // 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. - const watchedFile = pollingWatchedFileSet.addFile(fileName, callback); + const watchSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet; + const watchedFile = watchSet.addFile(fileName, callback); return { - close: () => pollingWatchedFileSet.removeFile(watchedFile) + close: () => watchSet.removeFile(watchedFile) }; }, watchDirectory: (path, callback, recursive) => { From 178b2dabfe7f16824d126fdc6406391faec39f86 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Mon, 21 Dec 2015 16:29:04 -0800 Subject: [PATCH 05/28] Add type alias for filewatching callbacks --- src/compiler/core.ts | 4 +++- src/compiler/sys.ts | 28 +++++++++++++++++----------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index cae7bd82103..4e74029fb5d 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -612,7 +612,9 @@ namespace ts { return path.substr(0, rootLength) + normalized.join(directorySeparator); } - export function getDirectoryPath(path: string) { + export function getDirectoryPath(path: Path): Path; + export function getDirectoryPath(path: string): string; + export function getDirectoryPath(path: string): any { return path.substr(0, Math.max(getRootLength(path), path.lastIndexOf(directorySeparator))); } diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 5794c861670..5d723425496 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -1,6 +1,9 @@ /// namespace ts { + export type CallbackForWatchedFile = (path: string, removed?: boolean) => void; + export type CallbackForWatchedDirectory = (path: string) => void; + export interface System { args: string[]; newLine: string; @@ -8,8 +11,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; - watchDirectory?(path: string, callback: (path: string) => void, recursive?: boolean): FileWatcher; + watchFile?(path: string, callback: CallbackForWatchedFile): FileWatcher; + watchDirectory?(path: string, callback: CallbackForWatchedDirectory, recursive?: boolean): FileWatcher; resolvePath(path: string): string; fileExists(path: string): boolean; directoryExists(path: string): boolean; @@ -23,7 +26,7 @@ namespace ts { interface WatchedFile { fileName: string; - callback: (fileName: string, removed?: boolean) => void; + callback: CallbackForWatchedFile; mtime?: Date; } @@ -62,8 +65,8 @@ namespace ts { readFile(path: string): string; writeFile(path: string, contents: string): void; readDirectory(path: string, extension?: string, exclude?: string[]): string[]; - watchFile?(path: string, callback: (path: string, removed?: boolean) => void): FileWatcher; - watchDirectory?(path: string, callback: (path: string) => void, recursive?: boolean): FileWatcher; + watchFile?(path: string, callback: CallbackForWatchedFile): FileWatcher; + watchDirectory?(path: string, callback: CallbackForWatchedDirectory, recursive?: boolean): FileWatcher; }; export var sys: System = (function () { @@ -271,7 +274,7 @@ namespace ts { }, interval); } - function addFile(fileName: string, callback: (fileName: string, removed?: boolean) => void): WatchedFile { + function addFile(fileName: string, callback: CallbackForWatchedFile): WatchedFile { const file: WatchedFile = { fileName, callback, @@ -298,16 +301,18 @@ namespace ts { }; } + + function createWatchedFileSet() { const watchedDirectories = createFileMap(); - const watchedFiles = createFileMap<(fileName: string, removed?: boolean) => void>(); + const watchedFiles = createFileMap(); const currentDirectory = process.cwd(); return { addFile, removeFile }; - function addFile(fileName: string, callback: (fileName: string, removed?: boolean) => void): WatchedFile { + function addFile(fileName: string, callback: CallbackForWatchedFile): WatchedFile { const path = toPath(fileName, currentDirectory, getCanonicalPath); - const parentDirPath = toPath(ts.getDirectoryPath(fileName), currentDirectory, getCanonicalPath); + const parentDirPath = getDirectoryPath(path); if (!watchedDirectories.contains(parentDirPath)) { watchedDirectories.set(parentDirPath, _fs.watch( @@ -323,7 +328,7 @@ namespace ts { const path = toPath(file.fileName, currentDirectory, getCanonicalPath); watchedFiles.remove(path); - const parentDirPath = toPath(ts.getDirectoryPath(path), currentDirectory, getCanonicalPath); + const parentDirPath = getDirectoryPath(path); if (watchedDirectories.contains(parentDirPath)) { let hasWatchedChildren = false; watchedFiles.forEachValue((key, _) => { @@ -474,9 +479,10 @@ namespace ts { 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) + const options = isNode4OrLater() ? { persistent: true } : { persistent: true, recursive: !!recursive }; return _fs.watch( path, - { persistent: true, recursive: !!recursive }, + options, (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 From caa6eb4204a8aa550e493be405ef5b22ef5eebce Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 22 Dec 2015 15:26:21 -0800 Subject: [PATCH 06/28] Reuse watchers between 'watchDirectory' and 'watchFile' --- src/compiler/sys.ts | 184 +++++++++++++++++++++++++++++--------------- 1 file changed, 122 insertions(+), 62 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 5d723425496..4056ffd9da9 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -1,8 +1,8 @@ /// namespace ts { - export type CallbackForWatchedFile = (path: string, removed?: boolean) => void; - export type CallbackForWatchedDirectory = (path: string) => void; + export type FileWatcherCallback = (path: string, removed?: boolean) => void; + export type DirWatcherCallback = (path: string) => void; export interface System { args: string[]; @@ -11,8 +11,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: CallbackForWatchedFile): FileWatcher; - watchDirectory?(path: string, callback: CallbackForWatchedDirectory, recursive?: boolean): FileWatcher; + watchFile?(path: string, callback: FileWatcherCallback): FileWatcher; + watchDirectory?(path: string, callback: DirWatcherCallback, recursive?: boolean): FileWatcher; resolvePath(path: string): string; fileExists(path: string): boolean; directoryExists(path: string): boolean; @@ -26,13 +26,17 @@ namespace ts { interface WatchedFile { fileName: string; - callback: CallbackForWatchedFile; + callback: FileWatcherCallback; mtime?: Date; } export interface FileWatcher { close(): void; } + + export interface DirWatcher extends FileWatcher { + referenceCount: number; + } declare var require: any; declare var module: any; @@ -65,8 +69,8 @@ namespace ts { readFile(path: string): string; writeFile(path: string, contents: string): void; readDirectory(path: string, extension?: string, exclude?: string[]): string[]; - watchFile?(path: string, callback: CallbackForWatchedFile): FileWatcher; - watchDirectory?(path: string, callback: CallbackForWatchedDirectory, recursive?: boolean): FileWatcher; + watchFile?(path: string, callback: FileWatcherCallback): FileWatcher; + watchDirectory?(path: string, callback: DirWatcherCallback, recursive?: boolean): FileWatcher; }; export var sys: System = (function () { @@ -274,7 +278,7 @@ namespace ts { }, interval); } - function addFile(fileName: string, callback: CallbackForWatchedFile): WatchedFile { + function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile { const file: WatchedFile = { fileName, callback, @@ -301,53 +305,124 @@ namespace ts { }; } - - function createWatchedFileSet() { - const watchedDirectories = createFileMap(); - const watchedFiles = createFileMap(); + const dirWatchers = createFileMap(); + const recursiveDirWatchers = createFileMap(); + const fileWatcherCallbacks = createFileMap(); + const dirWatcherCallbacks = createFileMap(); + const currentDirectory = process.cwd(); + return { addFile, removeFile, addDir }; - return { addFile, removeFile }; - - function addFile(fileName: string, callback: CallbackForWatchedFile): WatchedFile { - const path = toPath(fileName, currentDirectory, getCanonicalPath); - const parentDirPath = getDirectoryPath(path); - - if (!watchedDirectories.contains(parentDirPath)) { - watchedDirectories.set(parentDirPath, _fs.watch( - parentDirPath, - (eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, parentDirPath) - )); + function addDir(dirName: string, callback: DirWatcherCallback, recursive?: boolean) { + const dirPath = toPath(dirName, currentDirectory, getCanonicalPath); + dirWatcherCallbacks.set(dirPath, callback); + const { watcher, isRecursive } = addDirWatcher(dirPath, recursive); + return { + close: () => reduceDirWatcherRefCount(watcher, dirPath, isRecursive) } - watchedFiles.set(path, callback); - return { fileName, callback }; } - - function removeFile(file: WatchedFile) { - const path = toPath(file.fileName, currentDirectory, getCanonicalPath); - watchedFiles.remove(path); - - const parentDirPath = getDirectoryPath(path); - if (watchedDirectories.contains(parentDirPath)) { - let hasWatchedChildren = false; - watchedFiles.forEachValue((key, _) => { - if (ts.getDirectoryPath(key) === parentDirPath) { - hasWatchedChildren = true; - } - }); - if (!hasWatchedChildren) { - watchedDirectories.get(parentDirPath).close(); - watchedDirectories.remove(parentDirPath); + + function reduceDirWatcherRefCount(watcher: DirWatcher, dirPath: Path, isRecursive: boolean) { + watcher.referenceCount -= 1; + if (watcher.referenceCount <= 0) { + watcher.close(); + if (isRecursive) { + recursiveDirWatchers.remove(dirPath); + } else { + dirWatchers.remove(dirPath); } } } - function fileEventHandler(eventName: string, fileName: string, basePath: string) { - const path = ts.toPath(fileName, basePath, getCanonicalPath); - if (watchedFiles.contains(path)) { - const callback = watchedFiles.get(path); - callback(fileName); + function addDirWatcher(dirPath: Path, recursive?: boolean): { watcher: DirWatcher, isRecursive: boolean } { + let watchers: FileMap; + let options: { persistent: boolean, recursive?: boolean } = { persistent: true }; + + // 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) + if (isNode4OrLater() && recursive === true) { + if (recursiveDirWatchers.contains(dirPath)) { + const watcher = recursiveDirWatchers.get(dirPath); + watcher.referenceCount += 1; + return { watcher, isRecursive: true }; + } + watchers = recursiveDirWatchers; + options.recursive = true; + } else { + if (dirWatchers.contains(dirPath)) { + const watcher = dirWatchers.get(dirPath); + watcher.referenceCount += 1; + return { watcher, isRecursive: false }; + } + watchers = dirWatchers; + } + + const watcher: DirWatcher = _fs.watch(dirPath, options, (eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)); + watcher.referenceCount = 1; + watchers.set(dirPath, watcher); + return { watcher, isRecursive: false }; + } + + function findDirWatcherForFile(filePath: Path): { watcher: DirWatcher, watcherPath: Path, isRecursive: boolean } { + let watcher: DirWatcher; + let watcherPath: Path; + let isRecursive = false; + recursiveDirWatchers.forEachValue(dirPath => { + if (filePath.indexOf(dirPath) === 0) { + watcherPath = dirPath; + watcher = recursiveDirWatchers.get(dirPath); + isRecursive = true; + return; + } + }); + if (!watcher) { + const parentDirPath = getDirectoryPath(filePath); + if (dirWatchers.contains(parentDirPath)) { + watcherPath = parentDirPath; + watcher = dirWatchers.get(parentDirPath); + } + } + return { watcher, watcherPath, isRecursive }; + } + + function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile { + const filePath = toPath(fileName, currentDirectory, getCanonicalPath); + const { watcher } = findDirWatcherForFile(filePath); + if (!watcher) { + addDirWatcher(getDirectoryPath(filePath)); + } else { + watcher.referenceCount += 1; + } + fileWatcherCallbacks.set(filePath, callback); + return { fileName, callback }; + } + + function removeFile(file: WatchedFile) { + const filePath = toPath(file.fileName, currentDirectory, getCanonicalPath); + fileWatcherCallbacks.remove(filePath); + + const { watcher, watcherPath, isRecursive } = findDirWatcherForFile(filePath); + if (watcher) { + reduceDirWatcherRefCount(watcher, watcherPath, isRecursive); + } + } + + /** + * @param watcherPath is the path from which the watcher is triggered. + */ + function fileEventHandler(eventName: string, relativefileName: string, baseDirPath: Path) { + // When files are deleted from disk, the triggered "rename" event would have a relativefileName of "undefined" + const filePath = relativefileName === undefined ? undefined : toPath(relativefileName, baseDirPath, getCanonicalPath); + // Directory callbacks are not set for file content changes, they are more often used for + // adding/removing/renaming files, which corresponds to the "rename" event + if (eventName === "rename" && dirWatcherCallbacks.contains(baseDirPath)) { + const dirCallback = dirWatcherCallbacks.get(baseDirPath); + dirCallback(filePath); + } + if (fileWatcherCallbacks.contains(filePath)) { + const fileCallback = fileWatcherCallbacks.get(filePath); + fileCallback(filePath); } } } @@ -477,22 +552,7 @@ namespace ts { }; }, 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) - const options = isNode4OrLater() ? { persistent: true } : { persistent: true, recursive: !!recursive }; - return _fs.watch( - path, - options, - (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))); - }; - } - ); + return watchedFileSet.addDir(path, callback, recursive); }, resolvePath: function (path: string): string { return _path.resolve(path); From 631363fee19414f4d4cb136f8bf85e8aa061561e Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 22 Dec 2015 15:38:52 -0800 Subject: [PATCH 07/28] Fix lint issues --- src/compiler/sys.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 4056ffd9da9..afac095a56e 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -33,7 +33,7 @@ namespace ts { export interface FileWatcher { close(): void; } - + export interface DirWatcher extends FileWatcher { referenceCount: number; } @@ -320,16 +320,17 @@ namespace ts { const { watcher, isRecursive } = addDirWatcher(dirPath, recursive); return { close: () => reduceDirWatcherRefCount(watcher, dirPath, isRecursive) - } + }; } - + function reduceDirWatcherRefCount(watcher: DirWatcher, dirPath: Path, isRecursive: boolean) { watcher.referenceCount -= 1; if (watcher.referenceCount <= 0) { watcher.close(); if (isRecursive) { recursiveDirWatchers.remove(dirPath); - } else { + } + else { dirWatchers.remove(dirPath); } } @@ -337,19 +338,20 @@ namespace ts { function addDirWatcher(dirPath: Path, recursive?: boolean): { watcher: DirWatcher, isRecursive: boolean } { let watchers: FileMap; - let options: { persistent: boolean, recursive?: boolean } = { persistent: true }; + const options: { persistent: boolean, recursive?: boolean } = { persistent: true }; // 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) if (isNode4OrLater() && recursive === true) { if (recursiveDirWatchers.contains(dirPath)) { - const watcher = recursiveDirWatchers.get(dirPath); + const watcher = recursiveDirWatchers.get(dirPath); watcher.referenceCount += 1; return { watcher, isRecursive: true }; } watchers = recursiveDirWatchers; options.recursive = true; - } else { + } + else { if (dirWatchers.contains(dirPath)) { const watcher = dirWatchers.get(dirPath); watcher.referenceCount += 1; @@ -391,7 +393,8 @@ namespace ts { const { watcher } = findDirWatcherForFile(filePath); if (!watcher) { addDirWatcher(getDirectoryPath(filePath)); - } else { + } + else { watcher.referenceCount += 1; } fileWatcherCallbacks.set(filePath, callback); From 8cf1a34f70c76161adc623f835ad7e04b3026e04 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Mon, 28 Dec 2015 14:05:32 -0800 Subject: [PATCH 08/28] enable more than one callbacks for a watched file --- src/compiler/sys.ts | 61 +++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 62baf28f074..a9056756f01 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -307,15 +307,21 @@ namespace ts { function createWatchedFileSet() { const dirWatchers = createFileMap(); const recursiveDirWatchers = createFileMap(); - const fileWatcherCallbacks = createFileMap(); - const dirWatcherCallbacks = createFileMap(); + // One file can have multiple watchers + const fileWatcherCallbacks = createFileMap(); + const dirWatcherCallbacks = createFileMap(); const currentDirectory = process.cwd(); return { addFile, removeFile, addDir }; function addDir(dirName: string, callback: DirWatcherCallback, recursive?: boolean) { const dirPath = toPath(dirName, currentDirectory, getCanonicalPath); - dirWatcherCallbacks.set(dirPath, callback); + if (!dirWatcherCallbacks.contains(dirPath)) { + dirWatcherCallbacks.set(dirPath, [callback]); + } + else { + dirWatcherCallbacks.get(dirPath).push(callback); + } const { watcher, isRecursive } = addDirWatcher(dirPath, recursive); return { close: () => reduceDirWatcherRefCount(watcher, dirPath, isRecursive) @@ -341,7 +347,8 @@ namespace ts { // 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) - if (isNode4OrLater() && recursive === true) { + if (isNode4OrLater() && recursive === true && + (process.platform === "win32" || process.platform === "darwin")) { if (recursiveDirWatchers.contains(dirPath)) { const watcher = recursiveDirWatchers.get(dirPath); watcher.referenceCount += 1; @@ -357,12 +364,13 @@ namespace ts { return { watcher, isRecursive: false }; } watchers = dirWatchers; + options.recursive = false; } const watcher: DirWatcher = _fs.watch(dirPath, options, (eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)); watcher.referenceCount = 1; watchers.set(dirPath, watcher); - return { watcher, isRecursive: false }; + return { watcher, isRecursive: options.recursive }; } function findDirWatcherForFile(filePath: Path): { watcher: DirWatcher, watcherPath: Path, isRecursive: boolean } { @@ -389,24 +397,37 @@ namespace ts { function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile { const filePath = toPath(fileName, currentDirectory, getCanonicalPath); - const { watcher } = findDirWatcherForFile(filePath); - if (!watcher) { - addDirWatcher(getDirectoryPath(filePath)); + + if (fileWatcherCallbacks.contains(filePath)) { + fileWatcherCallbacks.get(filePath).push(callback); } else { - watcher.referenceCount += 1; + const { watcher } = findDirWatcherForFile(filePath); + if (!watcher) { + addDirWatcher(getDirectoryPath(filePath)); + } + else { + watcher.referenceCount += 1; + } + fileWatcherCallbacks.set(filePath, [callback]); } - fileWatcherCallbacks.set(filePath, callback); return { fileName, callback }; } function removeFile(file: WatchedFile) { const filePath = toPath(file.fileName, currentDirectory, getCanonicalPath); - fileWatcherCallbacks.remove(filePath); - - const { watcher, watcherPath, isRecursive } = findDirWatcherForFile(filePath); - if (watcher) { - reduceDirWatcherRefCount(watcher, watcherPath, isRecursive); + if (fileWatcherCallbacks.contains(filePath)) { + const newCallbacks = copyListRemovingItem(file.callback, fileWatcherCallbacks.get(filePath)); + if (newCallbacks.length === 0) { + fileWatcherCallbacks.remove(filePath); + const { watcher, watcherPath, isRecursive } = findDirWatcherForFile(filePath); + if (watcher) { + reduceDirWatcherRefCount(watcher, watcherPath, isRecursive); + } + } + else { + fileWatcherCallbacks.set(filePath, newCallbacks); + } } } @@ -419,12 +440,14 @@ namespace ts { // Directory callbacks are not set for file content changes, they are more often used for // adding/removing/renaming files, which corresponds to the "rename" event if (eventName === "rename" && dirWatcherCallbacks.contains(baseDirPath)) { - const dirCallback = dirWatcherCallbacks.get(baseDirPath); - dirCallback(filePath); + for (const dirCallback of dirWatcherCallbacks.get(baseDirPath)) { + dirCallback(filePath); + } } if (fileWatcherCallbacks.contains(filePath)) { - const fileCallback = fileWatcherCallbacks.get(filePath); - fileCallback(filePath); + for (const fileCallback of fileWatcherCallbacks.get(filePath)) { + fileCallback(filePath); + } } } } From 697644c583aec713927241f20d8fda17a2aefaa8 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Thu, 7 Jan 2016 22:48:17 -0800 Subject: [PATCH 09/28] spell our dir to directory --- src/compiler/sys.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index a9056756f01..a99f491175c 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -2,7 +2,7 @@ namespace ts { export type FileWatcherCallback = (path: string, removed?: boolean) => void; - export type DirWatcherCallback = (path: string) => void; + export type DirectoryWatcherCallback = (path: string) => void; export interface System { args: string[]; @@ -12,7 +12,7 @@ namespace ts { readFile(path: string, encoding?: string): string; writeFile(path: string, data: string, writeByteOrderMark?: boolean): void; watchFile?(path: string, callback: FileWatcherCallback): FileWatcher; - watchDirectory?(path: string, callback: DirWatcherCallback, recursive?: boolean): FileWatcher; + watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher; resolvePath(path: string): string; fileExists(path: string): boolean; directoryExists(path: string): boolean; @@ -34,7 +34,7 @@ namespace ts { close(): void; } - export interface DirWatcher extends FileWatcher { + export interface DirectoryWatcher extends FileWatcher { referenceCount: number; } @@ -70,7 +70,7 @@ namespace ts { writeFile(path: string, contents: string): void; readDirectory(path: string, extension?: string, exclude?: string[]): string[]; watchFile?(path: string, callback: FileWatcherCallback): FileWatcher; - watchDirectory?(path: string, callback: DirWatcherCallback, recursive?: boolean): FileWatcher; + watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher; }; export var sys: System = (function () { @@ -305,16 +305,16 @@ namespace ts { } function createWatchedFileSet() { - const dirWatchers = createFileMap(); - const recursiveDirWatchers = createFileMap(); + const dirWatchers = createFileMap(); + const recursiveDirWatchers = createFileMap(); // One file can have multiple watchers const fileWatcherCallbacks = createFileMap(); - const dirWatcherCallbacks = createFileMap(); + const dirWatcherCallbacks = createFileMap(); const currentDirectory = process.cwd(); return { addFile, removeFile, addDir }; - function addDir(dirName: string, callback: DirWatcherCallback, recursive?: boolean) { + function addDir(dirName: string, callback: DirectoryWatcherCallback, recursive?: boolean) { const dirPath = toPath(dirName, currentDirectory, getCanonicalPath); if (!dirWatcherCallbacks.contains(dirPath)) { dirWatcherCallbacks.set(dirPath, [callback]); @@ -328,7 +328,7 @@ namespace ts { }; } - function reduceDirWatcherRefCount(watcher: DirWatcher, dirPath: Path, isRecursive: boolean) { + function reduceDirWatcherRefCount(watcher: DirectoryWatcher, dirPath: Path, isRecursive: boolean) { watcher.referenceCount -= 1; if (watcher.referenceCount <= 0) { watcher.close(); @@ -341,8 +341,8 @@ namespace ts { } } - function addDirWatcher(dirPath: Path, recursive?: boolean): { watcher: DirWatcher, isRecursive: boolean } { - let watchers: FileMap; + function addDirWatcher(dirPath: Path, recursive?: boolean): { watcher: DirectoryWatcher, isRecursive: boolean } { + let watchers: FileMap; const options: { persistent: boolean, recursive?: boolean } = { persistent: true }; // Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows @@ -367,14 +367,14 @@ namespace ts { options.recursive = false; } - const watcher: DirWatcher = _fs.watch(dirPath, options, (eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)); + const watcher: DirectoryWatcher = _fs.watch(dirPath, options, (eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)); watcher.referenceCount = 1; watchers.set(dirPath, watcher); return { watcher, isRecursive: options.recursive }; } - function findDirWatcherForFile(filePath: Path): { watcher: DirWatcher, watcherPath: Path, isRecursive: boolean } { - let watcher: DirWatcher; + function findDirWatcherForFile(filePath: Path): { watcher: DirectoryWatcher, watcherPath: Path, isRecursive: boolean } { + let watcher: DirectoryWatcher; let watcherPath: Path; let isRecursive = false; recursiveDirWatchers.forEachValue(dirPath => { From 114d2bd66d849db3aff2ec3401f6a68805fafa8d Mon Sep 17 00:00:00 2001 From: zhengbli Date: Mon, 11 Jan 2016 11:35:46 -0800 Subject: [PATCH 10/28] Separate directory watching and file watching again to reduce logic complexity, because reference counting is a lot easier in this case --- src/compiler/sys.ts | 164 +++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 101 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index a99f491175c..de56beb8697 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -35,6 +35,7 @@ namespace ts { } export interface DirectoryWatcher extends FileWatcher { + directoryPath: Path; referenceCount: number; } @@ -306,123 +307,71 @@ namespace ts { function createWatchedFileSet() { const dirWatchers = createFileMap(); - const recursiveDirWatchers = createFileMap(); // One file can have multiple watchers const fileWatcherCallbacks = createFileMap(); - const dirWatcherCallbacks = createFileMap(); - const currentDirectory = process.cwd(); - return { addFile, removeFile, addDir }; + return { addFile, removeFile }; - function addDir(dirName: string, callback: DirectoryWatcherCallback, recursive?: boolean) { - const dirPath = toPath(dirName, currentDirectory, getCanonicalPath); - if (!dirWatcherCallbacks.contains(dirPath)) { - dirWatcherCallbacks.set(dirPath, [callback]); - } - else { - dirWatcherCallbacks.get(dirPath).push(callback); - } - const { watcher, isRecursive } = addDirWatcher(dirPath, recursive); - return { - close: () => reduceDirWatcherRefCount(watcher, dirPath, isRecursive) - }; - } - - function reduceDirWatcherRefCount(watcher: DirectoryWatcher, dirPath: Path, isRecursive: boolean) { + function reduceDirWatcherRefCount(dirPath: Path) { + const watcher = dirWatchers.get(dirPath); watcher.referenceCount -= 1; if (watcher.referenceCount <= 0) { watcher.close(); - if (isRecursive) { - recursiveDirWatchers.remove(dirPath); - } - else { - dirWatchers.remove(dirPath); - } + dirWatchers.remove(dirPath); } } - function addDirWatcher(dirPath: Path, recursive?: boolean): { watcher: DirectoryWatcher, isRecursive: boolean } { - let watchers: FileMap; - const options: { persistent: boolean, recursive?: boolean } = { persistent: true }; - - // 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) - if (isNode4OrLater() && recursive === true && - (process.platform === "win32" || process.platform === "darwin")) { - if (recursiveDirWatchers.contains(dirPath)) { - const watcher = recursiveDirWatchers.get(dirPath); - watcher.referenceCount += 1; - return { watcher, isRecursive: true }; - } - watchers = recursiveDirWatchers; - options.recursive = true; - } - else { - if (dirWatchers.contains(dirPath)) { - const watcher = dirWatchers.get(dirPath); - watcher.referenceCount += 1; - return { watcher, isRecursive: false }; - } - watchers = dirWatchers; - options.recursive = false; + function addDirWatcher(dirPath: Path): void { + if (dirWatchers.contains(dirPath)) { + const watcher = dirWatchers.get(dirPath); + watcher.referenceCount += 1; + return; } - const watcher: DirectoryWatcher = _fs.watch(dirPath, options, (eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)); + const watcher: DirectoryWatcher = _fs.watch( + dirPath, + { persistent: true }, + (eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath) + ); watcher.referenceCount = 1; - watchers.set(dirPath, watcher); - return { watcher, isRecursive: options.recursive }; + dirWatchers.set(dirPath, watcher); + return; } - function findDirWatcherForFile(filePath: Path): { watcher: DirectoryWatcher, watcherPath: Path, isRecursive: boolean } { - let watcher: DirectoryWatcher; - let watcherPath: Path; - let isRecursive = false; - recursiveDirWatchers.forEachValue(dirPath => { - if (filePath.indexOf(dirPath) === 0) { - watcherPath = dirPath; - watcher = recursiveDirWatchers.get(dirPath); - isRecursive = true; - return; - } - }); - if (!watcher) { - const parentDirPath = getDirectoryPath(filePath); - if (dirWatchers.contains(parentDirPath)) { - watcherPath = parentDirPath; - watcher = dirWatchers.get(parentDirPath); - } - } - return { watcher, watcherPath, isRecursive }; - } - - function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile { - const filePath = toPath(fileName, currentDirectory, getCanonicalPath); - + function addFileWatcherCallback(filePath: Path, callback: FileWatcherCallback): void { if (fileWatcherCallbacks.contains(filePath)) { fileWatcherCallbacks.get(filePath).push(callback); } else { - const { watcher } = findDirWatcherForFile(filePath); - if (!watcher) { - addDirWatcher(getDirectoryPath(filePath)); - } - else { - watcher.referenceCount += 1; - } fileWatcherCallbacks.set(filePath, [callback]); } + } + + function findWatchedDirForFile(filePath: Path): Path { + const dirPath = getDirectoryPath(filePath); + if (dirWatchers.contains(dirPath)) { + return dirPath; + } + return undefined; + } + + function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile { + const filePath = toPath(fileName, currentDirectory, getCanonicalPath); + addFileWatcherCallback(filePath, callback); + addDirWatcher(getDirectoryPath(filePath)); + return { fileName, callback }; } - function removeFile(file: WatchedFile) { - const filePath = toPath(file.fileName, currentDirectory, getCanonicalPath); + function removeFile(watchedFile: WatchedFile) { + const filePath = toPath(watchedFile.fileName, currentDirectory, getCanonicalPath); if (fileWatcherCallbacks.contains(filePath)) { - const newCallbacks = copyListRemovingItem(file.callback, fileWatcherCallbacks.get(filePath)); + const newCallbacks = copyListRemovingItem(watchedFile.callback, fileWatcherCallbacks.get(filePath)); if (newCallbacks.length === 0) { fileWatcherCallbacks.remove(filePath); - const { watcher, watcherPath, isRecursive } = findDirWatcherForFile(filePath); - if (watcher) { - reduceDirWatcherRefCount(watcher, watcherPath, isRecursive); + const watchedDir = findWatchedDirForFile(filePath); + if (watchedDir) { + reduceDirWatcherRefCount(watchedDir); } } else { @@ -437,14 +386,7 @@ namespace ts { function fileEventHandler(eventName: string, relativefileName: string, baseDirPath: Path) { // When files are deleted from disk, the triggered "rename" event would have a relativefileName of "undefined" const filePath = relativefileName === undefined ? undefined : toPath(relativefileName, baseDirPath, getCanonicalPath); - // Directory callbacks are not set for file content changes, they are more often used for - // adding/removing/renaming files, which corresponds to the "rename" event - if (eventName === "rename" && dirWatcherCallbacks.contains(baseDirPath)) { - for (const dirCallback of dirWatcherCallbacks.get(baseDirPath)) { - dirCallback(filePath); - } - } - if (fileWatcherCallbacks.contains(filePath)) { + if (eventName === "change" && fileWatcherCallbacks.contains(filePath)) { for (const fileCallback of fileWatcherCallbacks.get(filePath)) { fileCallback(filePath); } @@ -577,7 +519,29 @@ namespace ts { }; }, watchDirectory: (path, callback, recursive) => { - return watchedFileSet.addDir(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) + let options: any; + if (isNode4OrLater() && (process.platform === "win32" || process.platform === "darwin")) { + options = { persistent: true, recursive: !!recursive }; + } + else { + options = { persistent: true }; + } + + return _fs.watch( + path, + options, + (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(combinePaths(path, relativeFileName))); + }; + } + ); }, resolvePath: function (path: string): string { return _path.resolve(path); @@ -658,5 +622,3 @@ namespace ts { } })(); } - - From d22626f32db719801256cac2f888b0cb9c0f150a Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 12 Jan 2016 00:17:38 -0800 Subject: [PATCH 11/28] Fix lint issue --- src/compiler/sys.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index de56beb8697..f40de0bd65e 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -329,8 +329,8 @@ namespace ts { } const watcher: DirectoryWatcher = _fs.watch( - dirPath, - { persistent: true }, + dirPath, + { persistent: true }, (eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath) ); watcher.referenceCount = 1; From 5ba47eca864ca2493d1dd902095e8ce2fc9fec8a Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Wed, 13 Jan 2016 20:18:51 +0200 Subject: [PATCH 12/28] added two new more specific messages --- src/compiler/diagnosticMessages.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 28b10dd73b4..7f1c195ae20 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1775,6 +1775,14 @@ "category": "Error", "code": 2661 }, + "Cannot find name '{0}'. Did you mean to prefix the static member with the class name, '{1}.{0}'?": { + "category": "Error", + "code": 2662 + }, + "Cannot find name '{0}'. Did you mean to prefix the object member with 'this', 'this.{0}'?": { + "category": "Error", + "code": 2663 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", "code": 4000 From 6b7b9aaa5608f1c40c6dbe1daf4365caa58c0aff Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Wed, 13 Jan 2016 20:20:34 +0200 Subject: [PATCH 13/28] added check for missing prefix --- src/compiler/checker.ts | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4c1ef08ddd6..fdce825e292 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -740,7 +740,9 @@ namespace ts { if (!result) { if (nameNotFoundMessage) { - error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg)); + if (!checkForMissingPrefix(errorLocation, name, nameArg)) { + error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg)); + } } return undefined; } @@ -777,6 +779,39 @@ namespace ts { return result; } + function checkForMissingPrefix(errorLocation: Node, name: string, nameArg: string | Identifier): boolean { + if (!errorLocation || (errorLocation.kind === SyntaxKind.Identifier && (isTypeReferenceIdentifier(errorLocation)) || isInTypeQuery(errorLocation))) { + return false; + } + const container = getThisContainer(errorLocation, /* includeArrowFunctions */ true); + let location = container; + while (location) { + if (isClassLike(location.parent)) { + const symbol = getSymbolOfNode(location.parent); + let classType: Type; + if (location.flags & NodeFlags.Static) { + classType = getTypeOfSymbol(symbol); + if (getPropertyOfType(classType, name)) { + error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_to_prefix_the_static_member_with_the_class_name_1_0, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg), symbolToString(symbol)); + return true; + } + } + else { + if (location === container) { + classType = (getDeclaredTypeOfSymbol(symbol)).thisType; + if (getPropertyOfType(classType, name)) { + error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_to_prefix_the_object_member_with_this_this_0, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg)); + return true; + } + } + } + } + + location = location.parent; + } + return false; + } + function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void { Debug.assert((result.flags & SymbolFlags.BlockScopedVariable) !== 0); // Block-scoped variables cannot be used before their definition From 7f8dd6bb7459ae9959ccdf94889ccab66cf893f5 Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Wed, 13 Jan 2016 20:20:58 +0200 Subject: [PATCH 14/28] fixed initializerReferencingConstructorParameters test --- ...initializerReferencingConstructorParameters.errors.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/initializerReferencingConstructorParameters.errors.txt b/tests/baselines/reference/initializerReferencingConstructorParameters.errors.txt index 623bd535745..03e4e83e409 100644 --- a/tests/baselines/reference/initializerReferencingConstructorParameters.errors.txt +++ b/tests/baselines/reference/initializerReferencingConstructorParameters.errors.txt @@ -1,9 +1,9 @@ tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(4,9): error TS2304: Cannot find name 'x'. tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(5,15): error TS2304: Cannot find name 'x'. -tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(10,9): error TS2304: Cannot find name 'x'. +tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(10,9): error TS2663: Cannot find name 'x'. Did you mean to prefix the object member with 'this', 'this.x'? tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(11,15): error TS2304: Cannot find name 'x'. tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(17,15): error TS1003: Identifier expected. -tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(23,9): error TS2304: Cannot find name 'x'. +tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(23,9): error TS2663: Cannot find name 'x'. Did you mean to prefix the object member with 'this', 'this.x'? ==== tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts (6 errors) ==== @@ -22,7 +22,7 @@ tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencin class D { a = x; // error ~ -!!! error TS2304: Cannot find name 'x'. +!!! error TS2663: Cannot find name 'x'. Did you mean to prefix the object member with 'this', 'this.x'? b: typeof x; // error ~ !!! error TS2304: Cannot find name 'x'. @@ -41,6 +41,6 @@ tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencin a = this.x; // ok b = x; // error ~ -!!! error TS2304: Cannot find name 'x'. +!!! error TS2663: Cannot find name 'x'. Did you mean to prefix the object member with 'this', 'this.x'? constructor(public x: T) { } } \ No newline at end of file From 2ef9f69a7ec011ff4137d5efdcabd063dd63a521 Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Wed, 13 Jan 2016 20:21:15 +0200 Subject: [PATCH 15/28] fixed YieldExpression11_es6 test --- tests/baselines/reference/YieldExpression11_es6.errors.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/YieldExpression11_es6.errors.txt b/tests/baselines/reference/YieldExpression11_es6.errors.txt index c19e8b6cfa5..4a2f93a9c6d 100644 --- a/tests/baselines/reference/YieldExpression11_es6.errors.txt +++ b/tests/baselines/reference/YieldExpression11_es6.errors.txt @@ -1,5 +1,5 @@ tests/cases/conformance/es6/yieldExpressions/YieldExpression11_es6.ts(2,3): error TS1220: Generators are only available when targeting ECMAScript 6 or higher. -tests/cases/conformance/es6/yieldExpressions/YieldExpression11_es6.ts(3,11): error TS2304: Cannot find name 'foo'. +tests/cases/conformance/es6/yieldExpressions/YieldExpression11_es6.ts(3,11): error TS2663: Cannot find name 'foo'. Did you mean to prefix the object member with 'this', 'this.foo'? ==== tests/cases/conformance/es6/yieldExpressions/YieldExpression11_es6.ts (2 errors) ==== @@ -9,6 +9,6 @@ tests/cases/conformance/es6/yieldExpressions/YieldExpression11_es6.ts(3,11): err !!! error TS1220: Generators are only available when targeting ECMAScript 6 or higher. yield(foo); ~~~ -!!! error TS2304: Cannot find name 'foo'. +!!! error TS2663: Cannot find name 'foo'. Did you mean to prefix the object member with 'this', 'this.foo'? } } \ No newline at end of file From fe39e0c838a2db0bcc2881be2084a0b8bbca5e51 Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Wed, 13 Jan 2016 20:22:31 +0200 Subject: [PATCH 16/28] fixed parserharness test --- .../reference/parserharness.errors.txt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/baselines/reference/parserharness.errors.txt b/tests/baselines/reference/parserharness.errors.txt index 66afa3d010f..711d3fd9aac 100644 --- a/tests/baselines/reference/parserharness.errors.txt +++ b/tests/baselines/reference/parserharness.errors.txt @@ -7,11 +7,11 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(25,17): er tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(41,12): error TS2304: Cannot find name 'ActiveXObject'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(43,19): error TS2304: Cannot find name 'require'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(44,14): error TS2304: Cannot find name 'require'. -tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(341,13): error TS2304: Cannot find name 'errorHandlerStack'. -tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(347,13): error TS2304: Cannot find name 'errorHandlerStack'. -tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(351,17): error TS2304: Cannot find name 'errorHandlerStack'. -tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(354,17): error TS2304: Cannot find name 'errorHandlerStack'. -tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(354,35): error TS2304: Cannot find name 'errorHandlerStack'. +tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(341,13): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? +tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(347,13): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? +tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(351,17): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? +tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(354,17): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? +tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(354,35): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(691,50): error TS2304: Cannot find name 'ITextWriter'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(716,47): error TS2503: Cannot find namespace 'TypeScript'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(721,62): error TS2304: Cannot find name 'ITextWriter'. @@ -471,7 +471,7 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(2030,32): static pushGlobalErrorHandler(done: IDone) { errorHandlerStack.push(function (e) { ~~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'errorHandlerStack'. +!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? done(e); }); } @@ -479,20 +479,20 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(2030,32): static popGlobalErrorHandler() { errorHandlerStack.pop(); ~~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'errorHandlerStack'. +!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? } static handleError(e: Error) { if (errorHandlerStack.length === 0) { ~~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'errorHandlerStack'. +!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? IO.printLine('Global error: ' + e); } else { errorHandlerStack[errorHandlerStack.length - 1](e); ~~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'errorHandlerStack'. +!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? ~~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'errorHandlerStack'. +!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? } } } From 217b0d48b24ef9a6cc2b15878ffcd7183bd159a4 Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Wed, 13 Jan 2016 20:24:10 +0200 Subject: [PATCH 17/28] fixed parserindenter test --- tests/baselines/reference/parserindenter.errors.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/parserindenter.errors.txt b/tests/baselines/reference/parserindenter.errors.txt index a332abab7bb..d892f27579f 100644 --- a/tests/baselines/reference/parserindenter.errors.txt +++ b/tests/baselines/reference/parserindenter.errors.txt @@ -28,7 +28,7 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(152,63): tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(153,30): error TS2304: Cannot find name 'List_TextEditInfo'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(155,32): error TS2304: Cannot find name 'AuthorTokenKind'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(182,79): error TS2503: Cannot find namespace 'Services'. -tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(183,20): error TS2304: Cannot find name 'GetIndentSizeFromText'. +tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(183,20): error TS2662: Cannot find name 'GetIndentSizeFromText'. Did you mean to prefix the static member with the class name, 'Indenter.GetIndentSizeFromText'? tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(186,67): error TS2503: Cannot find namespace 'Services'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(207,50): error TS2304: Cannot find name 'TokenSpan'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(207,67): error TS2304: Cannot find name 'ParseNode'. @@ -373,7 +373,7 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(736,38): !!! error TS2503: Cannot find namespace 'Services'. return GetIndentSizeFromText(indentText, editorOptions, /*includeNonIndentChars:*/ false); ~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'GetIndentSizeFromText'. +!!! error TS2662: Cannot find name 'GetIndentSizeFromText'. Did you mean to prefix the static member with the class name, 'Indenter.GetIndentSizeFromText'? } static GetIndentSizeFromText(text: string, editorOptions: Services.EditorOptions, includeNonIndentChars: boolean): number { From 00a46cc3928d756186fb6250176bf9bcb6d70a73 Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Wed, 13 Jan 2016 20:24:59 +0200 Subject: [PATCH 18/28] fixed scannertest1 test --- tests/baselines/reference/scannertest1.errors.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/baselines/reference/scannertest1.errors.txt b/tests/baselines/reference/scannertest1.errors.txt index 14a19b28851..234923b5a2f 100644 --- a/tests/baselines/reference/scannertest1.errors.txt +++ b/tests/baselines/reference/scannertest1.errors.txt @@ -1,14 +1,14 @@ tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(1,1): error TS6053: File 'tests/cases/conformance/scanner/ecmascript5/References.ts' not found. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(5,21): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(5,47): error TS2304: Cannot find name 'CharacterCodes'. -tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(9,16): error TS2304: Cannot find name 'isDecimalDigit'. +tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(9,16): error TS2662: Cannot find name 'isDecimalDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isDecimalDigit'? tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(10,22): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(10,47): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(11,22): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(11,47): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(15,9): error TS2304: Cannot find name 'Debug'. -tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(15,22): error TS2304: Cannot find name 'isHexDigit'. -tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(16,16): error TS2304: Cannot find name 'isDecimalDigit'. +tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(15,22): error TS2662: Cannot find name 'isHexDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isHexDigit'? +tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(16,16): error TS2662: Cannot find name 'isDecimalDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isDecimalDigit'? tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(17,20): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(18,21): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(18,46): error TS2304: Cannot find name 'CharacterCodes'. @@ -33,7 +33,7 @@ tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(20,23): error TS2304 public static isHexDigit(c: number): boolean { return isDecimalDigit(c) || ~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'isDecimalDigit'. +!!! error TS2662: Cannot find name 'isDecimalDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isDecimalDigit'? (c >= CharacterCodes.A && c <= CharacterCodes.F) || ~~~~~~~~~~~~~~ !!! error TS2304: Cannot find name 'CharacterCodes'. @@ -51,10 +51,10 @@ tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(20,23): error TS2304 ~~~~~ !!! error TS2304: Cannot find name 'Debug'. ~~~~~~~~~~ -!!! error TS2304: Cannot find name 'isHexDigit'. +!!! error TS2662: Cannot find name 'isHexDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isHexDigit'? return isDecimalDigit(c) ~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'isDecimalDigit'. +!!! error TS2662: Cannot find name 'isDecimalDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isDecimalDigit'? ? (c - CharacterCodes._0) ~~~~~~~~~~~~~~ !!! error TS2304: Cannot find name 'CharacterCodes'. From 90ec38affc014e6245578c654788d016b5ec46b5 Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Wed, 13 Jan 2016 20:26:32 +0200 Subject: [PATCH 19/28] fixed recursiveClassReferenceTest test --- .../reference/recursiveClassReferenceTest.errors.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/recursiveClassReferenceTest.errors.txt b/tests/baselines/reference/recursiveClassReferenceTest.errors.txt index 088d7222f48..76563a19b5a 100644 --- a/tests/baselines/reference/recursiveClassReferenceTest.errors.txt +++ b/tests/baselines/reference/recursiveClassReferenceTest.errors.txt @@ -1,6 +1,6 @@ tests/cases/compiler/recursiveClassReferenceTest.ts(16,19): error TS2304: Cannot find name 'Element'. -tests/cases/compiler/recursiveClassReferenceTest.ts(56,11): error TS2304: Cannot find name 'domNode'. -tests/cases/compiler/recursiveClassReferenceTest.ts(88,36): error TS2304: Cannot find name 'mode'. +tests/cases/compiler/recursiveClassReferenceTest.ts(56,11): error TS2663: Cannot find name 'domNode'. Did you mean to prefix the object member with 'this', 'this.domNode'? +tests/cases/compiler/recursiveClassReferenceTest.ts(88,36): error TS2663: Cannot find name 'mode'. Did you mean to prefix the object member with 'this', 'this.mode'? tests/cases/compiler/recursiveClassReferenceTest.ts(95,21): error TS2345: Argument of type 'Window' is not assignable to parameter of type 'IMode'. Property 'getInitialState' is missing in type 'Window'. @@ -65,7 +65,7 @@ tests/cases/compiler/recursiveClassReferenceTest.ts(95,21): error TS2345: Argume public getDomNode() { return domNode; ~~~~~~~ -!!! error TS2304: Cannot find name 'domNode'. +!!! error TS2663: Cannot find name 'domNode'. Did you mean to prefix the object member with 'this', 'this.domNode'? } public destroy() { @@ -99,7 +99,7 @@ tests/cases/compiler/recursiveClassReferenceTest.ts(95,21): error TS2345: Argume public getMode(): IMode { return mode; } ~~~~ -!!! error TS2304: Cannot find name 'mode'. +!!! error TS2663: Cannot find name 'mode'. Did you mean to prefix the object member with 'this', 'this.mode'? } export class Mode extends AbstractMode { From 1d817d2337631e525fc5cda2f0c1c09e0453bda1 Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Wed, 13 Jan 2016 20:28:39 +0200 Subject: [PATCH 20/28] fixed scopeCheckExtendedClassInsidePublicMethod2 test --- .../scopeCheckExtendedClassInsidePublicMethod2.errors.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/scopeCheckExtendedClassInsidePublicMethod2.errors.txt b/tests/baselines/reference/scopeCheckExtendedClassInsidePublicMethod2.errors.txt index c59171bdf0e..d8fbf512bcd 100644 --- a/tests/baselines/reference/scopeCheckExtendedClassInsidePublicMethod2.errors.txt +++ b/tests/baselines/reference/scopeCheckExtendedClassInsidePublicMethod2.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/scopeCheckExtendedClassInsidePublicMethod2.ts(4,7): error TS2304: Cannot find name 'v'. +tests/cases/compiler/scopeCheckExtendedClassInsidePublicMethod2.ts(4,7): error TS2663: Cannot find name 'v'. Did you mean to prefix the object member with 'this', 'this.v'? tests/cases/compiler/scopeCheckExtendedClassInsidePublicMethod2.ts(6,7): error TS2304: Cannot find name 's'. @@ -8,7 +8,7 @@ tests/cases/compiler/scopeCheckExtendedClassInsidePublicMethod2.ts(6,7): error T public c() { v = 1; ~ -!!! error TS2304: Cannot find name 'v'. +!!! error TS2663: Cannot find name 'v'. Did you mean to prefix the object member with 'this', 'this.v'? this.p = 1; s = 1; ~ From da5235fc513895c8933f7bc26bb3711674ada24c Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Wed, 13 Jan 2016 20:34:55 +0200 Subject: [PATCH 21/28] fixed scopeCheckExtendedClassInsideStaticMethod1 test --- .../scopeCheckExtendedClassInsideStaticMethod1.errors.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/scopeCheckExtendedClassInsideStaticMethod1.errors.txt b/tests/baselines/reference/scopeCheckExtendedClassInsideStaticMethod1.errors.txt index a6ecd488278..ac9381272e8 100644 --- a/tests/baselines/reference/scopeCheckExtendedClassInsideStaticMethod1.errors.txt +++ b/tests/baselines/reference/scopeCheckExtendedClassInsideStaticMethod1.errors.txt @@ -1,6 +1,6 @@ tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts(4,7): error TS2304: Cannot find name 'v'. tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts(5,12): error TS2339: Property 'p' does not exist on type 'typeof D'. -tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts(6,7): error TS2304: Cannot find name 's'. +tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts(6,7): error TS2662: Cannot find name 's'. Did you mean to prefix the static member with the class name, 'D.s'? ==== tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts (3 errors) ==== @@ -15,6 +15,6 @@ tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts(6,7): error T !!! error TS2339: Property 'p' does not exist on type 'typeof D'. s = 1; ~ -!!! error TS2304: Cannot find name 's'. +!!! error TS2662: Cannot find name 's'. Did you mean to prefix the static member with the class name, 'D.s'? } } \ No newline at end of file From dc426683aff2fd92ae9b9c1c0121c8a2789c97f6 Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Wed, 13 Jan 2016 20:35:49 +0200 Subject: [PATCH 22/28] fixed unqualifiedCallToClassStatic1 test --- .../reference/unqualifiedCallToClassStatic1.errors.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/unqualifiedCallToClassStatic1.errors.txt b/tests/baselines/reference/unqualifiedCallToClassStatic1.errors.txt index af9edd115e9..190ea245459 100644 --- a/tests/baselines/reference/unqualifiedCallToClassStatic1.errors.txt +++ b/tests/baselines/reference/unqualifiedCallToClassStatic1.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/unqualifiedCallToClassStatic1.ts(4,3): error TS2304: Cannot find name 'foo'. +tests/cases/compiler/unqualifiedCallToClassStatic1.ts(4,3): error TS2662: Cannot find name 'foo'. Did you mean to prefix the static member with the class name, 'Vector.foo'? ==== tests/cases/compiler/unqualifiedCallToClassStatic1.ts (1 errors) ==== @@ -7,6 +7,6 @@ tests/cases/compiler/unqualifiedCallToClassStatic1.ts(4,3): error TS2304: Cannot // 'foo' cannot be called in an unqualified manner. foo(); ~~~ -!!! error TS2304: Cannot find name 'foo'. +!!! error TS2662: Cannot find name 'foo'. Did you mean to prefix the static member with the class name, 'Vector.foo'? } } \ No newline at end of file From 02531af991ff3c7d420f5ff804d0806626ff11d7 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Wed, 13 Jan 2016 13:18:28 -0800 Subject: [PATCH 23/28] Update the watchedFileSet to use Path instead of string for file names --- src/compiler/sys.ts | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index f40de0bd65e..822ea5c1921 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -25,7 +25,7 @@ namespace ts { } interface WatchedFile { - fileName: string; + filePath: Path; callback: FileWatcherCallback; mtime?: Date; } @@ -244,13 +244,13 @@ namespace ts { return; } - _fs.stat(watchedFile.fileName, (err: any, stats: any) => { + _fs.stat(watchedFile.filePath, (err: any, stats: any) => { if (err) { - watchedFile.callback(watchedFile.fileName); + watchedFile.callback(watchedFile.filePath); } else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) { - watchedFile.mtime = getModifiedTime(watchedFile.fileName); - watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0); + watchedFile.mtime = getModifiedTime(watchedFile.filePath); + watchedFile.callback(watchedFile.filePath, watchedFile.mtime.getTime() === 0); } }); } @@ -278,11 +278,11 @@ namespace ts { }, interval); } - function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile { + function addFile(filePath: Path, callback: FileWatcherCallback): WatchedFile { const file: WatchedFile = { - fileName, + filePath, callback, - mtime: getModifiedTime(fileName) + mtime: getModifiedTime(filePath) }; watchedFiles.push(file); @@ -309,7 +309,6 @@ namespace ts { const dirWatchers = createFileMap(); // One file can have multiple watchers const fileWatcherCallbacks = createFileMap(); - const currentDirectory = process.cwd(); return { addFile, removeFile }; function reduceDirWatcherRefCount(dirPath: Path) { @@ -355,16 +354,15 @@ namespace ts { return undefined; } - function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile { - const filePath = toPath(fileName, currentDirectory, getCanonicalPath); + function addFile(filePath: Path, callback: FileWatcherCallback): WatchedFile { addFileWatcherCallback(filePath, callback); addDirWatcher(getDirectoryPath(filePath)); - return { fileName, callback }; + return { filePath, callback }; } function removeFile(watchedFile: WatchedFile) { - const filePath = toPath(watchedFile.fileName, currentDirectory, getCanonicalPath); + const filePath = watchedFile.filePath; if (fileWatcherCallbacks.contains(filePath)) { const newCallbacks = copyListRemovingItem(watchedFile.callback, fileWatcherCallbacks.get(filePath)); if (newCallbacks.length === 0) { @@ -513,7 +511,7 @@ namespace ts { // and https://github.com/Microsoft/TypeScript/issues/4643), therefore // if the current node.js version is newer than 4, use `fs.watch` instead. const watchSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet; - const watchedFile = watchSet.addFile(fileName, callback); + const watchedFile = watchSet.addFile(fileName, callback); return { close: () => watchSet.removeFile(watchedFile) }; From 05b1dffc88ab6be902fafa82696d330a9686599d Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Thu, 14 Jan 2016 00:01:59 +0200 Subject: [PATCH 24/28] changed name of checkForMissingPrefix to checkAndReportErrorForMissingPrefix --- src/compiler/checker.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fdce825e292..1df5a625c2b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -740,7 +740,7 @@ namespace ts { if (!result) { if (nameNotFoundMessage) { - if (!checkForMissingPrefix(errorLocation, name, nameArg)) { + if (!checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg)) { error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg)); } } @@ -779,10 +779,11 @@ namespace ts { return result; } - function checkForMissingPrefix(errorLocation: Node, name: string, nameArg: string | Identifier): boolean { + function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: string, nameArg: string | Identifier): boolean { if (!errorLocation || (errorLocation.kind === SyntaxKind.Identifier && (isTypeReferenceIdentifier(errorLocation)) || isInTypeQuery(errorLocation))) { return false; } + const container = getThisContainer(errorLocation, /* includeArrowFunctions */ true); let location = container; while (location) { From 067573b0c3e387835452f1d703b877f055f4cbc5 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Wed, 13 Jan 2016 14:02:34 -0800 Subject: [PATCH 25/28] cr feedback: simplify the removeFile function --- src/compiler/sys.ts | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 822ea5c1921..073a662ce1c 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -311,12 +311,15 @@ namespace ts { const fileWatcherCallbacks = createFileMap(); return { addFile, removeFile }; - function reduceDirWatcherRefCount(dirPath: Path) { - const watcher = dirWatchers.get(dirPath); - watcher.referenceCount -= 1; - if (watcher.referenceCount <= 0) { - watcher.close(); - dirWatchers.remove(dirPath); + function reduceDirWatcherRefCountForFile(filePath: Path) { + const dirPath = getDirectoryPath(filePath); + if (dirWatchers.contains(dirPath)) { + const watcher = dirWatchers.get(dirPath); + watcher.referenceCount -= 1; + if (watcher.referenceCount <= 0) { + watcher.close(); + dirWatchers.remove(dirPath); + } } } @@ -346,14 +349,6 @@ namespace ts { } } - function findWatchedDirForFile(filePath: Path): Path { - const dirPath = getDirectoryPath(filePath); - if (dirWatchers.contains(dirPath)) { - return dirPath; - } - return undefined; - } - function addFile(filePath: Path, callback: FileWatcherCallback): WatchedFile { addFileWatcherCallback(filePath, callback); addDirWatcher(getDirectoryPath(filePath)); @@ -362,15 +357,15 @@ namespace ts { } function removeFile(watchedFile: WatchedFile) { - const filePath = watchedFile.filePath; + removeFileWatcherCallback(watchedFile.filePath, watchedFile.callback); + reduceDirWatcherRefCountForFile(watchedFile.filePath); + } + + function removeFileWatcherCallback(filePath: Path, callback: FileWatcherCallback) { if (fileWatcherCallbacks.contains(filePath)) { - const newCallbacks = copyListRemovingItem(watchedFile.callback, fileWatcherCallbacks.get(filePath)); + const newCallbacks = copyListRemovingItem(callback, fileWatcherCallbacks.get(filePath)); if (newCallbacks.length === 0) { fileWatcherCallbacks.remove(filePath); - const watchedDir = findWatchedDirForFile(filePath); - if (watchedDir) { - reduceDirWatcherRefCount(watchedDir); - } } else { fileWatcherCallbacks.set(filePath, newCallbacks); From 21baedfebab8224ac5ed0168b35b38fbd7ed6f4f Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Thu, 14 Jan 2016 01:14:33 +0200 Subject: [PATCH 26/28] changed messages text in checkAndReportErrorForMissingPrefix --- src/compiler/checker.ts | 4 ++-- src/compiler/diagnosticMessages.json | 4 ++-- .../YieldExpression11_es6.errors.txt | 4 ++-- ...eferencingConstructorParameters.errors.txt | 8 ++++---- .../reference/parserharness.errors.txt | 20 +++++++++---------- .../reference/parserindenter.errors.txt | 4 ++-- .../recursiveClassReferenceTest.errors.txt | 8 ++++---- .../reference/scannertest1.errors.txt | 12 +++++------ ...xtendedClassInsidePublicMethod2.errors.txt | 4 ++-- ...xtendedClassInsideStaticMethod1.errors.txt | 4 ++-- .../unqualifiedCallToClassStatic1.errors.txt | 4 ++-- 11 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1df5a625c2b..d618397f885 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -793,7 +793,7 @@ namespace ts { if (location.flags & NodeFlags.Static) { classType = getTypeOfSymbol(symbol); if (getPropertyOfType(classType, name)) { - error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_to_prefix_the_static_member_with_the_class_name_1_0, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg), symbolToString(symbol)); + error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg), symbolToString(symbol)); return true; } } @@ -801,7 +801,7 @@ namespace ts { if (location === container) { classType = (getDeclaredTypeOfSymbol(symbol)).thisType; if (getPropertyOfType(classType, name)) { - error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_to_prefix_the_object_member_with_this_this_0, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg)); + error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg)); return true; } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7f1c195ae20..0453df0a9bf 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1775,11 +1775,11 @@ "category": "Error", "code": 2661 }, - "Cannot find name '{0}'. Did you mean to prefix the static member with the class name, '{1}.{0}'?": { + "Cannot find name '{0}'. Did you mean the static member '{1}.{0}'?": { "category": "Error", "code": 2662 }, - "Cannot find name '{0}'. Did you mean to prefix the object member with 'this', 'this.{0}'?": { + "Cannot find name '{0}'. Did you mean the instance member 'this.{0}'?": { "category": "Error", "code": 2663 }, diff --git a/tests/baselines/reference/YieldExpression11_es6.errors.txt b/tests/baselines/reference/YieldExpression11_es6.errors.txt index 4a2f93a9c6d..1b0c08bd79a 100644 --- a/tests/baselines/reference/YieldExpression11_es6.errors.txt +++ b/tests/baselines/reference/YieldExpression11_es6.errors.txt @@ -1,5 +1,5 @@ tests/cases/conformance/es6/yieldExpressions/YieldExpression11_es6.ts(2,3): error TS1220: Generators are only available when targeting ECMAScript 6 or higher. -tests/cases/conformance/es6/yieldExpressions/YieldExpression11_es6.ts(3,11): error TS2663: Cannot find name 'foo'. Did you mean to prefix the object member with 'this', 'this.foo'? +tests/cases/conformance/es6/yieldExpressions/YieldExpression11_es6.ts(3,11): error TS2663: Cannot find name 'foo'. Did you mean the instance member 'this.foo'? ==== tests/cases/conformance/es6/yieldExpressions/YieldExpression11_es6.ts (2 errors) ==== @@ -9,6 +9,6 @@ tests/cases/conformance/es6/yieldExpressions/YieldExpression11_es6.ts(3,11): err !!! error TS1220: Generators are only available when targeting ECMAScript 6 or higher. yield(foo); ~~~ -!!! error TS2663: Cannot find name 'foo'. Did you mean to prefix the object member with 'this', 'this.foo'? +!!! error TS2663: Cannot find name 'foo'. Did you mean the instance member 'this.foo'? } } \ No newline at end of file diff --git a/tests/baselines/reference/initializerReferencingConstructorParameters.errors.txt b/tests/baselines/reference/initializerReferencingConstructorParameters.errors.txt index 03e4e83e409..eb6744d656b 100644 --- a/tests/baselines/reference/initializerReferencingConstructorParameters.errors.txt +++ b/tests/baselines/reference/initializerReferencingConstructorParameters.errors.txt @@ -1,9 +1,9 @@ tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(4,9): error TS2304: Cannot find name 'x'. tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(5,15): error TS2304: Cannot find name 'x'. -tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(10,9): error TS2663: Cannot find name 'x'. Did you mean to prefix the object member with 'this', 'this.x'? +tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(10,9): error TS2663: Cannot find name 'x'. Did you mean the instance member 'this.x'? tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(11,15): error TS2304: Cannot find name 'x'. tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(17,15): error TS1003: Identifier expected. -tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(23,9): error TS2663: Cannot find name 'x'. Did you mean to prefix the object member with 'this', 'this.x'? +tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(23,9): error TS2663: Cannot find name 'x'. Did you mean the instance member 'this.x'? ==== tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts (6 errors) ==== @@ -22,7 +22,7 @@ tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencin class D { a = x; // error ~ -!!! error TS2663: Cannot find name 'x'. Did you mean to prefix the object member with 'this', 'this.x'? +!!! error TS2663: Cannot find name 'x'. Did you mean the instance member 'this.x'? b: typeof x; // error ~ !!! error TS2304: Cannot find name 'x'. @@ -41,6 +41,6 @@ tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencin a = this.x; // ok b = x; // error ~ -!!! error TS2663: Cannot find name 'x'. Did you mean to prefix the object member with 'this', 'this.x'? +!!! error TS2663: Cannot find name 'x'. Did you mean the instance member 'this.x'? constructor(public x: T) { } } \ No newline at end of file diff --git a/tests/baselines/reference/parserharness.errors.txt b/tests/baselines/reference/parserharness.errors.txt index 711d3fd9aac..963ce12ddf1 100644 --- a/tests/baselines/reference/parserharness.errors.txt +++ b/tests/baselines/reference/parserharness.errors.txt @@ -7,11 +7,11 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(25,17): er tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(41,12): error TS2304: Cannot find name 'ActiveXObject'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(43,19): error TS2304: Cannot find name 'require'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(44,14): error TS2304: Cannot find name 'require'. -tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(341,13): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? -tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(347,13): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? -tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(351,17): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? -tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(354,17): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? -tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(354,35): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? +tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(341,13): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean the static member 'Runnable.errorHandlerStack'? +tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(347,13): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean the static member 'Runnable.errorHandlerStack'? +tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(351,17): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean the static member 'Runnable.errorHandlerStack'? +tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(354,17): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean the static member 'Runnable.errorHandlerStack'? +tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(354,35): error TS2662: Cannot find name 'errorHandlerStack'. Did you mean the static member 'Runnable.errorHandlerStack'? tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(691,50): error TS2304: Cannot find name 'ITextWriter'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(716,47): error TS2503: Cannot find namespace 'TypeScript'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(721,62): error TS2304: Cannot find name 'ITextWriter'. @@ -471,7 +471,7 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(2030,32): static pushGlobalErrorHandler(done: IDone) { errorHandlerStack.push(function (e) { ~~~~~~~~~~~~~~~~~ -!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? +!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean the static member 'Runnable.errorHandlerStack'? done(e); }); } @@ -479,20 +479,20 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserharness.ts(2030,32): static popGlobalErrorHandler() { errorHandlerStack.pop(); ~~~~~~~~~~~~~~~~~ -!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? +!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean the static member 'Runnable.errorHandlerStack'? } static handleError(e: Error) { if (errorHandlerStack.length === 0) { ~~~~~~~~~~~~~~~~~ -!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? +!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean the static member 'Runnable.errorHandlerStack'? IO.printLine('Global error: ' + e); } else { errorHandlerStack[errorHandlerStack.length - 1](e); ~~~~~~~~~~~~~~~~~ -!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? +!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean the static member 'Runnable.errorHandlerStack'? ~~~~~~~~~~~~~~~~~ -!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean to prefix the static member with the class name, 'Runnable.errorHandlerStack'? +!!! error TS2662: Cannot find name 'errorHandlerStack'. Did you mean the static member 'Runnable.errorHandlerStack'? } } } diff --git a/tests/baselines/reference/parserindenter.errors.txt b/tests/baselines/reference/parserindenter.errors.txt index d892f27579f..8ccc9220710 100644 --- a/tests/baselines/reference/parserindenter.errors.txt +++ b/tests/baselines/reference/parserindenter.errors.txt @@ -28,7 +28,7 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(152,63): tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(153,30): error TS2304: Cannot find name 'List_TextEditInfo'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(155,32): error TS2304: Cannot find name 'AuthorTokenKind'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(182,79): error TS2503: Cannot find namespace 'Services'. -tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(183,20): error TS2662: Cannot find name 'GetIndentSizeFromText'. Did you mean to prefix the static member with the class name, 'Indenter.GetIndentSizeFromText'? +tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(183,20): error TS2662: Cannot find name 'GetIndentSizeFromText'. Did you mean the static member 'Indenter.GetIndentSizeFromText'? tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(186,67): error TS2503: Cannot find namespace 'Services'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(207,50): error TS2304: Cannot find name 'TokenSpan'. tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(207,67): error TS2304: Cannot find name 'ParseNode'. @@ -373,7 +373,7 @@ tests/cases/conformance/parser/ecmascript5/RealWorld/parserindenter.ts(736,38): !!! error TS2503: Cannot find namespace 'Services'. return GetIndentSizeFromText(indentText, editorOptions, /*includeNonIndentChars:*/ false); ~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2662: Cannot find name 'GetIndentSizeFromText'. Did you mean to prefix the static member with the class name, 'Indenter.GetIndentSizeFromText'? +!!! error TS2662: Cannot find name 'GetIndentSizeFromText'. Did you mean the static member 'Indenter.GetIndentSizeFromText'? } static GetIndentSizeFromText(text: string, editorOptions: Services.EditorOptions, includeNonIndentChars: boolean): number { diff --git a/tests/baselines/reference/recursiveClassReferenceTest.errors.txt b/tests/baselines/reference/recursiveClassReferenceTest.errors.txt index 76563a19b5a..4a1a6f1782c 100644 --- a/tests/baselines/reference/recursiveClassReferenceTest.errors.txt +++ b/tests/baselines/reference/recursiveClassReferenceTest.errors.txt @@ -1,6 +1,6 @@ tests/cases/compiler/recursiveClassReferenceTest.ts(16,19): error TS2304: Cannot find name 'Element'. -tests/cases/compiler/recursiveClassReferenceTest.ts(56,11): error TS2663: Cannot find name 'domNode'. Did you mean to prefix the object member with 'this', 'this.domNode'? -tests/cases/compiler/recursiveClassReferenceTest.ts(88,36): error TS2663: Cannot find name 'mode'. Did you mean to prefix the object member with 'this', 'this.mode'? +tests/cases/compiler/recursiveClassReferenceTest.ts(56,11): error TS2663: Cannot find name 'domNode'. Did you mean the instance member 'this.domNode'? +tests/cases/compiler/recursiveClassReferenceTest.ts(88,36): error TS2663: Cannot find name 'mode'. Did you mean the instance member 'this.mode'? tests/cases/compiler/recursiveClassReferenceTest.ts(95,21): error TS2345: Argument of type 'Window' is not assignable to parameter of type 'IMode'. Property 'getInitialState' is missing in type 'Window'. @@ -65,7 +65,7 @@ tests/cases/compiler/recursiveClassReferenceTest.ts(95,21): error TS2345: Argume public getDomNode() { return domNode; ~~~~~~~ -!!! error TS2663: Cannot find name 'domNode'. Did you mean to prefix the object member with 'this', 'this.domNode'? +!!! error TS2663: Cannot find name 'domNode'. Did you mean the instance member 'this.domNode'? } public destroy() { @@ -99,7 +99,7 @@ tests/cases/compiler/recursiveClassReferenceTest.ts(95,21): error TS2345: Argume public getMode(): IMode { return mode; } ~~~~ -!!! error TS2663: Cannot find name 'mode'. Did you mean to prefix the object member with 'this', 'this.mode'? +!!! error TS2663: Cannot find name 'mode'. Did you mean the instance member 'this.mode'? } export class Mode extends AbstractMode { diff --git a/tests/baselines/reference/scannertest1.errors.txt b/tests/baselines/reference/scannertest1.errors.txt index 234923b5a2f..3831dbe398e 100644 --- a/tests/baselines/reference/scannertest1.errors.txt +++ b/tests/baselines/reference/scannertest1.errors.txt @@ -1,14 +1,14 @@ tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(1,1): error TS6053: File 'tests/cases/conformance/scanner/ecmascript5/References.ts' not found. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(5,21): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(5,47): error TS2304: Cannot find name 'CharacterCodes'. -tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(9,16): error TS2662: Cannot find name 'isDecimalDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isDecimalDigit'? +tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(9,16): error TS2662: Cannot find name 'isDecimalDigit'. Did you mean the static member 'CharacterInfo.isDecimalDigit'? tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(10,22): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(10,47): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(11,22): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(11,47): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(15,9): error TS2304: Cannot find name 'Debug'. -tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(15,22): error TS2662: Cannot find name 'isHexDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isHexDigit'? -tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(16,16): error TS2662: Cannot find name 'isDecimalDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isDecimalDigit'? +tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(15,22): error TS2662: Cannot find name 'isHexDigit'. Did you mean the static member 'CharacterInfo.isHexDigit'? +tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(16,16): error TS2662: Cannot find name 'isDecimalDigit'. Did you mean the static member 'CharacterInfo.isDecimalDigit'? tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(17,20): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(18,21): error TS2304: Cannot find name 'CharacterCodes'. tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(18,46): error TS2304: Cannot find name 'CharacterCodes'. @@ -33,7 +33,7 @@ tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(20,23): error TS2304 public static isHexDigit(c: number): boolean { return isDecimalDigit(c) || ~~~~~~~~~~~~~~ -!!! error TS2662: Cannot find name 'isDecimalDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isDecimalDigit'? +!!! error TS2662: Cannot find name 'isDecimalDigit'. Did you mean the static member 'CharacterInfo.isDecimalDigit'? (c >= CharacterCodes.A && c <= CharacterCodes.F) || ~~~~~~~~~~~~~~ !!! error TS2304: Cannot find name 'CharacterCodes'. @@ -51,10 +51,10 @@ tests/cases/conformance/scanner/ecmascript5/scannertest1.ts(20,23): error TS2304 ~~~~~ !!! error TS2304: Cannot find name 'Debug'. ~~~~~~~~~~ -!!! error TS2662: Cannot find name 'isHexDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isHexDigit'? +!!! error TS2662: Cannot find name 'isHexDigit'. Did you mean the static member 'CharacterInfo.isHexDigit'? return isDecimalDigit(c) ~~~~~~~~~~~~~~ -!!! error TS2662: Cannot find name 'isDecimalDigit'. Did you mean to prefix the static member with the class name, 'CharacterInfo.isDecimalDigit'? +!!! error TS2662: Cannot find name 'isDecimalDigit'. Did you mean the static member 'CharacterInfo.isDecimalDigit'? ? (c - CharacterCodes._0) ~~~~~~~~~~~~~~ !!! error TS2304: Cannot find name 'CharacterCodes'. diff --git a/tests/baselines/reference/scopeCheckExtendedClassInsidePublicMethod2.errors.txt b/tests/baselines/reference/scopeCheckExtendedClassInsidePublicMethod2.errors.txt index d8fbf512bcd..91cb87dbeb8 100644 --- a/tests/baselines/reference/scopeCheckExtendedClassInsidePublicMethod2.errors.txt +++ b/tests/baselines/reference/scopeCheckExtendedClassInsidePublicMethod2.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/scopeCheckExtendedClassInsidePublicMethod2.ts(4,7): error TS2663: Cannot find name 'v'. Did you mean to prefix the object member with 'this', 'this.v'? +tests/cases/compiler/scopeCheckExtendedClassInsidePublicMethod2.ts(4,7): error TS2663: Cannot find name 'v'. Did you mean the instance member 'this.v'? tests/cases/compiler/scopeCheckExtendedClassInsidePublicMethod2.ts(6,7): error TS2304: Cannot find name 's'. @@ -8,7 +8,7 @@ tests/cases/compiler/scopeCheckExtendedClassInsidePublicMethod2.ts(6,7): error T public c() { v = 1; ~ -!!! error TS2663: Cannot find name 'v'. Did you mean to prefix the object member with 'this', 'this.v'? +!!! error TS2663: Cannot find name 'v'. Did you mean the instance member 'this.v'? this.p = 1; s = 1; ~ diff --git a/tests/baselines/reference/scopeCheckExtendedClassInsideStaticMethod1.errors.txt b/tests/baselines/reference/scopeCheckExtendedClassInsideStaticMethod1.errors.txt index ac9381272e8..dd3e5ef446b 100644 --- a/tests/baselines/reference/scopeCheckExtendedClassInsideStaticMethod1.errors.txt +++ b/tests/baselines/reference/scopeCheckExtendedClassInsideStaticMethod1.errors.txt @@ -1,6 +1,6 @@ tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts(4,7): error TS2304: Cannot find name 'v'. tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts(5,12): error TS2339: Property 'p' does not exist on type 'typeof D'. -tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts(6,7): error TS2662: Cannot find name 's'. Did you mean to prefix the static member with the class name, 'D.s'? +tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts(6,7): error TS2662: Cannot find name 's'. Did you mean the static member 'D.s'? ==== tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts (3 errors) ==== @@ -15,6 +15,6 @@ tests/cases/compiler/scopeCheckExtendedClassInsideStaticMethod1.ts(6,7): error T !!! error TS2339: Property 'p' does not exist on type 'typeof D'. s = 1; ~ -!!! error TS2662: Cannot find name 's'. Did you mean to prefix the static member with the class name, 'D.s'? +!!! error TS2662: Cannot find name 's'. Did you mean the static member 'D.s'? } } \ No newline at end of file diff --git a/tests/baselines/reference/unqualifiedCallToClassStatic1.errors.txt b/tests/baselines/reference/unqualifiedCallToClassStatic1.errors.txt index 190ea245459..4152c182d45 100644 --- a/tests/baselines/reference/unqualifiedCallToClassStatic1.errors.txt +++ b/tests/baselines/reference/unqualifiedCallToClassStatic1.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/unqualifiedCallToClassStatic1.ts(4,3): error TS2662: Cannot find name 'foo'. Did you mean to prefix the static member with the class name, 'Vector.foo'? +tests/cases/compiler/unqualifiedCallToClassStatic1.ts(4,3): error TS2662: Cannot find name 'foo'. Did you mean the static member 'Vector.foo'? ==== tests/cases/compiler/unqualifiedCallToClassStatic1.ts (1 errors) ==== @@ -7,6 +7,6 @@ tests/cases/compiler/unqualifiedCallToClassStatic1.ts(4,3): error TS2662: Cannot // 'foo' cannot be called in an unqualified manner. foo(); ~~~ -!!! error TS2662: Cannot find name 'foo'. Did you mean to prefix the static member with the class name, 'Vector.foo'? +!!! error TS2662: Cannot find name 'foo'. Did you mean the static member 'Vector.foo'? } } \ No newline at end of file From dbfe862dbd87e491728fdd83c82c26572c63af7b Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Thu, 14 Jan 2016 00:34:43 -0800 Subject: [PATCH 27/28] not casting relative filenames in 'tsc watch' to Path --- src/compiler/core.ts | 7 +++++++ src/compiler/sys.ts | 6 +++--- src/compiler/tsc.ts | 6 ++++-- src/server/editorServices.ts | 4 ++-- src/services/services.ts | 7 ------- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index aba2e48e4a1..639660a2a4c 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -872,4 +872,11 @@ namespace ts { } return copiedList; } + + export function createGetCanonicalFileName(useCaseSensitivefileNames: boolean): (fileName: string) => string { + return useCaseSensitivefileNames + ? ((fileName) => fileName) + : ((fileName) => fileName.toLowerCase()); + } + } diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 073a662ce1c..e6f908d250a 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -11,7 +11,7 @@ namespace ts { write(s: string): void; readFile(path: string, encoding?: string): string; writeFile(path: string, data: string, writeByteOrderMark?: boolean): void; - watchFile?(path: string, callback: FileWatcherCallback): FileWatcher; + watchFile?(path: Path, callback: FileWatcherCallback): FileWatcher; watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher; resolvePath(path: string): string; fileExists(path: string): boolean; @@ -500,13 +500,13 @@ namespace ts { }, readFile, writeFile, - watchFile: (fileName, callback) => { + watchFile: (filePath, callback) => { // 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. const watchSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet; - const watchedFile = watchSet.addFile(fileName, callback); + const watchedFile = watchSet.addFile(filePath, callback); return { close: () => watchSet.removeFile(watchedFile) }; diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index d064ec54c9c..808ee6da804 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -334,7 +334,8 @@ namespace ts { return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } if (configFileName) { - configFileWatcher = sys.watchFile(configFileName, configFileChanged); + const configFilePath = toPath(configFileName, sys.getCurrentDirectory(), createGetCanonicalFileName(sys.useCaseSensitiveFileNames)); + configFileWatcher = sys.watchFile(configFilePath, configFileChanged); } if (sys.watchDirectory && configFileName) { const directory = ts.getDirectoryPath(configFileName); @@ -442,7 +443,8 @@ namespace ts { const sourceFile = hostGetSourceFile(fileName, languageVersion, onError); if (sourceFile && compilerOptions.watch) { // Attach a file watcher - sourceFile.fileWatcher = sys.watchFile(sourceFile.fileName, (fileName: string, removed?: boolean) => sourceFileChanged(sourceFile, removed)); + const filePath = toPath(sourceFile.fileName, sys.getCurrentDirectory(), createGetCanonicalFileName(sys.useCaseSensitiveFileNames)); + sourceFile.fileWatcher = sys.watchFile(filePath, (fileName: string, removed?: boolean) => sourceFileChanged(sourceFile, removed)); } return sourceFile; } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 5a1c85fc13c..0442575aded 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1000,7 +1000,7 @@ namespace ts.server { info.setFormatOptions(this.getFormatCodeOptions()); this.filenameToScriptInfo[fileName] = info; if (!info.isOpen) { - info.fileWatcher = this.host.watchFile(fileName, _ => { this.watchedFileChanged(fileName); }); + info.fileWatcher = this.host.watchFile(fileName, _ => { this.watchedFileChanged(fileName); }); } } } @@ -1213,7 +1213,7 @@ namespace ts.server { } } project.finishGraph(); - project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project)); + 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), diff --git a/src/services/services.ts b/src/services/services.ts index 0ffd1138cba..0f3c18f7a85 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2008,13 +2008,6 @@ namespace ts { return createLanguageServiceSourceFile(sourceFile.fileName, scriptSnapshot, sourceFile.languageVersion, version, /*setNodeParents*/ true); } - export function createGetCanonicalFileName(useCaseSensitivefileNames: boolean): (fileName: string) => string { - return useCaseSensitivefileNames - ? ((fileName) => fileName) - : ((fileName) => fileName.toLowerCase()); - } - - export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean, currentDirectory = ""): DocumentRegistry { // Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have // for those settings. From e547a1abd27586b41ce7285afe0fadbbf4314e34 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 14 Jan 2016 11:30:02 -0800 Subject: [PATCH 28/28] Update CONTRIBUTING.md Add guidelines for logging issues --- CONTRIBUTING.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3a712b5619a..d9941d92e87 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,45 @@ +# Instructions for Logging Issues + +## 1. Read the FAQ + +Please [read the FAQ](https://github.com/Microsoft/TypeScript/wiki/FAQ) before logging new issues, even if you think you have found a bug. + +Issues that ask questions answered in the FAQ will be closed without elaboration. + +## 2. Search for Duplicates + +[Search the existing issues](https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&q=is%3Aissue) before logging a new one. + +## 3. Do you have a question? + +The issue tracker is for **issues**, in other words, bugs and suggestions. +If you have a *question*, please use [http://stackoverflow.com/questions/tagged/typescript](Stack Overflow), [https://gitter.im/Microsoft/TypeScript](Gitter), your favorite search engine, or other resources. +Due to increased traffic, we can no longer answer questions in the issue tracker. + +## 4. Did you find a bug? + +When logging a bug, please be sure to include the following: + * What version of TypeScript you're using (run `tsc --v`) + * If at all possible, an *isolated* way to reproduce the behavior + * The behavior you expect to see, and the actual behavior + +You can try out the nightly build of TypeScript (`npm install typescript@next`) to see if the bug has already been fixed. + +## 5. Do you have a suggestion? + +We also accept suggestions in the issue tracker. +Be sure to [check the FAQ](https://github.com/Microsoft/TypeScript/wiki/FAQ) and [search](https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&q=is%3Aissue) first. + +In general, things we find useful when reviewing suggestins are: +* A description of the problem you're trying to solve +* An overview of the suggested solution +* Examples of how the suggestion would work in various places + * Code examples showing e.g. "this would be an error, this wouldn't" + * Code examples showing the generated JavaScript (if applicable) +* If relevant, precedent in other languages can be useful for establishing context and expected behavior + +# Instructions for Contributing Code + ## Contributing bug fixes TypeScript is currently accepting contributions in the form of bug fixes. A bug must have an issue tracking it in the issue tracker that has been approved ("Milestone == Community") by the TypeScript team. Your pull request should include a link to the bug that you are fixing. If you've submitted a PR for a bug, please post a comment in the bug to avoid duplication of effort.