Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
a06f0c3
Use builder state to emit instead
sheetalkamat Oct 19, 2017
576fe1e
Expose the watch and builder API in the typescript.d.ts
sheetalkamat Oct 26, 2017
7ebf9d9
Lint errors fix
sheetalkamat Nov 7, 2017
3c5a6e1
Allow watch host to specify module name resolver
sheetalkamat Nov 7, 2017
c9a17f3
Add api to get the dependencies of the file
sheetalkamat Nov 9, 2017
6d36a3d
Make the versions in the source file non zero when the source file is…
sheetalkamat Nov 14, 2017
85ce1d0
Make the builder state as internal and expose builder instead of buil…
sheetalkamat Nov 14, 2017
e102fee
Use the results from affected file enumerator apis as Affected File r…
sheetalkamat Nov 15, 2017
ffa64e8
Set program as affected if emitting/diagnostics for whole program
sheetalkamat Nov 16, 2017
012f12b
To handle cancellation token, remove changed/affected files from the …
sheetalkamat Nov 23, 2017
0b79f4a
Handle emit only declaration file to always produce declaration file …
sheetalkamat Nov 23, 2017
374536b
Merge branch 'master' into builderApi
sheetalkamat Dec 4, 2017
3dda217
Rename getProgram to getExistingProgram
sheetalkamat Dec 4, 2017
61fc9b9
Rename Watch.synchronizeProgram to getProgram and return the updated …
sheetalkamat Dec 4, 2017
471c83b
Rename WatchHost.moduleNameResolver to WatchHost.resolveModuleNames t…
sheetalkamat Dec 4, 2017
1a91256
Make before and after program create callbacks optional
sheetalkamat Dec 4, 2017
f046d82
Merge branch 'master' into builderApi
sheetalkamat Dec 5, 2017
944f8b8
Instead of using system as object on WatchHost, create WatchCompilerH…
sheetalkamat Dec 5, 2017
43c2610
More functions moved from system to WatchCompilerHost
sheetalkamat Dec 6, 2017
e694b9e
Update the WatchCompilerHost creation
sheetalkamat Dec 6, 2017
8cc2936
Move watchFile and watchDirectory to WatchCompilerHost
sheetalkamat Dec 6, 2017
abafddd
Move internal functions in the watch to separate namespace
sheetalkamat Dec 6, 2017
77e6731
Handle setTimeout, clearTimeout, clearScreen and report watch Diagnos…
sheetalkamat Dec 6, 2017
d22ba5e
Move the system.write to trace on WatchCompilerHost
sheetalkamat Dec 6, 2017
c9a407e
Add getDefaultLibLocation and getDefaultLibFileName and remove system…
sheetalkamat Dec 6, 2017
14f66ef
Update the emitting file, reporting errors part of the watch api
sheetalkamat Dec 6, 2017
a21b074
Update the builder to take options aligning with the WatchCompilerHost
sheetalkamat Dec 6, 2017
eb052fe
Merge branch 'master' into builderApi
sheetalkamat Dec 6, 2017
39bf33d
Few renames
sheetalkamat Dec 7, 2017
4c21cbf
Create builderState so that when FilesAffectedBy is only api needed, …
sheetalkamat Dec 7, 2017
2586bb3
From builder use the builderState containing references and file infos
sheetalkamat Dec 7, 2017
bb0fc0d
Convert builder state to mutable data, so that later we can create bu…
sheetalkamat Dec 7, 2017
965f40f
Use builder state in the semantic/emit builder as well
sheetalkamat Dec 8, 2017
dc62bb9
Change builder to BuilderProgram so it is similar to operating on pro…
sheetalkamat Dec 8, 2017
9b54d2e
Create api to create Watch<BuilderProgram>
sheetalkamat Dec 8, 2017
8ad9a62
Api to get underlying program from builder
sheetalkamat Dec 8, 2017
a75badf
Rename on WatchBuilderProgram
sheetalkamat Dec 8, 2017
2611c9b
Merge branch 'master' into builderApi
sheetalkamat Dec 8, 2017
cb26366
When user provided resolution is used, invalidate resolutions for all…
sheetalkamat Dec 8, 2017
5bc78af
Merge branch 'master' into builderApi
sheetalkamat Jan 8, 2018
5bd3f97
Merge branch 'master' into builderApi
sheetalkamat Jan 16, 2018
6650029
Merge branch 'master' into builderApi
sheetalkamat Jan 16, 2018
ed23ca5
Merge branch 'master' into builderApi
sheetalkamat Jan 18, 2018
29dee9f
Do not expose createWatchOfConfigFile and createWatchOfFilesAndCompil…
sheetalkamat Jan 18, 2018
f29c0e3
Expose createWatchCompilerHost as overload
sheetalkamat Jan 18, 2018
bd43e45
Move getCurrentDirectory to builder program
sheetalkamat Jan 18, 2018
2be231d
Add createProgram on WatchCompilerHost
sheetalkamat Jan 19, 2018
8a51cda
Merge branch 'master' into builderApi
sheetalkamat Jan 19, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
More functions moved from system to WatchCompilerHost
  • Loading branch information
