addressed PR feedback

This commit is contained in:
Vladimir Matveev 2015-08-04 21:22:37 -07:00
parent a72994d78c
commit 03aaf7cd7c
12 changed files with 185 additions and 182 deletions

View File

@ -714,7 +714,7 @@ namespace ts {
/**
* List of supported extensions in order of file resolution precedence.
*/
export const supportedExtensions = [".ts", ".d.ts", ".tsx"];
export const supportedExtensions = [".ts", ".tsx", ".d.ts"];
const extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"];
export function removeFileExtension(path: string): string {

View File

@ -152,10 +152,7 @@ namespace ts {
const newLine = getNewLineCharacter(options);
let moduleResolutionHost: ModuleResolutionHost = {
fileExists: fileName => sys.fileExists(fileName),
}
return {
getSourceFile,
getDefaultLibFileName: options => combinePaths(getDirectoryPath(normalizePath(sys.getExecutingFilePath())), getDefaultLibFileName(options)),
@ -164,7 +161,8 @@ namespace ts {
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
getCanonicalFileName,
getNewLine: () => newLine,
getModuleResolutionHost: () => moduleResolutionHost
fileExists: fileName => sys.fileExists(fileName),
readFile: fileName => sys.readFile(fileName)
};
}
@ -228,11 +226,10 @@ namespace ts {
if (!options.noResolve) {
resolveModuleNamesWorker = host.resolveModuleNames;
if (!resolveModuleNamesWorker) {
Debug.assert(host.getModuleResolutionHost !== undefined);
let defaultResolver = getDefaultModuleNameResolver(options);
resolveModuleNamesWorker = (moduleNames, containingFile) => {
return map(moduleNames, moduleName => {
let moduleResolution = defaultResolver(moduleName, containingFile, options, host.getModuleResolutionHost());
let moduleResolution = defaultResolver(moduleName, containingFile, options, host);
return moduleResolution.resolvedFileName;
});
}
@ -248,7 +245,8 @@ namespace ts {
if ((oldOptions.module !== options.module) ||
(oldOptions.noResolve !== options.noResolve) ||
(oldOptions.target !== options.target) ||
(oldOptions.noLib !== options.noLib)) {
(oldOptions.noLib !== options.noLib) ||
(oldOptions.jsx !== options.jsx)) {
oldProgram = undefined;
}
}

View File

@ -2244,6 +2244,7 @@ namespace ts {
export interface ModuleResolutionHost {
fileExists(fileName: string): boolean;
readFile(fileName: string): string;
}
export interface ResolvedModule {
@ -2253,7 +2254,7 @@ namespace ts {
export type ModuleNameResolver = (moduleName: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost) => ResolvedModule;
export interface CompilerHost {
export interface CompilerHost extends ModuleResolutionHost {
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
getCancellationToken?(): CancellationToken;
getDefaultLibFileName(options: CompilerOptions): string;
@ -2263,12 +2264,14 @@ namespace ts {
useCaseSensitiveFileNames(): boolean;
getNewLine(): string;
// Compiler host must implement one of these methods
// if getModuleResolutionHost is implemented then compiler will apply one of built-in ways to resolve module names
// and ModuleResolutionHost will be used to ask host specific questions
// if resolveModuleName is implemented - this will mean that host is completely in charge of module name resolution
/*
* CompilerHost must either implement resolveModuleNames (in case if it wants to be completely in charge of
* module name resolution) or provide implementation for methods from ModuleResolutionHost (in this case compiler
* will appply built-in module resolution logic and use members of ModuleResolutionHost to ask host specific questions).
* If resolveModuleNames is implemented then implementation for members from ModuleResolutionHost can be just
* 'throw new Error("NotImplemented")'
*/
resolveModuleNames?(moduleNames: string[], containingFile: string): string[];
getModuleResolutionHost?(): ModuleResolutionHost;
}
export interface TextSpan {

View File

@ -893,11 +893,7 @@ module Harness {
newLineKind === ts.NewLineKind.CarriageReturnLineFeed ? carriageReturnLineFeed :
newLineKind === ts.NewLineKind.LineFeed ? lineFeed :
ts.sys.newLine;
let moduleResolutionHost: ts.ModuleResolutionHost = {
fileExists: fileName => getSourceFile(fileName, ts.ScriptTarget.ES5) !== undefined,
}
return {
getCurrentDirectory,
getSourceFile,
@ -906,7 +902,8 @@ module Harness {
getCanonicalFileName,
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
getNewLine: () => newLine,
getModuleResolutionHost: () => moduleResolutionHost
fileExists: fileName => getSourceFile(fileName, ts.ScriptTarget.ES5) !== undefined,
readFile: (fileName: string): string => { throw new Error("NotYetImplemented"); }
};
}

View File

@ -230,7 +230,10 @@ module Harness.LanguageService {
throw new Error("NYI");
}
fileExists(fileName: string) { return this.getScriptInfo(fileName) !== undefined; }
readFile(fileName: string) {
let snapshot = this.nativeHost.getScriptSnapshot(fileName);
return snapshot && snapshot.getText(0, snapshot.getLength());
}
log(s: string): void { this.nativeHost.log(s); }
trace(s: string): void { this.nativeHost.trace(s); }
error(s: string): void { this.nativeHost.error(s); }

View File

@ -129,10 +129,6 @@ class ProjectRunner extends RunnerBase {
getSourceFileText: (fileName: string) => string,
writeFile: (fileName: string, data: string, writeByteOrderMark: boolean) => void): CompileProjectFilesResult {
let moduleResolutionHost: ts.ModuleResolutionHost = {
fileExists: fileName => getSourceFile(fileName, ts.ScriptTarget.ES5) !== undefined,
}
let program = ts.createProgram(getInputFiles(), createCompilerOptions(), createCompilerHost());
let errors = ts.getPreEmitDiagnostics(program);
@ -196,7 +192,8 @@ class ProjectRunner extends RunnerBase {
getCanonicalFileName: Harness.Compiler.getCanonicalFileName,
useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
getNewLine: () => ts.sys.newLine,
getModuleResolutionHost: () => moduleResolutionHost
fileExists: fileName => getSourceFile(fileName, ts.ScriptTarget.ES5) !== undefined,
readFile: fileName => Harness.IO.readFile(fileName)
};
}
}

View File

@ -94,12 +94,13 @@ namespace ts.server {
constructor(public host: ServerHost, public project: Project) {
this.resolvedModuleNames = ts.createFileMap<Map<TimestampedResolvedModule>>(ts.createGetCanonicalFileName(host.useCaseSensitiveFileNames))
this.moduleResolutionHost = {
fileExists: fileName => this.fileExists(fileName)
fileExists: fileName => this.fileExists(fileName),
readFile: fileName => this.host.readFile(fileName)
}
}
resolveModuleNames(moduleNames: string[], containingFile: string): string[] {
let currentResolutionsInFile = this.resolvedModuleNames.get(containingFile);
let currentResolutionsInFile = this.resolvedModuleNames.get(containingFile);
let newResolutions: Map<TimestampedResolvedModule> = {};
let resolvedFileNames: string[] = [];

View File

@ -73,7 +73,7 @@ namespace ts {
}
/**
* Represents an immutable snapshot of a script at a specified time.Once acquired, the
* Represents an immutable snapshot of a script at a specified time.Once acquired, the
* snapshot is observably immutable. i.e. the same calls with the same parameters will return
* the same values.
*/
@ -85,9 +85,9 @@ namespace ts {
getLength(): number;
/**
* Gets the TextChangeRange that describe how the text changed between this text and
* Gets the TextChangeRange that describe how the text changed between this text and
* an older version. This information is used by the incremental parser to determine
* what sections of the script need to be re-parsed. 'undefined' can be returned if the
* what sections of the script need to be re-parsed. 'undefined' can be returned if the
* change range cannot be determined. However, in that case, incremental parsing will
* not happen and the entire document will be re - parsed.
*/
@ -276,8 +276,8 @@ namespace ts {
let children = this.getChildren(sourceFile);
let child = lastOrUndefined(children);
if (!child) {
return undefined;
if (!child) {
return undefined;
}
return child.kind < SyntaxKind.FirstNode ? child : child.getLastToken(sourceFile);
@ -337,10 +337,10 @@ namespace ts {
ts.forEach(declarations, (declaration, indexOfDeclaration) => {
// Make sure we are collecting doc comment from declaration once,
// In case of union property there might be same declaration multiple times
// In case of union property there might be same declaration multiple times
// which only varies in type parameter
// Eg. let a: Array<string> | Array<number>; a.length
// The property length will have two declarations of property length coming
// The property length will have two declarations of property length coming
// from Array<T> - Array<string> and Array<number>
if (indexOf(declarations, declaration) === indexOfDeclaration) {
let sourceFileOfDeclaration = getSourceFileOfNode(declaration);
@ -362,7 +362,7 @@ namespace ts {
// If this is dotted module name, get the doc comments from the parent
while (declaration.kind === SyntaxKind.ModuleDeclaration && declaration.parent.kind === SyntaxKind.ModuleDeclaration) {
declaration = <ModuleDeclaration>declaration.parent;
}
}
// Get the cleaned js doc comment text from the declaration
ts.forEach(getJsDocCommentTextRange(
@ -382,7 +382,7 @@ namespace ts {
jsDocComment => {
return {
pos: jsDocComment.pos + "/*".length, // Consume /* from the comment
end: jsDocComment.end - "*/".length // Trim off comment end indicator
end: jsDocComment.end - "*/".length // Trim off comment end indicator
};
});
}
@ -487,7 +487,7 @@ namespace ts {
pushDocCommentLineText(docComments, docCommentTextOfLine, blankLineCount);
blankLineCount = 0;
}
else if (!isInParamTag && docComments.length) {
else if (!isInParamTag && docComments.length) {
// This is blank line when there is text already parsed
blankLineCount++;
}
@ -503,7 +503,7 @@ namespace ts {
if (isParamTag(pos, end, sourceFile)) {
let blankLineCount = 0;
let recordedParamTag = false;
// Consume leading spaces
// Consume leading spaces
pos = consumeWhiteSpaces(pos + paramTag.length);
if (pos >= end) {
break;
@ -561,7 +561,7 @@ namespace ts {
while (pos < end) {
let ch = sourceFile.text.charCodeAt(pos);
// at line break, set this comment line text and go to next line
// at line break, set this comment line text and go to next line
if (isLineBreak(ch)) {
if (paramHelpString) {
pushDocCommentLineText(paramDocComments, paramHelpString, blankLineCount);
@ -627,7 +627,7 @@ namespace ts {
paramHelpStringMargin = sourceFile.getLineAndCharacterOfPosition(firstLineParamHelpStringPos).character;
}
// Now consume white spaces max
// Now consume white spaces max
let startOfLinePos = pos;
pos = consumeWhiteSpacesOnTheLine(pos, end, sourceFile, paramHelpStringMargin);
if (pos >= end) {
@ -976,13 +976,12 @@ namespace ts {
trace? (s: string): void;
error? (s: string): void;
useCaseSensitiveFileNames? (): boolean;
// LS host can implement one of these methods
// if getModuleResolutionHost is implemented then compiler will apply one of built-in ways to resolve module names
// and ModuleResolutionHost will be used to ask host specific questions
// if resolveModuleName is implemented - this will mean that host is completely in charge of module name resolution
// if none of these methods are implemented then language service will try to emulate getModuleResolutionHost atop of 'getScriptSnapshot'
getModuleResolutionHost?(): ModuleResolutionHost;
/*
* LS host can optionally implement this method if it wants to be completely in charge of module name resolution.
* if implementation is omitted then language service will use built-in module resolution logic and get answers to
* host specific questions using 'getScriptSnapshot'.
*/
resolveModuleNames?(moduleNames: string[], containingFile: string): string[];
}
@ -1000,17 +999,17 @@ namespace ts {
// diagnostics present for the program level, and not just 'options' diagnostics.
getCompilerOptionsDiagnostics(): Diagnostic[];
/**
/**
* @deprecated Use getEncodedSyntacticClassifications instead.
*/
getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[];
/**
/**
* @deprecated Use getEncodedSemanticClassifications instead.
*/
getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[];
// Encoded as triples of [start, length, ClassificationType].
// Encoded as triples of [start, length, ClassificationType].
getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications;
getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications;
@ -1229,7 +1228,7 @@ namespace ts {
* Represents a single signature to show in signature help.
* The id is used for subsequent calls into the language service to ask questions about the
* signature help item in the context of any documents that have been updated. i.e. after
* an edit has happened, while signature help is still active, the host can ask important
* an edit has happened, while signature help is still active, the host can ask important
* questions like 'what parameter is the user currently contained within?'.
*/
export interface SignatureHelpItem {
@ -1283,8 +1282,8 @@ namespace ts {
/** The text to display in the editor for the collapsed region. */
bannerText: string;
/**
* Whether or not this region should be automatically collapsed when
/**
* Whether or not this region should be automatically collapsed when
* the 'Collapse to Definitions' command is invoked.
*/
autoCollapse: boolean;
@ -1365,18 +1364,18 @@ namespace ts {
}
/**
* The document registry represents a store of SourceFile objects that can be shared between
* The document registry represents a store of SourceFile objects that can be shared between
* multiple LanguageService instances. A LanguageService instance holds on the SourceFile (AST)
* of files in the context.
* SourceFile objects account for most of the memory usage by the language service. Sharing
* the same DocumentRegistry instance between different instances of LanguageService allow
* for more efficient memory utilization since all projects will share at least the library
* of files in the context.
* SourceFile objects account for most of the memory usage by the language service. Sharing
* the same DocumentRegistry instance between different instances of LanguageService allow
* for more efficient memory utilization since all projects will share at least the library
* file (lib.d.ts).
*
* A more advanced use of the document registry is to serialize sourceFile objects to disk
* A more advanced use of the document registry is to serialize sourceFile objects to disk
* and re-hydrate them when needed.
*
* To create a default DocumentRegistry, use createDocumentRegistry to create one, and pass it
* To create a default DocumentRegistry, use createDocumentRegistry to create one, and pass it
* to all subsequent createLanguageService calls.
*/
export interface DocumentRegistry {
@ -1386,7 +1385,7 @@ namespace ts {
* the SourceFile if was not found in the registry.
*
* @param fileName The name of the file requested
* @param compilationSettings Some compilation settings like target affects the
* @param compilationSettings Some compilation settings like target affects the
* shape of a the resulting SourceFile. This allows the DocumentRegistry to store
* multiple copies of the same file for different compilation settings.
* @parm scriptSnapshot Text of the file. Only used if the file was not found
@ -1406,10 +1405,10 @@ namespace ts {
* to get an updated SourceFile.
*
* @param fileName The name of the file requested
* @param compilationSettings Some compilation settings like target affects the
* @param compilationSettings Some compilation settings like target affects the
* shape of a the resulting SourceFile. This allows the DocumentRegistry to store
* multiple copies of the same file for different compilation settings.
* @param scriptSnapshot Text of the file.
* @param scriptSnapshot Text of the file.
* @param version Current version of the file.
*/
updateDocument(
@ -1588,7 +1587,7 @@ namespace ts {
sourceFile: SourceFile;
// The number of language services that this source file is referenced in. When no more
// language services are referencing the file, then the file can be removed from the
// language services are referencing the file, then the file can be removed from the
// registry.
languageServiceRefCount: number;
owners: string[];
@ -1643,8 +1642,8 @@ namespace ts {
};
}
// Cache host information about scrip Should be refreshed
// at each language service public entry point, since we don't know when
// Cache host information about scrip Should be refreshed
// at each language service public entry point, since we don't know when
// set of scripts handled by the host changes.
class HostCache {
private fileNameToEntry: FileMap<HostFileInformation>;
@ -1723,8 +1722,8 @@ namespace ts {
}
class SyntaxTreeCache {
// For our syntactic only features, we also keep a cache of the syntax tree for the
// currently edited file.
// For our syntactic only features, we also keep a cache of the syntax tree for the
// currently edited file.
private currentFileName: string;
private currentFileVersion: string;
private currentFileScriptSnapshot: IScriptSnapshot;
@ -1769,20 +1768,20 @@ namespace ts {
sourceFile.version = version;
sourceFile.scriptSnapshot = scriptSnapshot;
}
export interface TranspileOptions {
compilerOptions?: CompilerOptions;
fileName?: string;
reportDiagnostics?: boolean;
moduleName?: string;
}
export interface TranspileOutput {
outputText: string;
diagnostics?: Diagnostic[];
sourceMapText?: string;
}
/*
* This function will compile source text from 'input' argument using specified compiler options.
* If not options are provided - it will use a set of default compiler options.
@ -1791,7 +1790,7 @@ namespace ts {
* - allowNonTsExtensions = true
* - noLib = true
* - noResolve = true
*/
*/
export function transpileModule(input: string, transpileOptions?: TranspileOptions): TranspileOutput {
let options = transpileOptions.compilerOptions ? clone(transpileOptions.compilerOptions) : getDefaultCompilerOptions();
@ -1800,7 +1799,7 @@ namespace ts {
// Filename can be non-ts file.
options.allowNonTsExtensions = true;
// We are not returning a sourceFile for lib file when asked by the program,
// We are not returning a sourceFile for lib file when asked by the program,
// so pass --noLib to avoid reporting a file not found error.
options.noLib = true;
@ -1820,9 +1819,6 @@ namespace ts {
// Output
let outputText: string;
let sourceMapText: string;
let moduleResolutionHost: ModuleResolutionHost = {
fileExists: fileName => fileName === inputFileName,
}
// Create a compilerHost object to allow the compiler to read and write files
let compilerHost: CompilerHost = {
getSourceFile: (fileName, target) => fileName === inputFileName ? sourceFile : undefined,
@ -1841,11 +1837,13 @@ namespace ts {
getCanonicalFileName: fileName => fileName,
getCurrentDirectory: () => "",
getNewLine: () => newLine,
getModuleResolutionHost: () => moduleResolutionHost
fileExists: (fileName): boolean => { throw new Error("Should never be called."); },
readFile: (fileName): string => { throw new Error("Should never be called."); }
};
let program = createProgram([inputFileName], options, compilerHost);
let diagnostics: Diagnostic[];
if (transpileOptions.reportDiagnostics) {
diagnostics = [];
@ -1857,11 +1855,11 @@ namespace ts {
Debug.assert(outputText !== undefined, "Output generation failed");
return { outputText, diagnostics, sourceMapText };
return { outputText, diagnostics, sourceMapText };
}
/*
* This is a shortcut function for transpileModule - it accepts transpileOptions as parameters and returns only outputText part of the result.
* This is a shortcut function for transpileModule - it accepts transpileOptions as parameters and returns only outputText part of the result.
*/
export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[], moduleName?: string): string {
let output = transpileModule(input, { compilerOptions, fileName, reportDiagnostics: !!diagnostics, moduleName });
@ -1882,19 +1880,19 @@ namespace ts {
export let disableIncrementalParsing = false;
export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile {
// If we were given a text change range, and our version or open-ness changed, then
// If we were given a text change range, and our version or open-ness changed, then
// incrementally parse this file.
if (textChangeRange) {
if (version !== sourceFile.version) {
// Once incremental parsing is ready, then just call into this function.
if (!disableIncrementalParsing) {
let newText: string;
// grab the fragment from the beginning of the original text to the beginning of the span
let prefix = textChangeRange.span.start !== 0
? sourceFile.text.substr(0, textChangeRange.span.start)
: "";
// grab the fragment from the end of the span till the end of the original text
let suffix = textSpanEnd(textChangeRange.span) !== sourceFile.text.length
? sourceFile.text.substr(textSpanEnd(textChangeRange.span))
@ -1908,10 +1906,10 @@ namespace ts {
// it was actual edit, fetch the fragment of new text that correspond to new span
let changedText = scriptSnapshot.getText(textChangeRange.span.start, textChangeRange.span.start + textChangeRange.newLength);
// combine prefix, changed text and suffix
newText = prefix && suffix
newText = prefix && suffix
? prefix + changedText + suffix
: prefix
? (prefix + changedText)
? (prefix + changedText)
: (changedText + suffix);
}
@ -1953,7 +1951,7 @@ namespace ts {
let getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames);
function getKeyFromCompilationSettings(settings: CompilerOptions): string {
return "_" + settings.target + "|" + settings.module + "|" + settings.noResolve;
return "_" + settings.target + "|" + settings.module + "|" + settings.noResolve + "|" + settings.jsx;
}
function getBucketForCompilationSettings(settings: CompilerOptions, createIfMissing: boolean): FileMap<DocumentRegistryEntry> {
@ -2017,7 +2015,7 @@ namespace ts {
bucket.set(fileName, entry);
}
else {
// We have an entry for this file. However, it may be for a different version of
// We have an entry for this file. However, it may be for a different version of
// the script snapshot. If so, update it appropriately. Otherwise, we can just
// return it as is.
if (entry.sourceFile.version !== version) {
@ -2058,7 +2056,7 @@ namespace ts {
reportStats
};
}
export function resolveModuleName(fileName: string, moduleName: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule {
let resolver = getDefaultModuleNameResolver(compilerOptions);
return resolver(moduleName, fileName, compilerOptions, host);
@ -2084,7 +2082,7 @@ namespace ts {
}
});
}
function recordAmbientExternalModule(): void {
if (!ambientExternalModules) {
ambientExternalModules = [];
@ -2556,17 +2554,20 @@ namespace ts {
return;
}
// IMPORTANT - It is critical from this moment onward that we do not check
// IMPORTANT - It is critical from this moment onward that we do not check
// cancellation tokens. We are about to mutate source files from a previous program
// instance. If we cancel midway through, we may end up in an inconsistent state where
// the program points to old source files that have been invalidated because of
// the program points to old source files that have been invalidated because of
// incremental parsing.
let oldSettings = program && program.getCompilerOptions();
let newSettings = hostCache.compilationSettings();
let changesInCompilationSettingsAffectSyntax = oldSettings &&
(oldSettings.target !== newSettings.target || oldSettings.module !== newSettings.module || oldSettings.noResolve !== newSettings.noResolve);
let changesInCompilationSettingsAffectSyntax = oldSettings &&
(oldSettings.target !== newSettings.target ||
oldSettings.module !== newSettings.module ||
oldSettings.noResolve !== newSettings.noResolve ||
oldSettings.jsx !== newSettings.jsx);
// Now create a new compiler
let compilerHost: CompilerHost = {
getSourceFile: getOrCreateSourceFile,
@ -2577,26 +2578,25 @@ namespace ts {
getDefaultLibFileName: (options) => host.getDefaultLibFileName(options),
writeFile: (fileName, data, writeByteOrderMark) => { },
getCurrentDirectory: () => host.getCurrentDirectory(),
fileExists: (fileName): boolean => { throw new Error("Not implemented"); },
readFile: (fileName): string => { throw new Error("Not implemented"); }
};
if (host.resolveModuleNames) {
compilerHost.resolveModuleNames = (moduleNames, containingFile) => host.resolveModuleNames(moduleNames, containingFile)
}
else if (host.getModuleResolutionHost) {
compilerHost.getModuleResolutionHost = () => host.getModuleResolutionHost()
}
else {
compilerHost.getModuleResolutionHost = () => {
// stub missing host functionality
return {
fileExists: fileName => hostCache.getOrCreateEntry(fileName) != undefined,
};
// stub missing host functionality
compilerHost.fileExists = fileName => hostCache.getOrCreateEntry(fileName) !== undefined;
compilerHost.readFile = fileName => {
let entry = hostCache.getOrCreateEntry(fileName);
return entry && entry.scriptSnapshot.getText(0, entry.scriptSnapshot.getLength());
}
}
let newProgram = createProgram(hostCache.getRootFileNames(), newSettings, compilerHost, program);
// Release any files we have acquired in the old program but are
// Release any files we have acquired in the old program but are
// not part of the new program.
if (program) {
let oldSourceFiles = program.getSourceFiles();
@ -2614,7 +2614,7 @@ namespace ts {
program = newProgram;
// Make sure all the nodes in the program are both bound, and have their parent
// Make sure all the nodes in the program are both bound, and have their parent
// pointers set property.
program.getTypeChecker();
return;
@ -2636,7 +2636,7 @@ namespace ts {
// Check if the old program had this file already
let oldSourceFile = program && program.getSourceFile(fileName);
if (oldSourceFile) {
// We already had a source file for this file name. Go to the registry to
// We already had a source file for this file name. Go to the registry to
// ensure that we get the right up to date version of it. We need this to
// address the following 'race'. Specifically, say we have the following:
//
@ -2647,15 +2647,15 @@ namespace ts {
// LS2
//
// Each LS has a reference to file 'foo.ts' at version 1. LS2 then updates
// it's version of 'foo.ts' to version 2. This will cause LS2 and the
// DocumentRegistry to have version 2 of the document. HOwever, LS1 will
// it's version of 'foo.ts' to version 2. This will cause LS2 and the
// DocumentRegistry to have version 2 of the document. HOwever, LS1 will
// have version 1. And *importantly* this source file will be *corrupt*.
// The act of creating version 2 of the file irrevocably damages the version
// 1 file.
//
// So, later when we call into LS1, we need to make sure that it doesn't use
// it's source file any more, and instead defers to DocumentRegistry to get
// either version 1, version 2 (or some other version) depending on what the
// either version 1, version 2 (or some other version) depending on what the
// host says should be used.
return documentRegistry.updateDocument(fileName, newSettings, hostFileInformation.scriptSnapshot, hostFileInformation.version);
}
@ -2721,7 +2721,7 @@ namespace ts {
/**
* getSemanticDiagnostiscs return array of Diagnostics. If '-d' is not enabled, only report semantic errors
* If '-d' enabled, report both semantic and emitter errors
* If '-d' enabled, report both semantic and emitter errors
*/
function getSemanticDiagnostics(fileName: string): Diagnostic[] {
synchronizeHostData();
@ -2729,7 +2729,7 @@ namespace ts {
let targetSourceFile = getValidSourceFile(fileName);
// For JavaScript files, we don't want to report the normal typescript semantic errors.
// Instead, we just report errors for using TypeScript-only constructs from within a
// Instead, we just report errors for using TypeScript-only constructs from within a
// JavaScript file.
if (isJavaScript(fileName)) {
return getJavaScriptSemanticDiagnostics(targetSourceFile);
@ -3109,7 +3109,7 @@ namespace ts {
}
if (isJavaScriptFile && type.flags & TypeFlags.Union) {
// In javascript files, for union types, we don't just get the members that
// In javascript files, for union types, we don't just get the members that
// the individual types have in common, we also include all the members that
// each individual type has. This is because we're going to add all identifiers
// anyways. So we might as well elevate the members that were at least part
@ -3164,10 +3164,10 @@ namespace ts {
// aggregating completion candidates. This is achieved in 'getScopeNode'
// by finding the first node that encompasses a position, accounting for whether a node
// is "complete" to decide whether a position belongs to the node.
//
//
// However, at the end of an identifier, we are interested in the scope of the identifier
// itself, but fall outside of the identifier. For instance:
//
//
// xyz => x$
//
// the cursor is outside of both the 'x' and the arrow function 'xyz => x',
@ -3194,7 +3194,7 @@ namespace ts {
/// TODO filter meaning based on the current context
let symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Alias;
symbols = typeChecker.getSymbolsInScope(scopeNode, symbolMeanings);
return true;
}
@ -3332,7 +3332,7 @@ namespace ts {
let rootDeclaration = getRootDeclaration(objectLikeContainer.parent);
if (isVariableLike(rootDeclaration)) {
// We don't want to complete using the type acquired by the shape
// We don't want to complete using the type acquired by the shape
// of the binding pattern; we are only interested in types acquired
// through type declaration or inference.
if (rootDeclaration.initializer || rootDeclaration.type) {
@ -3457,8 +3457,8 @@ namespace ts {
// its parent is a JsxExpression, whose parent is a JsxAttribute,
// whose parent is a JsxOpeningLikeElement
if(parent &&
parent.kind === SyntaxKind.JsxExpression &&
parent.parent &&
parent.kind === SyntaxKind.JsxExpression &&
parent.parent &&
parent.parent.kind === SyntaxKind.JsxAttribute) {
return <JsxOpeningLikeElement>parent.parent.parent;
@ -3503,16 +3503,16 @@ namespace ts {
containingNodeKind === SyntaxKind.FunctionDeclaration || // function A<T, |
containingNodeKind === SyntaxKind.InterfaceDeclaration || // interface A<T, |
containingNodeKind === SyntaxKind.ArrayBindingPattern; // var [x, y|
case SyntaxKind.DotToken:
return containingNodeKind === SyntaxKind.ArrayBindingPattern; // var [.|
case SyntaxKind.ColonToken:
return containingNodeKind === SyntaxKind.BindingElement; // var {x :html|
case SyntaxKind.OpenBracketToken:
return containingNodeKind === SyntaxKind.ArrayBindingPattern; // var [x|
case SyntaxKind.OpenParenToken:
return containingNodeKind === SyntaxKind.CatchClause ||
isFunction(containingNodeKind);
@ -3664,7 +3664,7 @@ namespace ts {
return filter(contextualMemberSymbols, m => !lookUp(existingMemberNames, m.name));
}
/**
* Filters out completion suggestions from 'symbols' according to existing JSX attributes.
*
@ -3747,7 +3747,7 @@ namespace ts {
}
function createCompletionEntry(symbol: Symbol, location: Node): CompletionEntry {
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
// We would like to only show things that can be added after a dot, so for instance numeric properties can
// not be accessed with a dot (a.1 <- invalid)
let displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, /*performCharacterChecks:*/ true, location);
@ -3755,10 +3755,10 @@ namespace ts {
return undefined;
}
// TODO(drosen): Right now we just permit *all* semantic meanings when calling
// 'getSymbolKind' which is permissible given that it is backwards compatible; but
// TODO(drosen): Right now we just permit *all* semantic meanings when calling
// 'getSymbolKind' which is permissible given that it is backwards compatible; but
// really we should consider passing the meaning for the node so that we don't report
// that a suggestion for a value is an interface. We COULD also just do what
// that a suggestion for a value is an interface. We COULD also just do what
// 'getSymbolModifiers' does, which is to use the first declaration.
// Use a 'sortText' of 0' so that all symbol completion entries come before any other
@ -3804,8 +3804,8 @@ namespace ts {
// Find the symbol with the matching entry name.
let target = program.getCompilerOptions().target;
// We don't need to perform character checks here because we're only comparing the
// name against 'entryName' (which is known to be good), not building a new
// We don't need to perform character checks here because we're only comparing the
// name against 'entryName' (which is known to be good), not building a new
// completion entry.
let symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, target, /*performCharacterChecks:*/ false, location) === entryName ? s : undefined);
@ -3820,7 +3820,7 @@ namespace ts {
};
}
}
// Didn't find a symbol with this name. See if we can find a keyword instead.
let keywordCompletion = forEach(keywordCompletions, c => c.name === entryName);
if (keywordCompletion) {
@ -3896,7 +3896,7 @@ namespace ts {
Debug.assert(!!(rootSymbolFlags & SymbolFlags.Method));
});
if (!unionPropertyKind) {
// If this was union of all methods,
// If this was union of all methods,
//make sure it has call signatures before we can label it as method
let typeOfUnionProperty = typeChecker.getTypeOfSymbolAtLocation(symbol, location);
if (typeOfUnionProperty.getCallSignatures().length) {
@ -3970,7 +3970,7 @@ namespace ts {
let allSignatures = useConstructSignatures ? type.getConstructSignatures() : type.getCallSignatures();
if (!contains(allSignatures, signature.target || signature)) {
// Get the first signature if there
// Get the first signature if there
signature = allSignatures.length ? allSignatures[0] : undefined;
}
@ -4346,7 +4346,7 @@ namespace ts {
if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) &&
!tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) {
// Just add all the declarations.
// Just add all the declarations.
forEach(declarations, declaration => {
result.push(createDefinitionInfo(declaration, symbolKind, symbolName, containerName));
});
@ -4457,7 +4457,7 @@ namespace ts {
// Because name in short-hand property assignment has two different meanings: property name and property value,
// using go-to-definition at such position should go to the variable declaration of the property value rather than
// go to the declaration of the property name (in this case stay at the same position). However, if go-to-definition
// go to the declaration of the property name (in this case stay at the same position). However, if go-to-definition
// is performed at the location of property access, we would like to go to definition of the property in the short-hand
// assignment. This case and others are handled by the following code.
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
@ -4523,7 +4523,7 @@ namespace ts {
if (results) {
let sourceFile = getCanonicalFileName(normalizeSlashes(fileName));
// Get occurrences only supports reporting occurrences for the file queried. So
// Get occurrences only supports reporting occurrences for the file queried. So
// filter down to that list.
results = filter(results, r => getCanonicalFileName(ts.normalizeSlashes(r.fileName)) === sourceFile);
}
@ -4750,7 +4750,7 @@ namespace ts {
if (isFunctionBlock(parent) || parent.kind === SyntaxKind.SourceFile) {
return parent;
}
// A throw-statement is only owned by a try-statement if the try-statement has
// a catch clause, and if the throw-statement occurs within the try block.
if (parent.kind === SyntaxKind.TryStatement) {
@ -4844,7 +4844,7 @@ namespace ts {
return undefined;
}
}
else {
else {
// unsupported modifier
return undefined;
}
@ -5440,13 +5440,13 @@ namespace ts {
// If we are past the end, stop looking
if (position > end) break;
// We found a match. Make sure it's not part of a larger word (i.e. the char
// We found a match. Make sure it's not part of a larger word (i.e. the char
// before and after it have to be a non-identifier char).
let endPosition = position + symbolNameLength;
if ((position === 0 || !isIdentifierPart(text.charCodeAt(position - 1), ScriptTarget.Latest)) &&
(endPosition === sourceLength || !isIdentifierPart(text.charCodeAt(endPosition), ScriptTarget.Latest))) {
// Found a real match. Keep searching.
// Found a real match. Keep searching.
positions.push(position);
}
position = text.indexOf(symbolName, position + symbolNameLength + 1);
@ -5513,9 +5513,9 @@ namespace ts {
return false;
}
/** Search within node "container" for references for a search value, where the search value is defined as a
/** Search within node "container" for references for a search value, where the search value is defined as a
* tuple of(searchSymbol, searchText, searchLocation, and searchMeaning).
* searchLocation: a node where the search value
* searchLocation: a node where the search value
*/
function getReferencesInNode(container: Node,
searchSymbol: Symbol,
@ -5541,7 +5541,7 @@ namespace ts {
let referenceLocation = getTouchingPropertyName(sourceFile, position);
if (!isValidReferencePosition(referenceLocation, searchText)) {
// This wasn't the start of a token. Check to see if it might be a
// This wasn't the start of a token. Check to see if it might be a
// match in a comment or string if that's what the caller is asking
// for.
if ((findInStrings && isInString(position)) ||
@ -5883,7 +5883,7 @@ namespace ts {
}
}
// If the reference location is in an object literal, try to get the contextual type for the
// If the reference location is in an object literal, try to get the contextual type for the
// object literal, lookup the property symbol in the contextual type, and use this symbol to
// compare to our searchSymbol
if (isNameOfPropertyAssignment(referenceLocation)) {
@ -5900,7 +5900,7 @@ namespace ts {
return rootSymbol;
}
// Finally, try all properties with the same name in any type the containing type extended or implemented, and
// Finally, try all properties with the same name in any type the containing type extended or implemented, and
// see if any is in the list
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
let result: Symbol[] = [];
@ -6251,7 +6251,7 @@ namespace ts {
}
else if (isNameOfModuleDeclaration(nodeForStartPos)) {
// If this is name of a module declarations, check if this is right side of dotted module name
// If parent of the module declaration which is parent of this node is module declaration and its body is the module declaration that this node is name of
// If parent of the module declaration which is parent of this node is module declaration and its body is the module declaration that this node is name of
// Then this name is name from dotted module
if (nodeForStartPos.parent.parent.kind === SyntaxKind.ModuleDeclaration &&
(<ModuleDeclaration>nodeForStartPos.parent.parent).body === nodeForStartPos.parent) {
@ -6294,7 +6294,7 @@ namespace ts {
// been canceled. That would be an enormous amount of chattyness, along with the all
// the overhead of marshalling the data to/from the host. So instead we pick a few
// reasonable node kinds to bother checking on. These node kinds represent high level
// constructs that we would expect to see commonly, but just at a far less frequent
// constructs that we would expect to see commonly, but just at a far less frequent
// interval.
//
// For example, in checker.ts (around 750k) we only have around 600 of these constructs.
@ -6367,7 +6367,7 @@ namespace ts {
*/
function hasValueSideModule(symbol: Symbol): boolean {
return forEach(symbol.declarations, declaration => {
return declaration.kind === SyntaxKind.ModuleDeclaration &&
return declaration.kind === SyntaxKind.ModuleDeclaration &&
getModuleInstanceState(declaration) === ModuleInstanceState.Instantiated;
});
}
@ -6488,8 +6488,8 @@ namespace ts {
// Only bother with the trivia if it at least intersects the span of interest.
if (isComment(kind)) {
classifyComment(token, kind, start, width);
// Classifying a comment might cause us to reuse the trivia scanner
// Classifying a comment might cause us to reuse the trivia scanner
// (because of jsdoc comments). So after we classify the comment make
// sure we set the scanner position back to where it needs to be.
triviaScanner.setTextPos(end);
@ -6540,7 +6540,7 @@ namespace ts {
for (let tag of docComment.tags) {
// As we walk through each tag, classify the portion of text from the end of
// the last tag (or the start of the entire doc comment) as 'comment'.
// the last tag (or the start of the entire doc comment) as 'comment'.
if (tag.pos !== pos) {
pushCommentRange(pos, tag.pos - pos);
}
@ -6602,7 +6602,7 @@ namespace ts {
}
function classifyDisabledMergeCode(text: string, start: number, end: number) {
// Classify the line that the ======= marker is on as a comment. Then just lex
// Classify the line that the ======= marker is on as a comment. Then just lex
// all further tokens and add them to the result.
for (var i = start; i < end; i++) {
if (isLineBreak(text.charCodeAt(i))) {
@ -6645,7 +6645,7 @@ namespace ts {
}
}
// for accurate classification, the actual token should be passed in. however, for
// for accurate classification, the actual token should be passed in. however, for
// cases like 'disabled merge code' classification, we just get the token kind and
// classify based on that instead.
function classifyTokenType(tokenKind: SyntaxKind, token?: Node): ClassificationType {
@ -6860,11 +6860,11 @@ namespace ts {
}
function getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] {
// Note: while getting todo comments seems like a syntactic operation, we actually
// Note: while getting todo comments seems like a syntactic operation, we actually
// treat it as a semantic operation here. This is because we expect our host to call
// this on every single file. If we treat this syntactically, then that will cause
// us to populate and throw away the tree in our syntax tree cache for each file. By
// treating this as a semantic operation, we can access any tree without throwing
// treating this as a semantic operation, we can access any tree without throwing
// anything away.
synchronizeHostData();
@ -6894,7 +6894,7 @@ namespace ts {
// 0) The full match for the entire regexp.
// 1) The preamble to the message portion.
// 2) The message portion.
// 3...N) The descriptor that was matched - by index. 'undefined' for each
// 3...N) The descriptor that was matched - by index. 'undefined' for each
// descriptor that didn't match. an actual value if it did match.
//
// i.e. 'undefined' in position 3 above means TODO(jason) didn't match.
@ -6920,7 +6920,7 @@ namespace ts {
}
Debug.assert(descriptor !== undefined);
// We don't want to match something like 'TODOBY', so we make sure a non
// We don't want to match something like 'TODOBY', so we make sure a non
// letter/digit follows the match.
if (isLetterOrDigit(fileContents.charCodeAt(matchPosition + descriptor.text.length))) {
continue;
@ -6972,11 +6972,11 @@ namespace ts {
// (?:(TODO\(jason\))|(HACK))
//
// Note that the outermost group is *not* a capture group, but the innermost groups
// *are* capture groups. By capturing the inner literals we can determine after
// *are* capture groups. By capturing the inner literals we can determine after
// matching which descriptor we are dealing with.
let literals = "(?:" + map(descriptors, d => "(" + escapeRegExp(d.text) + ")").join("|") + ")";
// After matching a descriptor literal, the following regexp matches the rest of the
// After matching a descriptor literal, the following regexp matches the rest of the
// text up to the end of the line (or */).
let endOfLineOrEndOfComment = /(?:$|\*\/)/.source
let messageRemainder = /(?:.*?)/.source
@ -7158,7 +7158,7 @@ namespace ts {
/// We do not have a full parser support to know when we should parse a regex or not
/// If we consider every slash token to be a regex, we could be missing cases like "1/2/3", where
/// we have a series of divide operator. this list allows us to be more accurate by ruling out
/// we have a series of divide operator. this list allows us to be more accurate by ruling out
/// locations where a regexp cannot exist.
let noRegexTable: boolean[] = [];
noRegexTable[SyntaxKind.Identifier] = true;
@ -7204,7 +7204,7 @@ namespace ts {
keyword2 === SyntaxKind.ConstructorKeyword ||
keyword2 === SyntaxKind.StaticKeyword) {
// Allow things like "public get", "public constructor" and "public static".
// Allow things like "public get", "public constructor" and "public static".
// These are all legal.
return true;
}
@ -7275,7 +7275,7 @@ namespace ts {
function getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult {
return convertClassifications(getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent), text);
}
// If there is a syntactic classifier ('syntacticClassifierAbsent' is false),
// we will be more conservative in order to avoid conflicting with the syntactic classifier.
function getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): Classifications {
@ -7337,12 +7337,12 @@ namespace ts {
// token. So the classification will go back to being an identifier. The moment the user
// types again, number will become a keyword, then an identifier, etc. etc.
//
// To try to avoid this problem, we avoid classifying contextual keywords as keywords
// To try to avoid this problem, we avoid classifying contextual keywords as keywords
// when the user is potentially typing something generic. We just can't do a good enough
// job at the lexical level, and so well leave it up to the syntactic classifier to make
// the determination.
//
// In order to determine if the user is potentially typing something generic, we use a
// In order to determine if the user is potentially typing something generic, we use a
// weak heuristic where we track < and > tokens. It's a weak heuristic, but should
// work well enough in practice.
let angleBracketStack = 0;
@ -7360,7 +7360,7 @@ namespace ts {
token = SyntaxKind.Identifier;
}
else if (isKeyword(lastNonTriviaToken) && isKeyword(token) && !canFollow(lastNonTriviaToken, token)) {
// We have two keywords in a row. Only treat the second as a keyword if
// We have two keywords in a row. Only treat the second as a keyword if
// it's a sequence that could legally occur in the language. Otherwise
// treat it as an identifier. This way, if someone writes "private var"
// we recognize that 'var' is actually an identifier here.
@ -7368,7 +7368,7 @@ namespace ts {
}
else if (lastNonTriviaToken === SyntaxKind.Identifier &&
token === SyntaxKind.LessThanToken) {
// Could be the start of something generic. Keep track of that by bumping
// Could be the start of something generic. Keep track of that by bumping
// up the current count of generic contexts we may be in.
angleBracketStack++;
}
@ -7383,7 +7383,7 @@ namespace ts {
token === SyntaxKind.BooleanKeyword ||
token === SyntaxKind.SymbolKeyword) {
if (angleBracketStack > 0 && !syntacticClassifierAbsent) {
// If it looks like we're could be in something generic, don't classify this
// If it looks like we're could be in something generic, don't classify this
// as a keyword. We may just get overwritten by the syntactic classifier,
// causing a noisy experience for the user.
token = SyntaxKind.Identifier;
@ -7491,8 +7491,8 @@ namespace ts {
}
if (start === 0 && offset > 0) {
// We're classifying the first token, and this was a case where we prepended
// text. We should consider the start of this token to be at the start of
// We're classifying the first token, and this was a case where we prepended
// text. We should consider the start of this token to be at the start of
// the original text.
start += offset;
}
@ -7615,11 +7615,11 @@ namespace ts {
/// getDefaultLibraryFilePath
declare let __dirname: string;
/**
* Get the path of the default library files (lib.d.ts) as distributed with the typescript
* node package.
* The functionality is not supported if the ts module is consumed outside of a node module.
* The functionality is not supported if the ts module is consumed outside of a node module.
*/
export function getDefaultLibFilePath(options: CompilerOptions): string {
// Check __dirname is defined and that we are on a node.js system.

View File

@ -421,6 +421,10 @@ namespace ts {
public fileExists(fileName: string): boolean {
return this.shimHost.fileExists(fileName);
}
public readFile(fileName: string): string {
return this.shimHost.readFile(fileName);
}
}
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any, logPerformance: boolean): any {

View File

@ -1,6 +1,6 @@
error TS6053: File 'a.ts' not found.
error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.d.ts', '.tsx'.
error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts'.
!!! error TS6053: File 'a.ts' not found.
!!! error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.d.ts', '.tsx'.
!!! error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts'.

View File

@ -1,6 +1,6 @@
error TS6053: File 'a.ts' not found.
error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.d.ts', '.tsx'.
error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts'.
!!! error TS6053: File 'a.ts' not found.
!!! error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.d.ts', '.tsx'.
!!! error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts'.

View File

@ -104,10 +104,6 @@ module ts {
files[t.name] = file;
}
let moduleResolutionHost: ModuleResolutionHost = {
fileExists: fileName => hasProperty(files, fileName)
}
return {
getSourceFile(fileName): SourceFile {
return files[fileName];
@ -130,7 +126,11 @@ module ts {
getNewLine(): string {
return sys.newLine;
},
getModuleResolutionHost: () => moduleResolutionHost
fileExists: fileName => hasProperty(files, fileName),
readFile: fileName => {
let file = lookUp(files, fileName);
return file && file.text;
}
}
}