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 {
|
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;
|
|
|
|
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
|
2015-10-06 01:19:09 +02:00
|
|
|
watchFile?(path: string, callback: (path: string, removed?: boolean) => void): FileWatcher;
|
2015-10-02 20:49:30 +02:00
|
|
|
watchDirectory?(path: string, callback: (path: string) => void, 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;
|
2015-05-16 20:38:28 +02:00
|
|
|
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
|
2015-04-09 23:18:32 +02:00
|
|
|
getMemoryUsage?(): number;
|
2014-12-06 01:33:39 +01:00
|
|
|
exit(exitCode?: number): void;
|
|
|
|
}
|
|
|
|
|
2015-10-02 00:40:13 +02:00
|
|
|
interface WatchedFile {
|
|
|
|
fileName: string;
|
2015-10-06 01:19:09 +02:00
|
|
|
callback: (fileName: string, removed?: boolean) => void;
|
2015-10-02 00:40:13 +02:00
|
|
|
mtime: Date;
|
|
|
|
}
|
|
|
|
|
2014-12-06 01:33:39 +01:00
|
|
|
export interface FileWatcher {
|
|
|
|
close(): void;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-12-06 01:33:39 +01:00
|
|
|
export var sys: System = (function () {
|
|
|
|
|
|
|
|
function getWScriptSystem(): System {
|
|
|
|
|
2015-11-04 23:02:33 +01:00
|
|
|
const fso = new ActiveXObject("Scripting.FileSystemObject");
|
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-05-16 20:38:28 +02:00
|
|
|
function getCanonicalPath(path: string): string {
|
|
|
|
return path.toLowerCase();
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2015-05-16 20:38:28 +02:00
|
|
|
function readDirectory(path: string, extension?: string, exclude?: string[]): string[] {
|
2015-11-04 23:02:33 +01:00
|
|
|
const result: string[] = [];
|
2015-05-16 20:38:28 +02:00
|
|
|
exclude = map(exclude, s => getCanonicalPath(combinePaths(path, s)));
|
2015-01-15 22:22:23 +01:00
|
|
|
visitDirectory(path);
|
|
|
|
return result;
|
|
|
|
function visitDirectory(path: string) {
|
2015-11-04 23:02:33 +01:00
|
|
|
const folder = fso.GetFolder(path || ".");
|
|
|
|
const files = getNames(folder.files);
|
|
|
|
for (const current of files) {
|
|
|
|
const name = combinePaths(path, current);
|
2015-05-16 20:38:28 +02:00
|
|
|
if ((!extension || fileExtensionIs(name, extension)) && !contains(exclude, getCanonicalPath(name))) {
|
|
|
|
result.push(name);
|
2015-01-15 22:22:23 +01:00
|
|
|
}
|
|
|
|
}
|
2015-11-04 23:02:33 +01:00
|
|
|
const subfolders = getNames(folder.subfolders);
|
|
|
|
for (const current of subfolders) {
|
|
|
|
const name = combinePaths(path, current);
|
2015-05-16 20:38:28 +02:00
|
|
|
if (!contains(exclude, getCanonicalPath(name))) {
|
|
|
|
visitDirectory(name);
|
|
|
|
}
|
2015-01-15 22:22:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-06 01:33:39 +01:00
|
|
|
return {
|
|
|
|
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) {
|
|
|
|
if (!this.directoryExists(directoryName)) {
|
|
|
|
fso.CreateFolder(directoryName);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
getExecutingFilePath() {
|
|
|
|
return WScript.ScriptFullName;
|
|
|
|
},
|
|
|
|
getCurrentDirectory() {
|
|
|
|
return new ActiveXObject("WScript.Shell").CurrentDirectory;
|
|
|
|
},
|
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
|
|
|
};
|
|
|
|
}
|
|
|
|
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");
|
2015-08-18 10:25:00 +02:00
|
|
|
const _tty = require("tty");
|
2014-12-06 01:33:39 +01:00
|
|
|
|
2015-10-15 00:10:05 +02:00
|
|
|
// average async stat takes about 30 microseconds
|
|
|
|
// set chunk size to do 30 files in < 1 millisecond
|
|
|
|
function createWatchedFileSet(interval = 2500, chunkSize = 30) {
|
|
|
|
let watchedFiles: WatchedFile[] = [];
|
|
|
|
let nextFileToCheck = 0;
|
|
|
|
let watchTimer: any;
|
|
|
|
|
|
|
|
function getModifiedTime(fileName: string): Date {
|
2015-10-02 00:40:13 +02:00
|
|
|
return _fs.statSync(fileName).mtime;
|
|
|
|
}
|
|
|
|
|
2015-10-15 00:10:05 +02:00
|
|
|
function poll(checkedIndex: number) {
|
2015-11-04 23:02:33 +01:00
|
|
|
const watchedFile = watchedFiles[checkedIndex];
|
2015-10-02 00:40:13 +02:00
|
|
|
if (!watchedFile) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_fs.stat(watchedFile.fileName, (err: any, stats: any) => {
|
|
|
|
if (err) {
|
|
|
|
watchedFile.callback(watchedFile.fileName);
|
|
|
|
}
|
|
|
|
else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) {
|
2015-10-15 00:10:05 +02:00
|
|
|
watchedFile.mtime = getModifiedTime(watchedFile.fileName);
|
2015-10-06 01:19:09 +02:00
|
|
|
watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0);
|
2015-10-02 00:40:13 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// this implementation uses polling and
|
|
|
|
// stat due to inconsistencies of fs.watch
|
|
|
|
// and efficiency of stat on modern filesystems
|
2015-10-15 00:10:05 +02:00
|
|
|
function startWatchTimer() {
|
|
|
|
watchTimer = setInterval(() => {
|
2015-10-06 21:33:06 +02:00
|
|
|
let count = 0;
|
2015-10-15 00:10:05 +02:00
|
|
|
let nextToCheck = nextFileToCheck;
|
2015-10-06 21:33:06 +02:00
|
|
|
let firstCheck = -1;
|
2015-10-15 00:10:05 +02:00
|
|
|
while ((count < chunkSize) && (nextToCheck !== firstCheck)) {
|
|
|
|
poll(nextToCheck);
|
2015-10-02 00:40:13 +02:00
|
|
|
if (firstCheck < 0) {
|
|
|
|
firstCheck = nextToCheck;
|
|
|
|
}
|
|
|
|
nextToCheck++;
|
2015-10-15 00:10:05 +02:00
|
|
|
if (nextToCheck === watchedFiles.length) {
|
2015-10-02 00:40:13 +02:00
|
|
|
nextToCheck = 0;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
}
|
2015-10-15 00:10:05 +02:00
|
|
|
nextFileToCheck = nextToCheck;
|
|
|
|
}, interval);
|
2015-10-02 00:40:13 +02:00
|
|
|
}
|
|
|
|
|
2015-10-15 00:10:05 +02:00
|
|
|
function addFile(fileName: string, callback: (fileName: string, removed?: boolean) => void): WatchedFile {
|
2015-11-04 23:02:33 +01:00
|
|
|
const file: WatchedFile = {
|
2015-10-02 00:40:13 +02:00
|
|
|
fileName,
|
|
|
|
callback,
|
2015-10-15 00:10:05 +02:00
|
|
|
mtime: getModifiedTime(fileName)
|
2015-10-02 00:40:13 +02:00
|
|
|
};
|
|
|
|
|
2015-10-15 00:10:05 +02:00
|
|
|
watchedFiles.push(file);
|
|
|
|
if (watchedFiles.length === 1) {
|
|
|
|
startWatchTimer();
|
2015-10-02 00:40:13 +02:00
|
|
|
}
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
2015-10-15 00:10:05 +02:00
|
|
|
function removeFile(file: WatchedFile) {
|
|
|
|
watchedFiles = copyListRemovingItem(file, watchedFiles);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
getModifiedTime: getModifiedTime,
|
|
|
|
poll: poll,
|
|
|
|
startWatchTimer: startWatchTimer,
|
|
|
|
addFile: addFile,
|
|
|
|
removeFile: removeFile
|
2015-10-15 01:57:08 +02:00
|
|
|
};
|
2015-10-02 00:40:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// REVIEW: for now this implementation uses polling.
|
|
|
|
// The advantage of polling is that it works reliably
|
|
|
|
// on all os and with network mounted files.
|
|
|
|
// For 90 referenced files, the average time to detect
|
|
|
|
// changes is 2*msInterval (by default 5 seconds).
|
|
|
|
// The overhead of this is .04 percent (1/2500) with
|
|
|
|
// average pause of < 1 millisecond (and max
|
|
|
|
// pause less than 1.5 milliseconds); question is
|
|
|
|
// do we anticipate reference sets in the 100s and
|
|
|
|
// do we care about waiting 10-20 seconds to detect
|
|
|
|
// changes for large reference sets? If so, do we want
|
|
|
|
// to increase the chunk size or decrease the interval
|
|
|
|
// time dynamically to match the large reference set?
|
2015-11-04 23:02:33 +01:00
|
|
|
const watchedFileSet = createWatchedFileSet();
|
2015-10-02 00:25:43 +02:00
|
|
|
|
|
|
|
function isNode4OrLater(): Boolean {
|
2015-10-02 00:59:03 +02:00
|
|
|
return parseInt(process.version.charAt(1)) >= 4;
|
2015-10-02 00:25:43 +02:00
|
|
|
}
|
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 {
|
|
|
|
if (!_fs.existsSync(fileName)) {
|
|
|
|
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
|
|
|
|
2015-05-16 20:38:28 +02:00
|
|
|
function getCanonicalPath(path: string): string {
|
|
|
|
return useCaseSensitiveFileNames ? path.toLowerCase() : path;
|
|
|
|
}
|
|
|
|
|
|
|
|
function readDirectory(path: string, extension?: string, exclude?: string[]): string[] {
|
2015-11-04 23:02:33 +01:00
|
|
|
const result: string[] = [];
|
2015-05-16 20:38:28 +02:00
|
|
|
exclude = map(exclude, s => getCanonicalPath(combinePaths(path, s)));
|
2015-01-15 22:22:23 +01:00
|
|
|
visitDirectory(path);
|
|
|
|
return result;
|
|
|
|
function visitDirectory(path: string) {
|
2015-11-04 23:02:33 +01:00
|
|
|
const files = _fs.readdirSync(path || ".").sort();
|
|
|
|
const directories: string[] = [];
|
|
|
|
for (const current of files) {
|
|
|
|
const name = combinePaths(path, current);
|
2015-05-16 20:38:28 +02:00
|
|
|
if (!contains(exclude, getCanonicalPath(name))) {
|
2015-11-04 23:02:33 +01:00
|
|
|
const stat = _fs.statSync(name);
|
2015-05-16 20:38:28 +02:00
|
|
|
if (stat.isFile()) {
|
|
|
|
if (!extension || fileExtensionIs(name, extension)) {
|
|
|
|
result.push(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (stat.isDirectory()) {
|
|
|
|
directories.push(name);
|
2015-01-15 22:22:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-11-04 23:02:33 +01:00
|
|
|
for (const current of directories) {
|
2015-03-13 18:36:29 +01:00
|
|
|
visitDirectory(current);
|
2015-01-15 22:22:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-06 01:33:39 +01:00
|
|
|
return {
|
|
|
|
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,
|
|
|
|
watchFile: (fileName, callback) => {
|
2015-10-02 00:40:13 +02:00
|
|
|
// Node 4.0 stablized the `fs.watch` function on Windows which avoids polling
|
2015-10-02 00:25:43 +02:00
|
|
|
// 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()) {
|
2015-10-05 23:31:43 +02:00
|
|
|
// 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));
|
2015-10-02 00:25:43 +02:00
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
|
2015-11-04 23:02:33 +01:00
|
|
|
const watchedFile = watchedFileSet.addFile(fileName, callback);
|
2014-12-06 01:33:39 +01:00
|
|
|
return {
|
2015-10-02 00:40:13 +02:00
|
|
|
close: () => watchedFileSet.removeFile(watchedFile)
|
2014-12-06 01:33:39 +01:00
|
|
|
};
|
|
|
|
},
|
2015-10-02 20:49:30 +02:00
|
|
|
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)
|
2015-10-05 23:07:51 +02:00
|
|
|
return _fs.watch(
|
|
|
|
path,
|
2015-10-15 06:36:35 +02:00
|
|
|
{ persistent: true, recursive: !!recursive },
|
2015-10-05 23:07:51 +02:00
|
|
|
(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")
|
2015-10-15 00:10:05 +02:00
|
|
|
if (eventName === "rename") {
|
2015-10-05 23:07:51 +02:00
|
|
|
// When deleting a file, the passed baseFileName is null
|
2015-10-06 21:33:06 +02:00
|
|
|
callback(!relativeFileName ? relativeFileName : normalizePath(ts.combinePaths(path, relativeFileName)));
|
2015-10-05 23:07:51 +02:00
|
|
|
};
|
2014-12-06 01:33:39 +01:00
|
|
|
}
|
2015-10-05 23:07:51 +02:00
|
|
|
);
|
2014-12-06 01:33:39 +01:00
|
|
|
},
|
|
|
|
resolvePath: function (path: string): string {
|
|
|
|
return _path.resolve(path);
|
|
|
|
},
|
|
|
|
fileExists(path: string): boolean {
|
|
|
|
return _fs.existsSync(path);
|
|
|
|
},
|
|
|
|
directoryExists(path: string) {
|
|
|
|
return _fs.existsSync(path) && _fs.statSync(path).isDirectory();
|
|
|
|
},
|
|
|
|
createDirectory(directoryName: string) {
|
|
|
|
if (!this.directoryExists(directoryName)) {
|
|
|
|
_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();
|
|
|
|
},
|
2015-01-15 22:22:23 +01:00
|
|
|
readDirectory,
|
2014-12-06 01:33:39 +01:00
|
|
|
getMemoryUsage() {
|
|
|
|
if (global.gc) {
|
|
|
|
global.gc();
|
|
|
|
}
|
|
|
|
return process.memoryUsage().heapUsed;
|
|
|
|
},
|
|
|
|
exit(exitCode?: number): void {
|
|
|
|
process.exit(exitCode);
|
2014-08-14 19:52:24 +02:00
|
|
|
}
|
2014-12-06 01:33:39 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") {
|
|
|
|
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
|
|
|
}
|