sheetalkamat committed Dec 6, 2017
commit 43c2610a69748a875b08ca3a3c9e3e9cdece3b83
219 changes: 6 additions & 213 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,9 @@ namespace ts {
/** Returns its argument. */
export function identity<T>(x: T) { return x; }

/** Returns lower case string */
export function toLowerCase(x: string) { return x.toLowerCase(); }

/** Throws an error because a function is not implemented. */
export function notImplemented(): never {
throw new Error("Not implemented");
Expand Down Expand Up @@ -2877,9 +2880,7 @@ namespace ts {

export type GetCanonicalFileName = (fileName: string) => string;
export function createGetCanonicalFileName(useCaseSensitiveFileNames: boolean): GetCanonicalFileName {
return useCaseSensitiveFileNames
? ((fileName) => fileName)
: ((fileName) => fileName.toLowerCase());
return useCaseSensitiveFileNames ? identity : toLowerCase;
}

/**
Expand Down Expand Up @@ -3000,215 +3001,7 @@ namespace ts {

export function assertTypeIsNever(_: never): void { } // tslint:disable-line no-empty

export interface FileAndDirectoryExistence {
fileExists: boolean;
directoryExists: boolean;
}

export interface CachedDirectoryStructureHost extends DirectoryStructureHost {
/** Returns the queried result for the file exists and directory exists if at all it was done */
addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path): FileAndDirectoryExistence | undefined;
addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind): void;
clearCache(): void;
}

interface MutableFileSystemEntries {
readonly files: string[];
readonly directories: string[];
}

export function createCachedDirectoryStructureHost(host: DirectoryStructureHost): CachedDirectoryStructureHost {
const cachedReadDirectoryResult = createMap<MutableFileSystemEntries>();
const getCurrentDirectory = memoize(() => host.getCurrentDirectory());
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
return {
useCaseSensitiveFileNames: host.useCaseSensitiveFileNames,
readFile: (path, encoding) => host.readFile(path, encoding),
writeFile,
fileExists,
directoryExists,
createDirectory,
getCurrentDirectory,
getDirectories,
readDirectory,
addOrDeleteFileOrDirectory,
addOrDeleteFile,
clearCache,
exit: code => host.exit(code)
};

function toPath(fileName: string) {
return ts.toPath(fileName, getCurrentDirectory(), getCanonicalFileName);
}

function getCachedFileSystemEntries(rootDirPath: Path): MutableFileSystemEntries | undefined {
return cachedReadDirectoryResult.get(rootDirPath);
}

function getCachedFileSystemEntriesForBaseDir(path: Path): MutableFileSystemEntries | undefined {
return getCachedFileSystemEntries(getDirectoryPath(path));
}

function getBaseNameOfFileName(fileName: string) {
return getBaseFileName(normalizePath(fileName));
}

function createCachedFileSystemEntries(rootDir: string, rootDirPath: Path) {
const resultFromHost: MutableFileSystemEntries = {
files: map(host.readDirectory(rootDir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/["*.*"]), getBaseNameOfFileName) || [],
directories: host.getDirectories(rootDir) || []
};

cachedReadDirectoryResult.set(rootDirPath, resultFromHost);
return resultFromHost;
}

/**
* If the readDirectory result was already cached, it returns that
* Otherwise gets result from host and caches it.
* The host request is done under try catch block to avoid caching incorrect result
*/
function tryReadDirectory(rootDir: string, rootDirPath: Path): MutableFileSystemEntries | undefined {
const cachedResult = getCachedFileSystemEntries(rootDirPath);
if (cachedResult) {
return cachedResult;
}

try {
return createCachedFileSystemEntries(rootDir, rootDirPath);
}
catch (_e) {
// If there is exception to read directories, dont cache the result and direct the calls to host
Debug.assert(!cachedReadDirectoryResult.has(rootDirPath));
return undefined;
}
}

function fileNameEqual(name1: string, name2: string) {
return getCanonicalFileName(name1) === getCanonicalFileName(name2);
}

function hasEntry(entries: ReadonlyArray<string>, name: string) {
return some(entries, file => fileNameEqual(file, name));
}

function updateFileSystemEntry(entries: string[], baseName: string, isValid: boolean) {
if (hasEntry(entries, baseName)) {
if (!isValid) {
return filterMutate(entries, entry => !fileNameEqual(entry, baseName));
}
}
else if (isValid) {
return entries.push(baseName);
}
}

function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
const path = toPath(fileName);
const result = getCachedFileSystemEntriesForBaseDir(path);
if (result) {
updateFilesOfFileSystemEntry(result, getBaseNameOfFileName(fileName), /*fileExists*/ true);
}
return host.writeFile(fileName, data, writeByteOrderMark);
}

