2015-01-16 03:18:19 +01:00
|
|
|
/// <reference path="core.ts"/>
|
2014-07-16 19:49:11 +02:00
|
|
|
|
2015-06-12 18:01:48 +02:00
|
|
|
namespace ts {
|
2016-03-23 20:49:34 +01:00
|
|
|
export type FileWatcherCallback = (fileName: string, removed?: boolean) => void;
|
[Transforms] Merge master 06/06/2016 (#8991)
* Remove check narrowing only certain types, add test showing issues with this
* string literal case test
* Reconcile fix with CFA work
* Defaultable -> NotNarrowable to align with use
* Missed a defaultable in comments
* Add test for narrowing to unions of string literals
* Rewrite isInStringLiteral to accomodate for unterminated strings
* Refactor signatureHelp to expose helper functions
* Add support for completion in string literals
* Remove unused check
* Use const instead of let
* Fix error
* Formatting changes
* Use shorthand properties
* Add failing test for #8738
* Sort baseline reference identifier by name
* Detects assignment to internal module export clause, fixes #8738
* add SharedArrayBuffer
fix
* Factor out assignment op check
* Add test for composite assignment
* Factor out the behaviour and handles x++ and ++x
* Handles ES3 default as identifier name
* Fix missing else statement
* isNameOfExportedDeclarationInNonES6Module
* Reorder options alphabetically
* Mark diagnostics, and skipDefaultLibCheck as internal
* Allow an import of "foo.js" to be matched by a file "foo.ts"
* Improve loadModuleFromFile code
* Respond to PR comments
* Respond to more PR comments
* Fix test
* Actually merge from master
* Revert to old tryLoad implementation
* Run fixupParentReferences when parsing isolated jsDocComment
* initial revision of unit test support for project system in tsserver
* Allow wildcard ("*") patterns in ambient module declarations
* Add non-widening forms of null and undefined
* Create separate control flows for property declarations with initializers
* Add regression test
* Allow trailing commas in function parameter and argument lists
* Add tests
* Remove unused variable
* Add null check and CR feedback
* Support shorthand ambient module declarations
* Revert "Merge pull request #7235 from weswigham/narrow-all-types"
This reverts commit ef0f6c8fe4f94a7e294cfe42d7025c9dca6535d5, reversing
changes made to 9f087cb62ade7a879e23c229df752fc8f87d679c.
* reuse the fixupParentReferences function
* Improve typing of && operator with --strictNullChecks
* Add test
* Respond to PR comments
* Respond to PR comments
* Add merging tests
* Use a function `stringify` to simplify calls to `JSON.stringify(xyz, undefined, 2)`
* Update tests
* Fix mistake
* Include indent in navigation bar protocol
Previously navbar01 test had indents when run in the browser but not when run from node. Now they run the same.
* Remove unnecessary restrictions in property access narrowing
* Fix fourslash test
* Add regression test
* Consider property declarations to be control flow containers
* Adding regression test
* Remove restriction on --target es5 and --module es6
* change type definition for Object.create
* Fix signature help
* Add "implicit any" warning for shorthand ambient modules
* Remove trailing whitespace
* Support using string values in enums for CompilerOptions in transpile methods
* Remove trailing whitespace in jakefile
* Make `jake runtests-browser` support test regexes with spaces
For example: `jake runtests-browser t="transpile .js files"` now works.
* Add another test
* factor out isJsxOrTsxExtension
* Move to a conformance test
* Revert "Revert "Merge pull request #7235 from weswigham/narrow-all-types""
This reverts commit fc3e040c5167868ed623612e8f33fb3beedf73b1.
* Use inclusive flag, as originally done, but include almost everything
* Add additional tests
* Respond to PR comments
* Fix typo
* add tests for tsserver project system
* Fix test
* Allow case comparison to undefined and null in strict null checking mode
* Remove incorrectly added tests
* check if moduleResolution when verifying that program can be reused
* more tests for module resolution change and exclude
* Fix linting issues
* Merge JSDoc of assignments from function expressions
* Allow nested assignments in type guards
* Add tests
* Improve order of parameter's merged jsdoc
* Force LF newlines for LKG builds/non debug builds
Fixes 6630
* Create intersection types in type guards for unrelated types
* Split commentsFunction test into expr/decl
And renumber.
* Remove TODO comments
* Accept new baselines
* Add tests
* Remove comments
* Fix test helper
* Recognize relative path using in outDir property (#9025)
* Recognize relative path using in outDir property
* Add projects tests
* Add project .json files
* Update baselines
* Add comments
* Add test case
The test passes in 1.8 and fails in master.
* Return trace when exception happens
* Remove Long-Done TODO
AFAIK, the harness sources have been concatenated into `run.js` for as long as I've known. This stops executing them twice (and in turn makes debugging tests much easier, since you no longer have to debug into eval'd code).
* Allow primitive type guards with typeof on right
Previously, only type guards of the form `typeof x === 'string'` were
allowed. Now you can write `'string' === typeof x`.
* Primitive type guards are now order independent
* Fix comments in tests
* Add handleing for classes
* Add more tests for target=es5 module=es6
* addExportToArgumentListKind
* Accept baseline
* Add more tests
* wip-fixing transforms
* Adds progress indicators to the runtests-parallel build task.
* Fixed typo
* Fix comment
* Add test for out-of-range error
* Use proper method of not resolving alias
* Fix module loading error
(commandLineOptions_stringToEnum would be undefined if optionDeclarations wasn't loaded yet)
* Port 8739
* Update tests
* Update baselines
* Contextually type return statement in async function
* Remove stale files
* Undo change
* Improve perf
* Improve tests
* Fix sourcemaps for debugging tests
* Allow --sourceRoot with --inlineSources option
Fixes #8445
* this in parameter initializers resolves to class
Accept baselines now that the test passes.
* Add tests for more kinds of import/export
* Fix7334 Disallow async in functionExpression and ArrowFunction (#9062)
* Error when using async modifier in function-expression and arrow-function when target es5
* Add tests and baselines
* Resolve function-this in parameter initialisers when explicitly provided
* Allow null/undefined guard with null/undefined on left
Also add a test with baselines.
* Code review comments
* Update more diagnostic messages ES6->2015
Fix #8996 CC @mhegazy.
* Fixes an issue with runtests-parallel when global mocha is not installed.
* Update LKG
* Add tests
* fix baselines
* Recommend runtests-parallel in CONTRIBUTING
* Only inlineSourceMap when debugging through jake-browser (#9080)
* Only inlineSourceMap when debugging through jake-browser
* Address PR: fix typo in opt's property
* Manually port tests from PR 8470
* minor fix: add missing return clause
* Support using string values in enums for CompilerOptions in transpile methods
* Support using string values in enums for CompilerOptions in transpile methods
# Conflicts:
# tests/cases/unittests/transpile.ts
* Fix test helper
* Add test for out-of-range error
* Fix module loading error
(commandLineOptions_stringToEnum would be undefined if optionDeclarations wasn't loaded yet)
* Use camel-case instead of snake-case (#9134)
* Manually add tests for PR 8988
* Allow wildcard ("*") patterns in ambient module declarations
* Respond to PR comments
* Add another test
* Improve perf
* Improve tests
* Update baseline from merging with master
* Address PR comment
* Update baseline
* Refactor how we retrieve binding-name cache in module transformer
* Temporary accept so we get a clean run-tests result
2016-06-14 20:36:57 +02:00
|
|
|
export type DirectoryWatcherCallback = (fileName: string) => void;
|
2016-04-22 19:20:41 +02:00
|
|
|
export interface WatchedFile {
|
|
|
|
fileName: string;
|
|
|
|
callback: FileWatcherCallback;
|
|
|
|
mtime?: Date;
|
|
|
|
}
|
2015-12-22 01:29:04 +01:00
|
|
|
|
2014-12-06 01:33:39 +01:00
|
|
|
export interface System {
|
|
|
|
args: string[];
|
|
|
|
newLine: string;
|
|
|
|
useCaseSensitiveFileNames: boolean;
|
|
|
|
write(s: string): void;
|
2015-04-09 23:18:32 +02:00
|
|
|
readFile(path: string, encoding?: string): string;
|
2016-06-18 01:40:26 +02:00
|
|
|
getFileSize?(path: string): number;
|
2015-04-09 23:18:32 +02:00
|
|
|
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
|
2016-03-23 20:49:34 +01:00
|
|
|
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
|
2016-01-08 07:48:17 +01:00
|
|
|
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
2014-12-06 01:33:39 +01:00
|
|
|
resolvePath(path: string): string;
|
|
|
|
fileExists(path: string): boolean;
|
|
|
|
directoryExists(path: string): boolean;
|
2015-04-09 23:18:32 +02:00
|
|
|
createDirectory(path: string): void;
|
2014-12-06 01:33:39 +01:00
|
|
|
getExecutingFilePath(): string;
|
|
|
|
getCurrentDirectory(): string;
|
2016-05-18 00:41:31 +02:00
|
|
|
getDirectories(path: string): string[];
|
2016-07-11 21:41:12 +02:00
|
|
|
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[];
|
2016-02-09 15:23:43 +01:00
|
|
|
getModifiedTime?(path: string): Date;
|
|
|
|
createHash?(data: string): string;
|
2015-04-09 23:18:32 +02:00
|
|
|
getMemoryUsage?(): number;
|
2014-12-06 01:33:39 +01:00
|
|
|
exit(exitCode?: number): void;
|
2016-05-05 22:38:09 +02:00
|
|
|
realpath?(path: string): string;
|
2016-03-21 19:54:10 +01:00
|
|
|
/*@internal*/ getEnvironmentVariable(name: string): string;
|
2016-02-20 01:59:57 +01:00
|
|
|
/*@internal*/ tryEnableSourceMapsForHost?(): void;
|
2014-12-06 01:33:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface FileWatcher {
|
|
|
|
close(): void;
|
|
|
|
}
|
2015-12-23 00:38:52 +01:00
|
|
|
|
2016-01-08 07:48:17 +01:00
|
|
|
export interface DirectoryWatcher extends FileWatcher {
|
2016-03-23 20:49:34 +01:00
|
|
|
directoryName: string;
|
2015-12-23 00:26:21 +01:00
|
|
|
referenceCount: number;
|
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
|
|
|
|
declare var require: any;
|
|
|
|
declare var module: any;
|
|
|
|
declare var process: any;
|
|
|
|
declare var global: any;
|
|
|
|
declare var __filename: string;
|
2015-10-01 01:10:52 +02:00
|
|
|
declare var Buffer: {
|
|
|
|
new (str: string, encoding?: string): any;
|
2015-07-24 00:18:48 +02:00
|
|
|
};
|
2014-12-06 01:33:39 +01:00
|
|
|
|
2015-01-15 22:22:23 +01:00
|
|
|
declare class Enumerator {
|
|
|
|
public atEnd(): boolean;
|
|
|
|
public moveNext(): boolean;
|
|
|
|
public item(): any;
|
|
|
|
constructor(o: any);
|
|
|
|
}
|
|
|
|
|
2015-12-02 01:18:06 +01:00
|
|
|
declare var ChakraHost: {
|
|
|
|
args: string[];
|
|
|
|
currentDirectory: string;
|
|
|
|
executingFile: string;
|
2015-12-12 01:32:44 +01:00
|
|
|
newLine?: string;
|
|
|
|
useCaseSensitiveFileNames?: boolean;
|
2015-12-02 01:18:06 +01:00
|
|
|
echo(s: string): void;
|
|
|
|
quit(exitCode?: number): void;
|
|
|
|
fileExists(path: string): boolean;
|
|
|
|
directoryExists(path: string): boolean;
|
|
|
|
createDirectory(path: string): void;
|
|
|
|
resolvePath(path: string): string;
|
|
|
|
readFile(path: string): string;
|
|
|
|
writeFile(path: string, contents: string): void;
|
2016-05-18 00:41:31 +02:00
|
|
|
getDirectories(path: string): string[];
|
2016-07-11 21:41:12 +02:00
|
|
|
readDirectory(path: string, extensions?: string[], basePaths?: string[], excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
|
2015-12-23 00:26:21 +01:00
|
|
|
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
|
2016-01-08 07:48:17 +01:00
|
|
|
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
2016-05-05 22:38:09 +02:00
|
|
|
realpath(path: string): string;
|
2016-04-08 01:13:28 +02:00
|
|
|
getEnvironmentVariable?(name: string): string;
|
2015-12-02 02:44:43 +01:00
|
|
|
};
|
2015-12-02 01:18:06 +01:00
|
|
|
|
2016-06-18 01:40:26 +02:00
|
|
|
export var sys: System = (function() {
|
2014-12-06 01:33:39 +01:00
|
|
|
|
|
|
|
function getWScriptSystem(): System {
|
|
|
|
|
2015-11-04 23:02:33 +01:00
|
|
|
const fso = new ActiveXObject("Scripting.FileSystemObject");
|
2016-07-11 21:41:12 +02:00
|
|
|
const shell = new ActiveXObject("WScript.Shell");
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2015-11-04 23:02:33 +01:00
|
|
|
const fileStream = new ActiveXObject("ADODB.Stream");
|
2014-12-06 01:33:39 +01:00
|
|
|
fileStream.Type = 2 /*text*/;
|
|
|
|
|
2015-11-04 23:02:33 +01:00
|
|
|
const binaryStream = new ActiveXObject("ADODB.Stream");
|
2014-12-06 01:33:39 +01:00
|
|
|
binaryStream.Type = 1 /*binary*/;
|
|
|
|
|
2015-11-04 23:02:33 +01:00
|
|
|
const args: string[] = [];
|
2015-07-09 02:42:26 +02:00
|
|
|
for (let i = 0; i < WScript.Arguments.length; i++) {
|
2014-12-06 01:33:39 +01:00
|
|
|
args[i] = WScript.Arguments.Item(i);
|
2014-07-16 19:49:11 +02:00
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
|
|
|
|
function readFile(fileName: string, encoding?: string): string {
|
|
|
|
if (!fso.FileExists(fileName)) {
|
|
|
|
return undefined;
|
2014-07-16 19:49:11 +02:00
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
fileStream.Open();
|
|
|
|
try {
|
|
|
|
if (encoding) {
|
|
|
|
fileStream.Charset = encoding;
|
|
|
|
fileStream.LoadFromFile(fileName);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Load file and read the first two bytes into a string with no interpretation
|
|
|
|
fileStream.Charset = "x-ansi";
|
|
|
|
fileStream.LoadFromFile(fileName);
|
2015-11-04 23:02:33 +01:00
|
|
|
const bom = fileStream.ReadText(2) || "";
|
2014-12-06 01:33:39 +01:00
|
|
|
// Position must be at 0 before encoding can be changed
|
|
|
|
fileStream.Position = 0;
|
|
|
|
// [0xFF,0xFE] and [0xFE,0xFF] mean utf-16 (little or big endian), otherwise default to utf-8
|
|
|
|
fileStream.Charset = bom.length >= 2 && (bom.charCodeAt(0) === 0xFF && bom.charCodeAt(1) === 0xFE || bom.charCodeAt(0) === 0xFE && bom.charCodeAt(1) === 0xFF) ? "unicode" : "utf-8";
|
|
|
|
}
|
|
|
|
// ReadText method always strips byte order mark from resulting string
|
|
|
|
return fileStream.ReadText();
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
fileStream.Close();
|
2014-07-14 19:45:24 +02:00
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-12-06 01:33:39 +01:00
|
|
|
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
|
|
|
|
fileStream.Open();
|
|
|
|
binaryStream.Open();
|
|
|
|
try {
|
|
|
|
// Write characters in UTF-8 encoding
|
|
|
|
fileStream.Charset = "utf-8";
|
|
|
|
fileStream.WriteText(data);
|
|
|
|
// If we don't want the BOM, then skip it by setting the starting location to 3 (size of BOM).
|
|
|
|
// If not, start from position 0, as the BOM will be added automatically when charset==utf8.
|
|
|
|
if (writeByteOrderMark) {
|
|
|
|
fileStream.Position = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fileStream.Position = 3;
|
|
|
|
}
|
|
|
|
fileStream.CopyTo(binaryStream);
|
|
|
|
binaryStream.SaveToFile(fileName, 2 /*overwrite*/);
|
2014-08-06 20:32:51 +02:00
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
finally {
|
|
|
|
binaryStream.Close();
|
|
|
|
fileStream.Close();
|
2014-08-06 20:32:51 +02:00
|
|
|
}
|
2014-07-14 19:45:24 +02:00
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2015-10-01 01:10:52 +02:00
|
|
|
function getNames(collection: any): string[] {
|
2015-11-04 23:02:33 +01:00
|
|
|
const result: string[] = [];
|
2015-07-09 02:42:26 +02:00
|
|
|
for (let e = new Enumerator(collection); !e.atEnd(); e.moveNext()) {
|
2015-01-15 22:22:23 +01:00
|
|
|
result.push(e.item().Name);
|
|
|
|
}
|
|
|
|
return result.sort();
|
|
|
|
}
|
|
|
|
|
2016-05-18 00:41:31 +02:00
|
|
|
function getDirectories(path: string): string[] {
|
|
|
|
const folder = fso.GetFolder(path);
|
|
|
|
return getNames(folder.subfolders);
|
|
|
|
}
|
|
|
|
|
2016-07-11 21:41:12 +02:00
|
|
|
function getAccessibleFileSystemEntries(path: string): FileSystemEntries {
|
|
|
|
try {
|
2015-11-04 23:02:33 +01:00
|
|
|
const folder = fso.GetFolder(path || ".");
|
|
|
|
const files = getNames(folder.files);
|
2016-07-11 21:41:12 +02:00
|
|
|
const directories = getNames(folder.subfolders);
|
|
|
|
return { files, directories };
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
return { files: [], directories: [] };
|
2015-01-15 22:22:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-11 21:41:12 +02:00
|
|
|
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[]): string[] {
|
|
|
|
return matchFiles(path, extensions, excludes, includes, /*useCaseSensitiveFileNames*/ false, shell.CurrentDirectory, getAccessibleFileSystemEntries);
|
|
|
|
}
|
|
|
|
|
2016-07-11 20:30:22 +02:00
|
|
|
const wscriptSystem: System = {
|
2014-12-06 01:33:39 +01:00
|
|
|
args,
|
|
|
|
newLine: "\r\n",
|
|
|
|
useCaseSensitiveFileNames: false,
|
|
|
|
write(s: string): void {
|
|
|
|
WScript.StdOut.Write(s);
|
|
|
|
},
|
|
|
|
readFile,
|
|
|
|
writeFile,
|
|
|
|
resolvePath(path: string): string {
|
|
|
|
return fso.GetAbsolutePathName(path);
|
|
|
|
},
|
|
|
|
fileExists(path: string): boolean {
|
|
|
|
return fso.FileExists(path);
|
|
|
|
},
|
|
|
|
directoryExists(path: string) {
|
|
|
|
return fso.FolderExists(path);
|
|
|
|
},
|
|
|
|
createDirectory(directoryName: string) {
|
2016-07-11 20:30:22 +02:00
|
|
|
if (!wscriptSystem.directoryExists(directoryName)) {
|
2014-12-06 01:33:39 +01:00
|
|
|
fso.CreateFolder(directoryName);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
getExecutingFilePath() {
|
|
|
|
return WScript.ScriptFullName;
|
|
|
|
},
|
|
|
|
getCurrentDirectory() {
|
2016-07-11 21:41:12 +02:00
|
|
|
return shell.CurrentDirectory;
|
2014-12-06 01:33:39 +01:00
|
|
|
},
|
2016-05-18 00:41:31 +02:00
|
|
|
getDirectories,
|
2016-03-21 19:54:10 +01:00
|
|
|
getEnvironmentVariable(name: string) {
|
|
|
|
return new ActiveXObject("WScript.Shell").ExpandEnvironmentStrings(`%${name}%`);
|
|
|
|
},
|
2015-01-15 22:22:23 +01:00
|
|
|
readDirectory,
|
2014-12-06 01:33:39 +01:00
|
|
|
exit(exitCode?: number): void {
|
|
|
|
try {
|
|
|
|
WScript.Quit(exitCode);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
};
|
2016-07-11 20:30:22 +02:00
|
|
|
return wscriptSystem;
|
2014-12-06 01:33:39 +01:00
|
|
|
}
|
2015-12-02 02:44:43 +01:00
|
|
|
|
2014-12-06 01:33:39 +01:00
|
|
|
function getNodeSystem(): System {
|
2015-07-24 00:18:48 +02:00
|
|
|
const _fs = require("fs");
|
|
|
|
const _path = require("path");
|
2015-07-24 02:30:31 +02:00
|
|
|
const _os = require("os");
|
2016-02-06 09:51:25 +01:00
|
|
|
const _crypto = require("crypto");
|
2014-12-06 01:33:39 +01:00
|
|
|
|
2016-04-22 19:20:41 +02:00
|
|
|
const useNonPollingWatchers = process.env["TSC_NONPOLLING_WATCHER"];
|
2015-12-11 02:59:07 +01:00
|
|
|
|
2015-12-10 01:21:04 +01:00
|
|
|
function createWatchedFileSet() {
|
2016-03-23 20:49:34 +01:00
|
|
|
const dirWatchers: Map<DirectoryWatcher> = {};
|
2015-12-28 23:05:32 +01:00
|
|
|
// One file can have multiple watchers
|
2016-03-23 20:49:34 +01:00
|
|
|
const fileWatcherCallbacks: Map<FileWatcherCallback[]> = {};
|
2016-01-11 20:35:46 +01:00
|
|
|
return { addFile, removeFile };
|
2015-12-23 00:26:21 +01:00
|
|
|
|
2016-03-23 20:49:34 +01:00
|
|
|
function reduceDirWatcherRefCountForFile(fileName: string) {
|
|
|
|
const dirName = getDirectoryPath(fileName);
|
|
|
|
if (hasProperty(dirWatchers, dirName)) {
|
|
|
|
const watcher = dirWatchers[dirName];
|
2016-01-13 23:02:34 +01:00
|
|
|
watcher.referenceCount -= 1;
|
|
|
|
if (watcher.referenceCount <= 0) {
|
|
|
|
watcher.close();
|
2016-03-23 20:49:34 +01:00
|
|
|
delete dirWatchers[dirName];
|
2016-01-13 23:02:34 +01:00
|
|
|
}
|
2015-12-23 00:26:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-23 20:49:34 +01:00
|
|
|
function addDirWatcher(dirPath: string): void {
|
|
|
|
if (hasProperty(dirWatchers, dirPath)) {
|
|
|
|
const watcher = dirWatchers[dirPath];
|
2016-01-11 20:35:46 +01:00
|
|
|
watcher.referenceCount += 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const watcher: DirectoryWatcher = _fs.watch(
|
2016-01-12 09:17:38 +01:00
|
|
|
dirPath,
|
|
|
|
{ persistent: true },
|
2016-01-11 20:35:46 +01:00
|
|
|
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
|
|
|
|
);
|
|
|
|
watcher.referenceCount = 1;
|
2016-03-23 20:49:34 +01:00
|
|
|
dirWatchers[dirPath] = watcher;
|
2016-01-11 20:35:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2015-12-23 00:26:21 +01:00
|
|
|
|
2016-03-23 20:49:34 +01:00
|
|
|
function addFileWatcherCallback(filePath: string, callback: FileWatcherCallback): void {
|
|
|
|
if (hasProperty(fileWatcherCallbacks, filePath)) {
|
|
|
|
fileWatcherCallbacks[filePath].push(callback);
|
2015-12-23 00:38:52 +01:00
|
|
|
}
|
|
|
|
else {
|
2016-03-23 20:49:34 +01:00
|
|
|
fileWatcherCallbacks[filePath] = [callback];
|
2015-12-23 00:26:21 +01:00
|
|
|
}
|
|
|
|
}
|
2015-12-11 02:59:07 +01:00
|
|
|
|
2016-03-23 20:49:34 +01:00
|
|
|
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
|
|
|
|
addFileWatcherCallback(fileName, callback);
|
|
|
|
addDirWatcher(getDirectoryPath(fileName));
|
2015-12-28 23:05:32 +01:00
|
|
|
|
2016-03-23 20:49:34 +01:00
|
|
|
return { fileName, callback };
|
2015-12-10 01:21:04 +01:00
|
|
|
}
|
2015-12-11 02:59:07 +01:00
|
|
|
|
2016-01-11 20:35:46 +01:00
|
|
|
function removeFile(watchedFile: WatchedFile) {
|
2016-03-23 20:49:34 +01:00
|
|
|
removeFileWatcherCallback(watchedFile.fileName, watchedFile.callback);
|
|
|
|
reduceDirWatcherRefCountForFile(watchedFile.fileName);
|
2016-01-13 23:02:34 +01:00
|
|
|
}
|
|
|
|
|
2016-03-23 20:49:34 +01:00
|
|
|
function removeFileWatcherCallback(filePath: string, callback: FileWatcherCallback) {
|
|
|
|
if (hasProperty(fileWatcherCallbacks, filePath)) {
|
|
|
|
const newCallbacks = copyListRemovingItem(callback, fileWatcherCallbacks[filePath]);
|
2015-12-28 23:05:32 +01:00
|
|
|
if (newCallbacks.length === 0) {
|
2016-03-23 20:49:34 +01:00
|
|
|
delete fileWatcherCallbacks[filePath];
|
2015-12-28 23:05:32 +01:00
|
|
|
}
|
|
|
|
else {
|
2016-03-23 20:49:34 +01:00
|
|
|
fileWatcherCallbacks[filePath] = newCallbacks;
|
2015-12-28 23:05:32 +01:00
|
|
|
}
|
2015-12-15 17:39:51 +01:00
|
|
|
}
|
2015-12-10 01:21:04 +01:00
|
|
|
}
|
2015-12-11 02:59:07 +01:00
|
|
|
|
2016-03-23 20:49:34 +01:00
|
|
|
function fileEventHandler(eventName: string, relativeFileName: string, baseDirPath: string) {
|
2015-12-23 00:26:21 +01:00
|
|
|
// When files are deleted from disk, the triggered "rename" event would have a relativefileName of "undefined"
|
2016-03-23 20:49:34 +01:00
|
|
|
const fileName = typeof relativeFileName !== "string"
|
2016-01-15 23:58:04 +01:00
|
|
|
? undefined
|
2016-03-23 20:49:34 +01:00
|
|
|
: ts.getNormalizedAbsolutePath(relativeFileName, baseDirPath);
|
2016-02-12 03:47:56 +01:00
|
|
|
// Some applications save a working file via rename operations
|
2016-03-23 20:49:34 +01:00
|
|
|
if ((eventName === "change" || eventName === "rename") && hasProperty(fileWatcherCallbacks, fileName)) {
|
|
|
|
for (const fileCallback of fileWatcherCallbacks[fileName]) {
|
|
|
|
fileCallback(fileName);
|
2015-12-28 23:05:32 +01:00
|
|
|
}
|
2015-12-10 01:21:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-15 17:39:51 +01:00
|
|
|
const watchedFileSet = createWatchedFileSet();
|
2015-10-02 00:25:43 +02:00
|
|
|
|
2015-12-23 01:00:49 +01:00
|
|
|
function isNode4OrLater(): boolean {
|
2016-04-19 23:25:57 +02:00
|
|
|
return parseInt(process.version.charAt(1)) >= 4;
|
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
|
2015-07-24 00:18:48 +02:00
|
|
|
const platform: string = _os.platform();
|
2014-12-06 01:33:39 +01:00
|
|
|
// win32\win64 are case insensitive platforms, MacOS (darwin) by default is also case insensitive
|
2015-07-24 00:18:48 +02:00
|
|
|
const useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin";
|
2014-12-06 01:33:39 +01:00
|
|
|
|
|
|
|
function readFile(fileName: string, encoding?: string): string {
|
2016-02-12 01:59:54 +01:00
|
|
|
if (!fileExists(fileName)) {
|
2014-12-06 01:33:39 +01:00
|
|
|
return undefined;
|
2014-07-25 20:01:09 +02:00
|
|
|
}
|
2015-11-04 23:02:33 +01:00
|
|
|
const buffer = _fs.readFileSync(fileName);
|
2015-07-09 02:42:26 +02:00
|
|
|
let len = buffer.length;
|
2014-12-06 01:33:39 +01:00
|
|
|
if (len >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) {
|
|
|
|
// Big endian UTF-16 byte order mark detected. Since big endian is not supported by node.js,
|
|
|
|
// flip all byte pairs and treat as little endian.
|
|
|
|
len &= ~1;
|
2015-07-09 02:42:26 +02:00
|
|
|
for (let i = 0; i < len; i += 2) {
|
2015-11-04 23:02:33 +01:00
|
|
|
const temp = buffer[i];
|
2014-12-06 01:33:39 +01:00
|
|
|
buffer[i] = buffer[i + 1];
|
|
|
|
buffer[i + 1] = temp;
|
|
|
|
}
|
|
|
|
return buffer.toString("utf16le", 2);
|
2014-07-25 20:01:09 +02:00
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
if (len >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) {
|
|
|
|
// Little endian UTF-16 byte order mark detected
|
|
|
|
return buffer.toString("utf16le", 2);
|
2014-07-14 19:45:24 +02:00
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
if (len >= 3 && buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
|
|
|
|
// UTF-8 byte order mark detected
|
|
|
|
return buffer.toString("utf8", 3);
|
|
|
|
}
|
|
|
|
// Default is UTF-8 with no byte order mark
|
|
|
|
return buffer.toString("utf8");
|
2014-07-14 19:45:24 +02:00
|
|
|
}
|
2014-07-16 19:49:11 +02:00
|
|
|
|
2014-12-06 01:33:39 +01:00
|
|
|
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
|
|
|
|
// If a BOM is required, emit one
|
|
|
|
if (writeByteOrderMark) {
|
2015-07-24 02:30:31 +02:00
|
|
|
data = "\uFEFF" + data;
|
2014-12-06 01:33:39 +01:00
|
|
|
}
|
2014-08-06 20:32:51 +02:00
|
|
|
|
2015-10-29 19:13:54 +01:00
|
|
|
let fd: number;
|
|
|
|
|
|
|
|
try {
|
|
|
|
fd = _fs.openSync(fileName, "w");
|
|
|
|
_fs.writeSync(fd, data, undefined, "utf8");
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
if (fd !== undefined) {
|
|
|
|
_fs.closeSync(fd);
|
|
|
|
}
|
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2016-07-11 21:41:12 +02:00
|
|
|
function getAccessibleFileSystemEntries(path: string): FileSystemEntries {
|
|
|
|
try {
|
|
|
|
const entries = _fs.readdirSync(path || ".").sort();
|
|
|
|
const files: string[] = [];
|
|
|
|
const directories: string[] = [];
|
|
|
|
for (const entry of entries) {
|
|
|
|
// This is necessary because on some file system node fails to exclude
|
|
|
|
// "." and "..". See https://github.com/nodejs/node/issues/4002
|
|
|
|
if (entry === "." || entry === "..") {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const name = combinePaths(path, entry);
|
|
|
|
|
|
|
|
let stat: any;
|
|
|
|
try {
|
|
|
|
stat = _fs.statSync(name);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stat.isFile()) {
|
|
|
|
files.push(entry);
|
|
|
|
}
|
|
|
|
else if (stat.isDirectory()) {
|
|
|
|
directories.push(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return { files, directories };
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
return { files: [], directories: [] };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[]): string[] {
|
|
|
|
return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), getAccessibleFileSystemEntries);
|
2015-05-16 20:38:28 +02:00
|
|
|
}
|
|
|
|
|
2016-02-12 01:59:54 +01:00
|
|
|
const enum FileSystemEntryKind {
|
|
|
|
File,
|
|
|
|
Directory
|
|
|
|
}
|
2016-02-12 02:29:01 +01:00
|
|
|
|
2016-02-12 01:59:54 +01:00
|
|
|
function fileSystemEntryExists(path: string, entryKind: FileSystemEntryKind): boolean {
|
|
|
|
try {
|
|
|
|
const stat = _fs.statSync(path);
|
|
|
|
switch (entryKind) {
|
|
|
|
case FileSystemEntryKind.File: return stat.isFile();
|
|
|
|
case FileSystemEntryKind.Directory: return stat.isDirectory();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function fileExists(path: string): boolean {
|
|
|
|
return fileSystemEntryExists(path, FileSystemEntryKind.File);
|
|
|
|
}
|
|
|
|
|
|
|
|
function directoryExists(path: string): boolean {
|
|
|
|
return fileSystemEntryExists(path, FileSystemEntryKind.Directory);
|
|
|
|
}
|
|
|
|
|
2016-05-18 00:41:31 +02:00
|
|
|
function getDirectories(path: string): string[] {
|
2016-05-24 01:20:13 +02:00
|
|
|
return filter<string>(_fs.readdirSync(path), p => fileSystemEntryExists(combinePaths(path, p), FileSystemEntryKind.Directory));
|
2016-05-18 00:41:31 +02:00
|
|
|
}
|
|
|
|
|
2016-07-11 20:30:22 +02:00
|
|
|
const nodeSystem: System = {
|
2014-12-06 01:33:39 +01:00
|
|
|
args: process.argv.slice(2),
|
|
|
|
newLine: _os.EOL,
|
|
|
|
useCaseSensitiveFileNames: useCaseSensitiveFileNames,
|
2015-10-06 08:37:50 +02:00
|
|
|
write(s: string): void {
|
2015-07-24 21:18:18 +02:00
|
|
|
process.stdout.write(s);
|
2014-12-06 01:33:39 +01:00
|
|
|
},
|
|
|
|
readFile,
|
|
|
|
writeFile,
|
2016-03-23 20:49:34 +01:00
|
|
|
watchFile: (fileName, callback) => {
|
2016-04-22 19:20:41 +02:00
|
|
|
if (useNonPollingWatchers) {
|
|
|
|
const watchedFile = watchedFileSet.addFile(fileName, callback);
|
|
|
|
return {
|
|
|
|
close: () => watchedFileSet.removeFile(watchedFile)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
_fs.watchFile(fileName, { persistent: true, interval: 250 }, fileChanged);
|
|
|
|
return {
|
|
|
|
close: () => _fs.unwatchFile(fileName, fileChanged)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function fileChanged(curr: any, prev: any) {
|
|
|
|
if (+curr.mtime <= +prev.mtime) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
callback(fileName);
|
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
},
|
2016-03-23 20:49:34 +01:00
|
|
|
watchDirectory: (directoryName, callback, recursive) => {
|
2016-01-11 20:35:46 +01:00
|
|
|
// 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(
|
2016-03-23 20:49:34 +01:00
|
|
|
directoryName,
|
2016-01-11 20:35:46 +01:00
|
|
|
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
|
2016-03-23 20:49:34 +01:00
|
|
|
callback(!relativeFileName ? relativeFileName : normalizePath(combinePaths(directoryName, relativeFileName)));
|
2016-01-11 20:35:46 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
);
|
2014-12-06 01:33:39 +01:00
|
|
|
},
|
2016-06-18 01:40:26 +02:00
|
|
|
resolvePath: function(path: string): string {
|
2014-12-06 01:33:39 +01:00
|
|
|
return _path.resolve(path);
|
|
|
|
},
|
2016-02-12 01:59:54 +01:00
|
|
|
fileExists,
|
|
|
|
directoryExists,
|
2014-12-06 01:33:39 +01:00
|
|
|
createDirectory(directoryName: string) {
|
2016-07-11 20:30:22 +02:00
|
|
|
if (!nodeSystem.directoryExists(directoryName)) {
|
2014-12-06 01:33:39 +01:00
|
|
|
_fs.mkdirSync(directoryName);
|
2014-08-01 06:58:05 +02:00
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
},
|
|
|
|
getExecutingFilePath() {
|
|
|
|
return __filename;
|
|
|
|
},
|
|
|
|
getCurrentDirectory() {
|
|
|
|
return process.cwd();
|
|
|
|
},
|
2016-05-18 00:41:31 +02:00
|
|
|
getDirectories,
|
2016-03-21 19:54:10 +01:00
|
|
|
getEnvironmentVariable(name: string) {
|
|
|
|
return process.env[name] || "";
|
|
|
|
},
|
2015-01-15 22:22:23 +01:00
|
|
|
readDirectory,
|
2016-02-09 15:23:43 +01:00
|
|
|
getModifiedTime(path) {
|
2016-02-10 01:47:52 +01:00
|
|
|
try {
|
|
|
|
return _fs.statSync(path).mtime;
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
return undefined;
|
|
|
|
}
|
2016-02-09 15:23:43 +01:00
|
|
|
},
|
|
|
|
createHash(data) {
|
2016-02-10 01:50:22 +01:00
|
|
|
const hash = _crypto.createHash("md5");
|
2016-02-09 15:23:43 +01:00
|
|
|
hash.update(data);
|
|
|
|
return hash.digest("hex");
|
|
|
|
},
|
2014-12-06 01:33:39 +01:00
|
|
|
getMemoryUsage() {
|
|
|
|
if (global.gc) {
|
|
|
|
global.gc();
|
|
|
|
}
|
|
|
|
return process.memoryUsage().heapUsed;
|
|
|
|
},
|
2016-06-18 01:40:26 +02:00
|
|
|
getFileSize(path) {
|
|
|
|
try {
|
|
|
|
const stat = _fs.statSync(path);
|
|
|
|
if (stat.isFile()) {
|
|
|
|
return stat.size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (e) { }
|
|
|
|
return 0;
|
|
|
|
},
|
2014-12-06 01:33:39 +01:00
|
|
|
exit(exitCode?: number): void {
|
|
|
|
process.exit(exitCode);
|
2016-02-20 01:59:57 +01:00
|
|
|
},
|
2016-05-05 22:38:09 +02:00
|
|
|
realpath(path: string): string {
|
|
|
|
return _fs.realpathSync(path);
|
2016-05-25 23:14:32 +02:00
|
|
|
},
|
2016-02-20 01:59:57 +01:00
|
|
|
tryEnableSourceMapsForHost() {
|
|
|
|
try {
|
|
|
|
require("source-map-support").install();
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
// Could not enable source maps.
|
|
|
|
}
|
2014-08-14 19:52:24 +02:00
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
};
|
2016-07-11 20:30:22 +02:00
|
|
|
return nodeSystem;
|
2014-12-06 01:33:39 +01:00
|
|
|
}
|
2015-12-02 02:44:43 +01:00
|
|
|
|
2015-12-02 01:18:06 +01:00
|
|
|
function getChakraSystem(): System {
|
2016-05-05 22:38:09 +02:00
|
|
|
const realpath = ChakraHost.realpath && ((path: string) => ChakraHost.realpath(path));
|
2015-12-02 01:18:06 +01:00
|
|
|
return {
|
2015-12-12 01:19:08 +01:00
|
|
|
newLine: ChakraHost.newLine || "\r\n",
|
2015-12-02 01:18:06 +01:00
|
|
|
args: ChakraHost.args,
|
2015-12-12 01:19:08 +01:00
|
|
|
useCaseSensitiveFileNames: !!ChakraHost.useCaseSensitiveFileNames,
|
2015-12-02 20:49:54 +01:00
|
|
|
write: ChakraHost.echo,
|
2015-12-02 01:18:06 +01:00
|
|
|
readFile(path: string, encoding?: string) {
|
|
|
|
// encoding is automatically handled by the implementation in ChakraHost
|
|
|
|
return ChakraHost.readFile(path);
|
|
|
|
},
|
|
|
|
writeFile(path: string, data: string, writeByteOrderMark?: boolean) {
|
|
|
|
// If a BOM is required, emit one
|
|
|
|
if (writeByteOrderMark) {
|
|
|
|
data = "\uFEFF" + data;
|
|
|
|
}
|
|
|
|
|
|
|
|
ChakraHost.writeFile(path, data);
|
|
|
|
},
|
2015-12-02 20:49:54 +01:00
|
|
|
resolvePath: ChakraHost.resolvePath,
|
|
|
|
fileExists: ChakraHost.fileExists,
|
|
|
|
directoryExists: ChakraHost.directoryExists,
|
|
|
|
createDirectory: ChakraHost.createDirectory,
|
|
|
|
getExecutingFilePath: () => ChakraHost.executingFile,
|
|
|
|
getCurrentDirectory: () => ChakraHost.currentDirectory,
|
2016-05-18 00:41:31 +02:00
|
|
|
getDirectories: ChakraHost.getDirectories,
|
2016-04-08 01:13:28 +02:00
|
|
|
getEnvironmentVariable: ChakraHost.getEnvironmentVariable || ((name: string) => ""),
|
2016-07-11 21:41:12 +02:00
|
|
|
readDirectory: (path: string, extensions?: string[], excludes?: string[], includes?: string[]) => {
|
|
|
|
const pattern = getFileMatcherPatterns(path, extensions, excludes, includes, !!ChakraHost.useCaseSensitiveFileNames, ChakraHost.currentDirectory);
|
|
|
|
return ChakraHost.readDirectory(path, extensions, pattern.basePaths, pattern.excludePattern, pattern.includeFilePattern, pattern.includeDirectoryPattern);
|
|
|
|
},
|
2015-12-02 20:49:54 +01:00
|
|
|
exit: ChakraHost.quit,
|
2016-05-05 22:38:09 +02:00
|
|
|
realpath
|
2015-12-02 01:18:06 +01:00
|
|
|
};
|
|
|
|
}
|
2015-12-02 02:44:43 +01:00
|
|
|
|
2016-04-10 13:07:47 +02:00
|
|
|
if (typeof ChakraHost !== "undefined") {
|
|
|
|
return getChakraSystem();
|
|
|
|
}
|
|
|
|
else if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") {
|
2014-12-06 01:33:39 +01:00
|
|
|
return getWScriptSystem();
|
|
|
|
}
|
2015-08-15 05:53:38 +02:00
|
|
|
else if (typeof process !== "undefined" && process.nextTick && !process.browser && typeof require !== "undefined") {
|
2015-08-13 22:14:38 +02:00
|
|
|
// process and process.nextTick checks if current environment is node-like
|
|
|
|
// process.browser check excludes webpack and browserify
|
2014-12-06 01:33:39 +01:00
|
|
|
return getNodeSystem();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return undefined; // Unsupported host
|
|
|
|
}
|
|
|
|
})();
|
2015-07-09 02:42:26 +02:00
|
|
|
}
|