mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-13 16:10:06 -06:00
Update based on feedback
This commit is contained in:
parent
f1b1b12604
commit
136b091a4a
@ -393,7 +393,7 @@ namespace ts {
|
||||
allDiagnostics?: Diagnostic[];
|
||||
}
|
||||
|
||||
export function isProgramUptoDate(program: Program, rootFileNames: string[], newOptions: CompilerOptions,
|
||||
export function isProgramUptoDate(program: Program | undefined, rootFileNames: string[], newOptions: CompilerOptions,
|
||||
getSourceVersion: (path: Path) => string, fileExists: (fileName: string) => boolean, hasInvalidatedResolution: HasInvalidatedResolution): boolean {
|
||||
// If we haven't create a program yet, then it is not up-to-date
|
||||
if (!program) {
|
||||
@ -406,14 +406,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
// If any file is not up-to-date, then the whole program is not up-to-date
|
||||
for (const file of program.getSourceFiles()) {
|
||||
if (!sourceFileUpToDate(program.getSourceFile(file.fileName))) {
|
||||
if (program.getSourceFiles().some(sourceFileNotUptoDate)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If any of the missing file paths are now created
|
||||
if (program.getMissingFilePaths().some(missingFilePath => fileExists(missingFilePath))) {
|
||||
if (program.getMissingFilePaths().some(fileExists)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -431,15 +429,18 @@ namespace ts {
|
||||
|
||||
return true;
|
||||
|
||||
function sourceFileUpToDate(sourceFile: SourceFile): boolean {
|
||||
return sourceFile &&
|
||||
sourceFile.version === getSourceVersion(sourceFile.path) &&
|
||||
!hasInvalidatedResolution(sourceFile.path);
|
||||
function sourceFileNotUptoDate(sourceFile: SourceFile): boolean {
|
||||
return sourceFile.version !== getSourceVersion(sourceFile.path) ||
|
||||
hasInvalidatedResolution(sourceFile.path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determined if source file needs to be re-created even if its text hasnt changed
|
||||
*/
|
||||
function shouldProgramCreateNewSourceFiles(program: Program, newOptions: CompilerOptions) {
|
||||
// If any of these options change, we cant reuse old source file even if version match
|
||||
// The change in options like these could result in change in syntax tree change
|
||||
const oldOptions = program && program.getCompilerOptions();
|
||||
return oldOptions &&
|
||||
(oldOptions.target !== newOptions.target ||
|
||||
@ -478,19 +479,19 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
export interface WildcardDirectoryWatchers {
|
||||
export interface WildcardDirectoryWatcher {
|
||||
watcher: FileWatcher;
|
||||
flags: WatchDirectoryFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the existing wild card directory watcyhes with the new set of wild card directories from the config file after new program is created
|
||||
* Updates the existing wild card directory watches with the new set of wild card directories from the config file after new program is created
|
||||
*/
|
||||
export function updateWatchingWildcardDirectories(
|
||||
existingWatchedForWildcards: Map<WildcardDirectoryWatchers>,
|
||||
existingWatchedForWildcards: Map<WildcardDirectoryWatcher>,
|
||||
wildcardDirectories: Map<WatchDirectoryFlags>,
|
||||
watchDirectory: (directory: string, flags: WatchDirectoryFlags) => FileWatcher,
|
||||
closeDirectoryWatcher: (directory: string, wildcardDirectoryWatcher: WildcardDirectoryWatchers, flagsChanged: boolean) => void
|
||||
closeDirectoryWatcher: (directory: string, wildcardDirectoryWatcher: WildcardDirectoryWatcher, flagsChanged: boolean) => void
|
||||
) {
|
||||
mutateMap(
|
||||
existingWatchedForWildcards,
|
||||
@ -506,7 +507,7 @@ namespace ts {
|
||||
}
|
||||
);
|
||||
|
||||
function createWildcardDirectoryWatcher(directory: string, flags: WatchDirectoryFlags): WildcardDirectoryWatchers {
|
||||
function createWildcardDirectoryWatcher(directory: string, flags: WatchDirectoryFlags): WildcardDirectoryWatcher {
|
||||
// Create new watch and recursive info
|
||||
return {
|
||||
watcher: watchDirectory(directory, flags),
|
||||
@ -514,7 +515,7 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function updateWildcardDirectoryWatcher(directory: string, wildcardDirectoryWatcher: WildcardDirectoryWatchers, flags: WatchDirectoryFlags) {
|
||||
function updateWildcardDirectoryWatcher(directory: string, wildcardDirectoryWatcher: WildcardDirectoryWatcher, flags: WatchDirectoryFlags) {
|
||||
// Watcher needs to be updated if the recursive flags dont match
|
||||
if (wildcardDirectoryWatcher.flags === flags) {
|
||||
return;
|
||||
@ -622,7 +623,7 @@ namespace ts {
|
||||
let redirectTargetsSet = createMap<true>();
|
||||
|
||||
const filesByName = createMap<SourceFile | undefined>();
|
||||
let missingFilePaths: Path[];
|
||||
let missingFilePaths: ReadonlyArray<Path>;
|
||||
// stores 'filename -> file association' ignoring case
|
||||
// used to track cases when two file names differ only in casing
|
||||
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createMap<SourceFile>() : undefined;
|
||||
@ -666,6 +667,8 @@ namespace ts {
|
||||
missingFilePaths = arrayFrom(filesByName.keys(), p => <Path>p).filter(p => !filesByName.get(p));
|
||||
}
|
||||
|
||||
Debug.assert(!!missingFilePaths);
|
||||
|
||||
// unconditionally set moduleResolutionCache to undefined to avoid unnecessary leaks
|
||||
moduleResolutionCache = undefined;
|
||||
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
/// <reference path="types.ts"/>
|
||||
/// <reference path="core.ts"/>
|
||||
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
/** This is the cache of module/typedirectives resolution that can be retained across program */
|
||||
export interface ResolutionCache {
|
||||
setModuleResolutionHost(host: ModuleResolutionHost): void;
|
||||
|
||||
@ -19,10 +21,15 @@ namespace ts {
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
type NameResolutionWithFailedLookupLocations = { failedLookupLocations: string[], isInvalidated?: boolean };
|
||||
type ResolverWithGlobalCache = (primaryResult: ResolvedModuleWithFailedLookupLocations, moduleName: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost) => ResolvedModuleWithFailedLookupLocations | undefined;
|
||||
interface NameResolutionWithFailedLookupLocations {
|
||||
readonly failedLookupLocations: string[];
|
||||
isInvalidated?: boolean;
|
||||
}
|
||||
|
||||
interface ResolverWithGlobalCache {
|
||||
(primaryResult: ResolvedModuleWithFailedLookupLocations, moduleName: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations | undefined;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function resolveWithGlobalCache(primaryResult: ResolvedModuleWithFailedLookupLocations, moduleName: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, globalCache: string | undefined, projectName: string): ResolvedModuleWithFailedLookupLocations | undefined {
|
||||
if (!isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTypeScript(primaryResult.resolvedModule.extension)) && globalCache !== undefined) {
|
||||
// otherwise try to load typings from @types
|
||||
@ -36,7 +43,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
interface FailedLookupLocationsWatcher {
|
||||
fileWatcher: FileWatcher;
|
||||
refCount: number;
|
||||
}
|
||||
|
||||
export function createResolutionCache(
|
||||
toPath: (fileName: string) => Path,
|
||||
getCompilerOptions: () => CompilerOptions,
|
||||
@ -51,7 +62,6 @@ namespace ts {
|
||||
const resolvedModuleNames = createMap<Map<ResolvedModuleWithFailedLookupLocations>>();
|
||||
const resolvedTypeReferenceDirectives = createMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
|
||||
|
||||
type FailedLookupLocationsWatcher = { fileWatcher: FileWatcher; refCount: number };
|
||||
const failedLookupLocationsWatches = createMap<FailedLookupLocationsWatcher>();
|
||||
|
||||
return {
|
||||
@ -71,11 +81,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function clear() {
|
||||
failedLookupLocationsWatches.forEach((failedLookupLocationWatcher, failedLookupLocationPath: Path) => {
|
||||
clearMap(failedLookupLocationsWatches, (failedLookupLocationPath, failedLookupLocationWatcher) => {
|
||||
log(`Watcher: FailedLookupLocations: Status: ForceClose: LocationPath: ${failedLookupLocationPath}, refCount: ${failedLookupLocationWatcher.refCount}`);
|
||||
failedLookupLocationWatcher.fileWatcher.close();
|
||||
});
|
||||
failedLookupLocationsWatches.clear();
|
||||
resolvedModuleNames.clear();
|
||||
resolvedTypeReferenceDirectives.clear();
|
||||
}
|
||||
|
||||
@ -2411,7 +2411,7 @@ namespace ts {
|
||||
* program source file but could not be located.
|
||||
*/
|
||||
/* @internal */
|
||||
getMissingFilePaths(): Path[];
|
||||
getMissingFilePaths(): ReadonlyArray<Path>;
|
||||
|
||||
/**
|
||||
* Emits the JavaScript and declaration files. If targetSourceFile is not specified, then
|
||||
@ -3561,6 +3561,7 @@ namespace ts {
|
||||
charset?: string;
|
||||
checkJs?: boolean;
|
||||
/* @internal */ configFilePath?: string;
|
||||
/** configFile is set as non enumerable property so as to avoid checking of json source files */
|
||||
/* @internal */ readonly configFile?: JsonSourceFile;
|
||||
declaration?: boolean;
|
||||
declarationDir?: string;
|
||||
|
||||
@ -403,7 +403,10 @@ namespace ts {
|
||||
((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral || isGlobalScopeAugmentation(<ModuleDeclaration>node));
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isModuleWithStringLiteralName(node: Node): node is ModuleDeclaration {
|
||||
return isModuleDeclaration(node) && node.name.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
|
||||
export function isNonGlobalAmbientModule(node: Node): node is ModuleDeclaration & { name: StringLiteral } {
|
||||
return isModuleDeclaration(node) && isStringLiteral(node.name);
|
||||
}
|
||||
@ -1403,10 +1406,6 @@ namespace ts {
|
||||
return SpecialPropertyAssignmentKind.None;
|
||||
}
|
||||
|
||||
export function isModuleWithStringLiteralName(node: Node): node is ModuleDeclaration {
|
||||
return isModuleDeclaration(node) && node.name.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
|
||||
export function getExternalModuleName(node: Node): Expression {
|
||||
if (node.kind === SyntaxKind.ImportDeclaration) {
|
||||
return (<ImportDeclaration>node).moduleSpecifier;
|
||||
|
||||
@ -241,12 +241,13 @@ namespace ts {
|
||||
let needsReload: boolean; // true if the config file changed and needs to reload it from the disk
|
||||
let missingFilesMap: Map<FileWatcher>; // Map of file watchers for the missing files
|
||||
let configFileWatcher: FileWatcher; // watcher for the config file
|
||||
let watchedWildcardDirectories: Map<WildcardDirectoryWatchers>; // map of watchers for the wild card directories in the config file
|
||||
let watchedWildcardDirectories: Map<WildcardDirectoryWatcher>; // map of watchers for the wild card directories in the config file
|
||||
let timerToUpdateProgram: any; // timer callback to recompile the program
|
||||
|
||||
const sourceFilesCache = createMap<HostFileInfo | string>(); // Cache that stores the source file and version info
|
||||
let missingFilePathsRequestedForRelease: Path[]; // These paths are held temparirly so that we can remove the entry from source file cache if the file is not tracked by missing files
|
||||
let hasInvalidatedResolution: HasInvalidatedResolution; // Passed along to see if source file has invalidated resolutions
|
||||
let hasChangedCompilerOptions = false; // True if the compiler options have changed between compilations
|
||||
|
||||
watchingHost = watchingHost || createWatchingSystemHost(compilerOptions.pretty);
|
||||
const { system, parseConfigFile, reportDiagnostic, reportWatchDiagnostic, beforeCompile, afterCompile } = watchingHost;
|
||||
@ -291,9 +292,10 @@ namespace ts {
|
||||
// Create the compiler host
|
||||
const compilerHost = createWatchedCompilerHost(compilerOptions);
|
||||
resolutionCache.setModuleResolutionHost(compilerHost);
|
||||
if (changesAffectModuleResolution(program && program.getCompilerOptions(), compilerOptions)) {
|
||||
if (hasChangedCompilerOptions && changesAffectModuleResolution(program && program.getCompilerOptions(), compilerOptions)) {
|
||||
resolutionCache.clear();
|
||||
}
|
||||
hasChangedCompilerOptions = false;
|
||||
beforeCompile(compilerOptions);
|
||||
|
||||
// Compile the program
|
||||
@ -504,6 +506,7 @@ namespace ts {
|
||||
const configParseResult = parseConfigFile(configFileName, optionsToExtendForConfigFile, cachedHost, reportDiagnostic, reportWatchDiagnostic);
|
||||
rootFileNames = configParseResult.fileNames;
|
||||
compilerOptions = configParseResult.options;
|
||||
hasChangedCompilerOptions = true;
|
||||
configFileSpecs = configParseResult.configFileSpecs;
|
||||
configFileWildCardDirectories = configParseResult.wildcardDirectories;
|
||||
|
||||
@ -603,7 +606,7 @@ namespace ts {
|
||||
(flags & WatchDirectoryFlags.Recursive) !== 0);
|
||||
}
|
||||
|
||||
function stopWatchingWildCardDirectory(_directory: string, { watcher }: WildcardDirectoryWatchers, _recursiveChanged: boolean) {
|
||||
function stopWatchingWildCardDirectory(_directory: string, { watcher }: WildcardDirectoryWatcher, _recursiveChanged: boolean) {
|
||||
watcher.close();
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,18 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
|
||||
namespace ts {
|
||||
function verifyMissingFilePaths(missingPaths: ReadonlyArray<Path>, expected: ReadonlyArray<string>) {
|
||||
assert.isDefined(missingPaths);
|
||||
const map = arrayToMap(expected, k => k, _v => true);
|
||||
for (const missing of missingPaths) {
|
||||
const value = map.get(missing);
|
||||
assert.isTrue(value, `${missing} to be ${value === undefined ? "not present" : "present only once"}, in actual: ${missingPaths} expected: ${expected}`);
|
||||
map.set(missing, false);
|
||||
}
|
||||
const notFound = mapDefinedIter(map.keys(), k => map.get(k) === true ? k : undefined);
|
||||
assert.equal(notFound.length, 0, `Not found ${notFound} in actual: ${missingPaths} expected: ${expected}`);
|
||||
}
|
||||
|
||||
describe("Program.getMissingFilePaths", () => {
|
||||
|
||||
const options: CompilerOptions = {
|
||||
@ -40,34 +52,31 @@ namespace ts {
|
||||
it("handles no missing root files", () => {
|
||||
const program = createProgram([emptyFileRelativePath], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, []);
|
||||
verifyMissingFilePaths(missing, []);
|
||||
});
|
||||
|
||||
it("handles missing root file", () => {
|
||||
const program = createProgram(["./nonexistent.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent.ts"]); // Absolute path
|
||||
verifyMissingFilePaths(missing, ["d:/pretend/nonexistent.ts"]); // Absolute path
|
||||
});
|
||||
|
||||
it("handles multiple missing root files", () => {
|
||||
const program = createProgram(["./nonexistent0.ts", "./nonexistent1.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths().sort();
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]);
|
||||
const missing = program.getMissingFilePaths();
|
||||
verifyMissingFilePaths(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]);
|
||||
});
|
||||
|
||||
it("handles a mix of present and missing root files", () => {
|
||||
const program = createProgram(["./nonexistent0.ts", emptyFileRelativePath, "./nonexistent1.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths().sort();
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]);
|
||||
const missing = program.getMissingFilePaths();
|
||||
verifyMissingFilePaths(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]);
|
||||
});
|
||||
|
||||
it("handles repeatedly specified root files", () => {
|
||||
const program = createProgram(["./nonexistent.ts", "./nonexistent.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent.ts"]);
|
||||
verifyMissingFilePaths(missing, ["d:/pretend/nonexistent.ts"]);
|
||||
});
|
||||
|
||||
it("normalizes file paths", () => {
|
||||
@ -81,9 +90,8 @@ namespace ts {
|
||||
|
||||
it("handles missing triple slash references", () => {
|
||||
const program = createProgram([referenceFileRelativePath], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths().sort();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, [
|
||||
const missing = program.getMissingFilePaths();
|
||||
verifyMissingFilePaths(missing, [
|
||||
// From absolute reference
|
||||
"d:/imaginary/nonexistent1.ts",
|
||||
|
||||
@ -100,4 +108,4 @@ namespace ts {
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1020,11 +1020,6 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
interface WildcardDirectoryWatcher {
|
||||
watcher: FileWatcher;
|
||||
flags: WatchDirectoryFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a file is opened, the server will look for a tsconfig (or jsconfig)
|
||||
* and if successfull create a ConfiguredProject for it.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user