function fileExists(fileName: string): boolean {
const path = toPath(fileName);
const result = getCachedFileSystemEntriesForBaseDir(path);
return result && hasEntry(result.files, getBaseNameOfFileName(fileName)) ||
host.fileExists(fileName);
}

function directoryExists(dirPath: string): boolean {
const path = toPath(dirPath);
return cachedReadDirectoryResult.has(path) || host.directoryExists(dirPath);
}

function createDirectory(dirPath: string) {
const path = toPath(dirPath);
const result = getCachedFileSystemEntriesForBaseDir(path);
const baseFileName = getBaseNameOfFileName(dirPath);
if (result) {
updateFileSystemEntry(result.directories, baseFileName, /*isValid*/ true);
}
host.createDirectory(dirPath);
}

function getDirectories(rootDir: string): string[] {
const rootDirPath = toPath(rootDir);
const result = tryReadDirectory(rootDir, rootDirPath);
if (result) {
return result.directories.slice();
}
return host.getDirectories(rootDir);
}

function readDirectory(rootDir: string, extensions?: ReadonlyArray<string>, excludes?: ReadonlyArray<string>, includes?: ReadonlyArray<string>, depth?: number): string[] {
const rootDirPath = toPath(rootDir);
const result = tryReadDirectory(rootDir, rootDirPath);
if (result) {
return matchFiles(rootDir, extensions, excludes, includes, host.useCaseSensitiveFileNames, getCurrentDirectory(), depth, getFileSystemEntries);
}
return host.readDirectory(rootDir, extensions, excludes, includes, depth);

function getFileSystemEntries(dir: string) {
const path = toPath(dir);
if (path === rootDirPath) {
return result;
}
return getCachedFileSystemEntries(path) || createCachedFileSystemEntries(dir, path);
}
}

function addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path) {
const existingResult = getCachedFileSystemEntries(fileOrDirectoryPath);
if (existingResult) {
// Just clear the cache for now
// For now just clear the cache, since this could mean that multiple level entries might need to be re-evaluated
clearCache();
}
else {
// This was earlier a file (hence not in cached directory contents)
// or we never cached the directory containing it
const parentResult = getCachedFileSystemEntriesForBaseDir(fileOrDirectoryPath);
if (parentResult) {
const baseName = getBaseNameOfFileName(fileOrDirectory);
if (parentResult) {
const fsQueryResult: FileAndDirectoryExistence = {
fileExists: host.fileExists(fileOrDirectoryPath),
directoryExists: host.directoryExists(fileOrDirectoryPath)
};
if (fsQueryResult.directoryExists || hasEntry(parentResult.directories, baseName)) {
// Folder added or removed, clear the cache instead of updating the folder and its structure
clearCache();
}
else {
// No need to update the directory structure, just files
updateFilesOfFileSystemEntry(parentResult, baseName, fsQueryResult.fileExists);
}
return fsQueryResult;
}
}
}
}

function addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind) {
if (eventKind === FileWatcherEventKind.Changed) {
return;
}

const parentResult = getCachedFileSystemEntriesForBaseDir(filePath);
if (parentResult) {
updateFilesOfFileSystemEntry(parentResult, getBaseNameOfFileName(fileName), eventKind === FileWatcherEventKind.Created);
}
}

function updateFilesOfFileSystemEntry(parentResult: MutableFileSystemEntries, baseName: string, fileExists: boolean) {
updateFileSystemEntry(parentResult.files, baseName, fileExists);
}

