mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-11 01:34:55 -06:00
Merge branch 'master' into refactorSignatureRelatability
This commit is contained in:
commit
74293a4b1d
@ -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.
|
||||
|
||||
@ -893,6 +893,7 @@ function getLinterOptions() {
|
||||
|
||||
function lintFileContents(options, path, contents) {
|
||||
var ll = new Linter(path, contents, options);
|
||||
console.log("Linting '" + path + "'.")
|
||||
return ll.lint();
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"istanbul": "latest",
|
||||
"mocha-fivemat-progress-reporter": "latest",
|
||||
"tslint": "next",
|
||||
"typescript": "next",
|
||||
"typescript": "1.8.0-dev.20160113",
|
||||
"tsd": "latest"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@ -616,7 +616,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)));
|
||||
}
|
||||
|
||||
@ -874,4 +876,11 @@ namespace ts {
|
||||
}
|
||||
return copiedList;
|
||||
}
|
||||
|
||||
export function createGetCanonicalFileName(useCaseSensitivefileNames: boolean): (fileName: string) => string {
|
||||
return useCaseSensitivefileNames
|
||||
? ((fileName) => fileName)
|
||||
: ((fileName) => fileName.toLowerCase());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
/// <reference path="core.ts"/>
|
||||
|
||||
namespace ts {
|
||||
export type FileWatcherCallback = (path: string, removed?: boolean) => void;
|
||||
export type DirectoryWatcherCallback = (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: Path, callback: FileWatcherCallback): FileWatcher;
|
||||
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
resolvePath(path: string): string;
|
||||
fileExists(path: string): boolean;
|
||||
directoryExists(path: string): boolean;
|
||||
@ -22,15 +25,20 @@ namespace ts {
|
||||
}
|
||||
|
||||
interface WatchedFile {
|
||||
fileName: string;
|
||||
callback: (fileName: string, removed?: boolean) => void;
|
||||
mtime: Date;
|
||||
filePath: Path;
|
||||
callback: FileWatcherCallback;
|
||||
mtime?: Date;
|
||||
}
|
||||
|
||||
export interface FileWatcher {
|
||||
close(): void;
|
||||
}
|
||||
|
||||
export interface DirectoryWatcher extends FileWatcher {
|
||||
directoryPath: Path;
|
||||
referenceCount: number;
|
||||
}
|
||||
|
||||
declare var require: any;
|
||||
declare var module: any;
|
||||
declare var process: any;
|
||||
@ -62,8 +70,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: FileWatcherCallback): FileWatcher;
|
||||
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
};
|
||||
|
||||
export var sys: System = (function () {
|
||||
@ -221,7 +229,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;
|
||||
@ -236,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);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -270,11 +278,11 @@ namespace ts {
|
||||
}, interval);
|
||||
}
|
||||
|
||||
function addFile(fileName: string, callback: (fileName: string, removed?: boolean) => void): WatchedFile {
|
||||
function addFile(filePath: Path, callback: FileWatcherCallback): WatchedFile {
|
||||
const file: WatchedFile = {
|
||||
fileName,
|
||||
filePath,
|
||||
callback,
|
||||
mtime: getModifiedTime(fileName)
|
||||
mtime: getModifiedTime(filePath)
|
||||
};
|
||||
|
||||
watchedFiles.push(file);
|
||||
@ -297,6 +305,88 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function createWatchedFileSet() {
|
||||
const dirWatchers = createFileMap<DirectoryWatcher>();
|
||||
// One file can have multiple watchers
|
||||
const fileWatcherCallbacks = createFileMap<FileWatcherCallback[]>();
|
||||
return { addFile, removeFile };
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addDirWatcher(dirPath: Path): void {
|
||||
if (dirWatchers.contains(dirPath)) {
|
||||
const watcher = dirWatchers.get(dirPath);
|
||||
watcher.referenceCount += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
const watcher: DirectoryWatcher = _fs.watch(
|
||||
dirPath,
|
||||
{ persistent: true },
|
||||
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
|
||||
);
|
||||
watcher.referenceCount = 1;
|
||||
dirWatchers.set(dirPath, watcher);
|
||||
return;
|
||||
}
|
||||
|
||||
function addFileWatcherCallback(filePath: Path, callback: FileWatcherCallback): void {
|
||||
if (fileWatcherCallbacks.contains(filePath)) {
|
||||
fileWatcherCallbacks.get(filePath).push(callback);
|
||||
}
|
||||
else {
|
||||
fileWatcherCallbacks.set(filePath, [callback]);
|
||||
}
|
||||
}
|
||||
|
||||
function addFile(filePath: Path, callback: FileWatcherCallback): WatchedFile {
|
||||
addFileWatcherCallback(filePath, callback);
|
||||
addDirWatcher(getDirectoryPath(filePath));
|
||||
|
||||
return { filePath, callback };
|
||||
}
|
||||
|
||||
function removeFile(watchedFile: WatchedFile) {
|
||||
removeFileWatcherCallback(watchedFile.filePath, watchedFile.callback);
|
||||
reduceDirWatcherRefCountForFile(watchedFile.filePath);
|
||||
}
|
||||
|
||||
function removeFileWatcherCallback(filePath: Path, callback: FileWatcherCallback) {
|
||||
if (fileWatcherCallbacks.contains(filePath)) {
|
||||
const newCallbacks = copyListRemovingItem(callback, fileWatcherCallbacks.get(filePath));
|
||||
if (newCallbacks.length === 0) {
|
||||
fileWatcherCallbacks.remove(filePath);
|
||||
}
|
||||
else {
|
||||
fileWatcherCallbacks.set(filePath, newCallbacks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
if (eventName === "change" && fileWatcherCallbacks.contains(filePath)) {
|
||||
for (const fileCallback of fileWatcherCallbacks.get(filePath)) {
|
||||
fileCallback(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// REVIEW: for now this implementation uses polling.
|
||||
// The advantage of polling is that it works reliably
|
||||
// on all os and with network mounted files.
|
||||
@ -310,8 +400,13 @@ 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 {
|
||||
return parseInt(process.version.charAt(1)) >= 4;
|
||||
}
|
||||
|
||||
const platform: string = _os.platform();
|
||||
// win32\win64 are case insensitive platforms, MacOS (darwin) by default is also case insensitive
|
||||
const useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin";
|
||||
@ -405,29 +500,38 @@ 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 watchedFile = watchedFileSet.addFile(fileName, callback);
|
||||
const watchSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet;
|
||||
const watchedFile = watchSet.addFile(filePath, callback);
|
||||
return {
|
||||
close: () => watchedFileSet.removeFile(watchedFile)
|
||||
close: () => watchSet.removeFile(watchedFile)
|
||||
};
|
||||
},
|
||||
watchDirectory: (path, callback, recursive) => {
|
||||
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
|
||||
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
|
||||
let options: any;
|
||||
if (isNode4OrLater() && (process.platform === "win32" || process.platform === "darwin")) {
|
||||
options = { persistent: true, recursive: !!recursive };
|
||||
}
|
||||
else {
|
||||
options = { persistent: true };
|
||||
}
|
||||
|
||||
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
|
||||
// event name is "change")
|
||||
if (eventName === "rename") {
|
||||
// When deleting a file, the passed baseFileName is null
|
||||
callback(!relativeFileName ? relativeFileName : normalizePath(ts.combinePaths(path, relativeFileName)));
|
||||
callback(!relativeFileName ? relativeFileName : normalizePath(combinePaths(path, relativeFileName)));
|
||||
};
|
||||
}
|
||||
);
|
||||
@ -511,5 +615,3 @@ namespace 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;
|
||||
}
|
||||
|
||||
@ -1002,7 +1002,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(<Path>fileName, _ => { this.watchedFileChanged(fileName); });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1215,7 +1215,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
project.finishGraph();
|
||||
project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project));
|
||||
project.projectFileWatcher = this.host.watchFile(<Path>configFilename, _ => this.watchedProjectConfigFileChanged(project));
|
||||
this.log("Add recursive watcher for: " + ts.getDirectoryPath(configFilename));
|
||||
project.directoryWatcher = this.host.watchDirectory(
|
||||
ts.getDirectoryPath(configFilename),
|
||||
|
||||
@ -2018,13 +2018,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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user