function clearCache() {
cachedReadDirectoryResult.clear();
}
export function getBoundFunction<T extends Function>(method: T | undefined, methodOf: {}): T | undefined {
return method && method.bind(methodOf);
}
}
1 change: 0 additions & 1 deletion src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ namespace ts {
readFile: fileName => sys.readFile(fileName),
trace: (s: string) => sys.write(s + newLine),
directoryExists: directoryName => sys.directoryExists(directoryName),
getEnvironmentVariable: name => sys.getEnvironmentVariable ? sys.getEnvironmentVariable(name) : "",
getDirectories: (path: string) => sys.getDirectories(path),
realpath
};
Expand Down
11 changes: 6 additions & 5 deletions src/compiler/resolutionCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace ts {
onInvalidatedResolution(): void;
watchTypeRootsDirectory(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher;
onChangedAutomaticTypeDirectiveNames(): void;
getCachedDirectoryStructureHost?(): CachedDirectoryStructureHost;
getCachedDirectoryStructureHost(): CachedDirectoryStructureHost | undefined;
projectName?: string;
getGlobalCache?(): string | undefined;
writeLog(s: string): void;
Expand Down Expand Up @@ -87,6 +87,7 @@ namespace ts {
const perDirectoryResolvedTypeReferenceDirectives = createMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();

const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory());
const cachedDirectoryStructureHost = resolutionHost.getCachedDirectoryStructureHost();

/**
* These are the extensions that failed lookup files will have by default,
Expand Down Expand Up @@ -467,9 +468,9 @@ namespace ts {
function createDirectoryWatcher(directory: string, dirPath: Path) {
return resolutionHost.watchDirectoryOfFailedLookupLocation(directory, fileOrDirectory => {
const fileOrDirectoryPath = resolutionHost.toPath(fileOrDirectory);
if (resolutionHost.getCachedDirectoryStructureHost) {
if (cachedDirectoryStructureHost) {
// Since the file existance changed, update the sourceFiles cache
resolutionHost.getCachedDirectoryStructureHost().addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
}

// If the files are added to project root or node_modules directory, always run through the invalidation process
Expand Down Expand Up @@ -596,9 +597,9 @@ namespace ts {
// Create new watch and recursive info
return resolutionHost.watchTypeRootsDirectory(typeRoot, fileOrDirectory => {
const fileOrDirectoryPath = resolutionHost.toPath(fileOrDirectory);
if (resolutionHost.getCachedDirectoryStructureHost) {
if (cachedDirectoryStructureHost) {
// Since the file existance changed, update the sourceFiles cache
resolutionHost.getCachedDirectoryStructureHost().addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
}

// For now just recompile
Expand Down
30 changes: 12 additions & 18 deletions src/compiler/sys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,42 +30,36 @@ namespace ts {
mtime?: Date;
}

/**
* Partial interface of the System thats needed to support the caching of directory structure
*/
export interface DirectoryStructureHost {
useCaseSensitiveFileNames: boolean;
readFile(path: string, encoding?: string): string | undefined;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
fileExists(path: string): boolean;
directoryExists(path: string): boolean;
createDirectory(path: string): void;
getCurrentDirectory(): string;
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
exit(exitCode?: number): void;
}

export interface System extends DirectoryStructureHost {
newLine: string;
export interface System {
args: string[];
newLine: string;
useCaseSensitiveFileNames: boolean;
write(s: string): void;
readFile(path: string, encoding?: string): string | undefined;
getFileSize?(path: string): number;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
/**
* @pollingInterval - this parameter is used in polling-based watchers and ignored in watchers that
* use native OS file watching
*/
watchFile?(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
resolvePath(path: string): string;
fileExists(path: string): boolean;
directoryExists(path: string): boolean;
createDirectory(path: string): void;
getExecutingFilePath(): string;
getCurrentDirectory(): string;
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
getModifiedTime?(path: string): Date;
/**
* This should be cryptographically secure.
* A good implementation is node.js' `crypto.createHash`. (https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm)
*/
createHash?(data: string): string;
getMemoryUsage?(): number;
exit(exitCode?: number): void;
realpath?(path: string): string;
/*@internal*/ getEnvironmentVariable(name: string): string;
/*@internal*/ tryEnableSourceMapsForHost?(): void;
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/tsc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ namespace ts {

const commandLineOptions = commandLine.options;
if (configFileName) {
const configParseResult = parseConfigFile(configFileName, commandLineOptions, sys, reportDiagnostic);
const configParseResult = parseConfigFileWithSystem(configFileName, commandLineOptions, sys, reportDiagnostic);
udpateReportDiagnostic(configParseResult.options);
if (isWatchSet(configParseResult.options)) {
reportWatchModeWithoutSysSupport();
Expand Down
1 change: 0 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4327,7 +4327,6 @@ namespace ts {
* This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files
*/
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
getEnvironmentVariable?(name: string): string;
/* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions): void;
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
Expand Down
Loading