Merge branch 'master' into autohoist-default

This commit is contained in:
Wesley Wigham
2015-11-20 13:45:25 -08:00
2179 changed files with 40304 additions and 35196 deletions
+81 -13
View File
@@ -1,3 +1,4 @@
/// <reference path="utilities.ts"/>
/// <reference path="parser.ts"/>
/* @internal */
@@ -6,8 +7,8 @@ namespace ts {
export const enum ModuleInstanceState {
NonInstantiated = 0,
Instantiated = 1,
ConstEnumOnly = 2
Instantiated = 1,
ConstEnumOnly = 2
}
const enum Reachability {
@@ -138,6 +139,8 @@ namespace ts {
file.classifiableNames = classifiableNames;
}
file = undefined;
options = undefined;
parent = undefined;
container = undefined;
blockScopeContainer = undefined;
@@ -174,9 +177,14 @@ namespace ts {
symbol.members = {};
}
if (symbolFlags & SymbolFlags.Value && !symbol.valueDeclaration) {
symbol.valueDeclaration = node;
}
if (symbolFlags & SymbolFlags.Value) {
const valueDeclaration = symbol.valueDeclaration;
if (!valueDeclaration ||
(valueDeclaration.kind !== node.kind && valueDeclaration.kind === SyntaxKind.ModuleDeclaration)) {
// other kinds of value declarations take precedence over modules
symbol.valueDeclaration = node;
}
}
}
// Should not be called on a declaration with a computed property name,
@@ -188,6 +196,11 @@ namespace ts {
}
if (node.name.kind === SyntaxKind.ComputedPropertyName) {
const nameExpression = (<ComputedPropertyName>node.name).expression;
// treat computed property names where expression is string/numeric literal as just string/numeric literal
if (isStringOrNumericLiteral(nameExpression.kind)) {
return (<LiteralExpression>nameExpression).text;
}
Debug.assert(isWellKnownSymbolSyntactically(nameExpression));
return getPropertyNameForKnownSymbolName((<PropertyAccessExpression>nameExpression).name.text);
}
@@ -208,6 +221,9 @@ namespace ts {
return "__export";
case SyntaxKind.ExportAssignment:
return (<ExportAssignment>node).isExportEquals ? "export=" : "default";
case SyntaxKind.BinaryExpression:
// Binary expression case is for JS module 'module.exports = expr'
return "export=";
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ClassDeclaration:
return node.flags & NodeFlags.Default ? "default" : undefined;
@@ -441,7 +457,7 @@ namespace ts {
/**
* Returns true if node and its subnodes were successfully traversed.
* Returning false means that node was not examined and caller needs to dive into the node himself.
* Returning false means that node was not examined and caller needs to dive into the node himself.
*/
function bindReachableStatement(node: Node): void {
if (checkUnreachable(node)) {
@@ -551,7 +567,7 @@ namespace ts {
}
function bindIfStatement(n: IfStatement): void {
// denotes reachability state when entering 'thenStatement' part of the if statement:
// denotes reachability state when entering 'thenStatement' part of the if statement:
// i.e. if condition is false then thenStatement is unreachable
const ifTrueState = n.expression.kind === SyntaxKind.FalseKeyword ? Reachability.Unreachable : currentReachabilityState;
// denotes reachability state when entering 'elseStatement':
@@ -1069,7 +1085,7 @@ namespace ts {
return "__" + indexOf((<SignatureDeclaration>node.parent).parameters, node);
}
function bind(node: Node) {
function bind(node: Node): void {
if (!node) {
return;
}
@@ -1145,9 +1161,18 @@ namespace ts {
function bindWorker(node: Node) {
switch (node.kind) {
/* Strict mode checks */
case SyntaxKind.Identifier:
return checkStrictModeIdentifier(<Identifier>node);
case SyntaxKind.BinaryExpression:
if (isInJavaScriptFile(node)) {
if (isExportsPropertyAssignment(node)) {
bindExportsPropertyAssignment(<BinaryExpression>node);
}
else if (isModuleExportsAssignment(node)) {
bindModuleExportsAssignment(<BinaryExpression>node);
}
}
return checkStrictModeBinaryExpression(<BinaryExpression>node);
case SyntaxKind.CatchClause:
return checkStrictModeCatchClause(<CatchClause>node);
@@ -1161,7 +1186,7 @@ namespace ts {
return checkStrictModePrefixUnaryExpression(<PrefixUnaryExpression>node);
case SyntaxKind.WithStatement:
return checkStrictModeWithStatement(<WithStatement>node);
case SyntaxKind.ThisKeyword:
case SyntaxKind.ThisType:
seenThisKeyword = true;
return;
@@ -1213,6 +1238,14 @@ namespace ts {
checkStrictModeFunctionName(<FunctionExpression>node);
const bindingName = (<FunctionExpression>node).name ? (<FunctionExpression>node).name.text : "__function";
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, bindingName);
case SyntaxKind.CallExpression:
if (isInJavaScriptFile(node)) {
bindCallExpression(<CallExpression>node);
}
break;
// Members of classes, interfaces, and modules
case SyntaxKind.ClassExpression:
case SyntaxKind.ClassDeclaration:
return bindClassLikeDeclaration(<ClassLikeDeclaration>node);
@@ -1224,6 +1257,8 @@ namespace ts {
return bindEnumDeclaration(<EnumDeclaration>node);
case SyntaxKind.ModuleDeclaration:
return bindModuleDeclaration(<ModuleDeclaration>node);
// Imports and exports
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.NamespaceImport:
case SyntaxKind.ImportSpecifier:
@@ -1243,16 +1278,21 @@ namespace ts {
function bindSourceFileIfExternalModule() {
setExportContextFlag(file);
if (isExternalModule(file)) {
bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName)}"`);
bindSourceFileAsExternalModule();
}
}
function bindExportAssignment(node: ExportAssignment) {
function bindSourceFileAsExternalModule() {
bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName) }"`);
}
function bindExportAssignment(node: ExportAssignment | BinaryExpression) {
const boundExpression = node.kind === SyntaxKind.ExportAssignment ? (<ExportAssignment>node).expression : (<BinaryExpression>node).right;
if (!container.symbol || !container.symbol.exports) {
// Export assignment in some sort of block construct
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node));
}
else if (node.expression.kind === SyntaxKind.Identifier) {
else if (boundExpression.kind === SyntaxKind.Identifier) {
// An export default clause with an identifier exports all meanings of that identifier
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
}
@@ -1279,6 +1319,34 @@ namespace ts {
}
}
function setCommonJsModuleIndicator(node: Node) {
if (!file.commonJsModuleIndicator) {
file.commonJsModuleIndicator = node;
bindSourceFileAsExternalModule();
}
}
function bindExportsPropertyAssignment(node: BinaryExpression) {
// When we create a property via 'exports.foo = bar', the 'exports.foo' property access
// expression is the declaration
setCommonJsModuleIndicator(node);
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.Export, SymbolFlags.None);
}
function bindModuleExportsAssignment(node: BinaryExpression) {
// 'module.exports = expr' assignment
setCommonJsModuleIndicator(node);
bindExportAssignment(node);
}
function bindCallExpression(node: CallExpression) {
// We're only inspecting call expressions to detect CommonJS modules, so we can skip
// this check if we've already seen the module indicator
if (!file.commonJsModuleIndicator && isRequireCall(node)) {
setCommonJsModuleIndicator(node);
}
}
function bindClassLikeDeclaration(node: ClassLikeDeclaration) {
if (node.kind === SyntaxKind.ClassDeclaration) {
bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
@@ -1467,7 +1535,7 @@ namespace ts {
// unreachable code is reported if
// - user has explicitly asked about it AND
// - statement is in not ambient context (statements in ambient context is already an error
// - statement is in not ambient context (statements in ambient context is already an error
// so we should not report extras) AND
// - node is not variable statement OR
// - node is block scoped variable statement OR
+409 -174
View File
File diff suppressed because it is too large Load Diff
+31 -16
View File
@@ -284,6 +284,11 @@ namespace ts {
name: "allowSyntheticDefaultImports",
type: "boolean",
description: Diagnostics.Allow_default_imports_from_modules_with_no_default_export
},
{
name: "allowJs",
type: "boolean",
description: Diagnostics.Allow_javascript_files_to_be_compiled
}
];
@@ -479,9 +484,10 @@ namespace ts {
* @param basePath A root directory to resolve relative path entries in the config
* file to. e.g. outDir
*/
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string): ParsedCommandLine {
const { options, errors } = convertCompilerOptionsFromJson(json["compilerOptions"], basePath);
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions: CompilerOptions = {}): ParsedCommandLine {
const { options: optionsFromJsonConfigFile, errors } = convertCompilerOptionsFromJson(json["compilerOptions"], basePath);
const options = extend(existingOptions, optionsFromJsonConfigFile);
return {
options,
fileNames: getFileNames(),
@@ -499,23 +505,32 @@ namespace ts {
}
}
else {
const filesSeen: Map<boolean> = {};
const exclude = json["exclude"] instanceof Array ? map(<string[]>json["exclude"], normalizeSlashes) : undefined;
const sysFiles = host.readDirectory(basePath, ".ts", exclude).concat(host.readDirectory(basePath, ".tsx", exclude));
for (let i = 0; i < sysFiles.length; i++) {
const name = sysFiles[i];
if (fileExtensionIs(name, ".d.ts")) {
const baseName = name.substr(0, name.length - ".d.ts".length);
if (!contains(sysFiles, baseName + ".tsx") && !contains(sysFiles, baseName + ".ts")) {
fileNames.push(name);
const supportedExtensions = getSupportedExtensions(options);
Debug.assert(indexOf(supportedExtensions, ".ts") < indexOf(supportedExtensions, ".d.ts"), "Changed priority of extensions to pick");
// Get files of supported extensions in their order of resolution
for (const extension of supportedExtensions) {
const filesInDirWithExtension = host.readDirectory(basePath, extension, exclude);
for (const fileName of filesInDirWithExtension) {
// .ts extension would read the .d.ts extension files too but since .d.ts is lower priority extension,
// lets pick them when its turn comes up
if (extension === ".ts" && fileExtensionIs(fileName, ".d.ts")) {
continue;
}
}
else if (fileExtensionIs(name, ".ts")) {
if (!contains(sysFiles, name + "x")) {
fileNames.push(name);
// If this is one of the output extension (which would be .d.ts and .js if we are allowing compilation of js files)
// do not include this file if we included .ts or .tsx file with same base name as it could be output of the earlier compilation
if (extension === ".d.ts" || (options.allowJs && contains(supportedJavascriptExtensions, extension))) {
const baseName = fileName.substr(0, fileName.length - extension.length);
if (hasProperty(filesSeen, baseName + ".ts") || hasProperty(filesSeen, baseName + ".tsx")) {
continue;
}
}
}
else {
fileNames.push(name);
filesSeen[fileName] = true;
fileNames.push(fileName);
}
}
}
+13 -13
View File
@@ -297,8 +297,8 @@ namespace ts {
return <T>result;
}
export function extend<T1, T2>(first: Map<T1>, second: Map<T2>): Map<T1 & T2> {
const result: Map<T1 & T2> = {};
export function extend<T1 extends Map<{}>, T2 extends Map<{}>>(first: T1 , second: T2): T1 & T2 {
const result: T1 & T2 = <any>{};
for (const id in first) {
(result as any)[id] = first[id];
}
@@ -714,7 +714,7 @@ namespace ts {
}
export function getBaseFileName(path: string) {
if (!path) {
if (path === undefined) {
return undefined;
}
const i = path.lastIndexOf(directorySeparator);
@@ -738,18 +738,18 @@ namespace ts {
/**
* List of supported extensions in order of file resolution precedence.
*/
export const supportedExtensions = [".ts", ".tsx", ".d.ts"];
/**
* List of extensions that will be used to look for external modules.
* This list is kept separate from supportedExtensions to for cases when we'll allow to include .js files in compilation,
* but still would like to load only TypeScript files as modules
*/
export const moduleFileExtensions = supportedExtensions;
export const supportedTypeScriptExtensions = [".ts", ".tsx", ".d.ts"];
export const supportedJavascriptExtensions = [".js", ".jsx"];
const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions);
export function isSupportedSourceFileName(fileName: string) {
export function getSupportedExtensions(options?: CompilerOptions): string[] {
return options && options.allowJs ? allSupportedExtensions : supportedTypeScriptExtensions;
}
export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions) {
if (!fileName) { return false; }
for (const extension of supportedExtensions) {
for (const extension of getSupportedExtensions(compilerOptions)) {
if (fileExtensionIs(fileName, extension)) {
return true;
}
@@ -847,7 +847,7 @@ namespace ts {
}
export function fail(message?: string): void {
Debug.assert(false, message);
Debug.assert(/*expression*/ false, message);
}
}
+124 -73
View File
@@ -31,13 +31,17 @@ namespace ts {
}
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, targetSourceFile: SourceFile): Diagnostic[] {
const diagnostics: Diagnostic[] = [];
const jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, host, ".js");
emitDeclarations(host, resolver, diagnostics, jsFilePath, targetSourceFile);
return diagnostics;
const declarationDiagnostics = createDiagnosticCollection();
forEachExpectedEmitFile(host, getDeclarationDiagnosticsFromFile, targetSourceFile);
return declarationDiagnostics.getDiagnostics(targetSourceFile.fileName);
function getDeclarationDiagnosticsFromFile({ declarationFilePath }, sources: SourceFile[], isBundledEmit: boolean) {
emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sources, isBundledEmit);
}
}
function emitDeclarations(host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[], jsFilePath: string, root?: SourceFile): DeclarationEmit {
function emitDeclarations(host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, declarationFilePath: string,
sourceFiles: SourceFile[], isBundledEmit: boolean): DeclarationEmit {
const newLine = host.getNewLine();
const compilerOptions = host.getCompilerOptions();
@@ -58,8 +62,9 @@ namespace ts {
let errorNameNode: DeclarationName;
const emitJsDocComments = compilerOptions.removeComments ? function (declaration: Node) { } : writeJsDocComments;
const emit = compilerOptions.stripInternal ? stripInternal : emitNode;
let noDeclare: boolean;
const moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = [];
let moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = [];
let asynchronousSubModuleDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[];
// Contains the reference paths that needs to go in the declaration file.
@@ -67,71 +72,78 @@ namespace ts {
// and we could be collecting these paths from multiple files into single one with --out option
let referencePathsOutput = "";
if (root) {
// Emitting just a single file, so emit references in this file only
// Emit references corresponding to each file
const emittedReferencedFiles: SourceFile[] = [];
let addedGlobalFileReference = false;
let allSourcesModuleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = [];
forEach(sourceFiles, sourceFile => {
// Dont emit for javascript file
if (isSourceFileJavaScript(sourceFile)) {
return;
}
// Check what references need to be added
if (!compilerOptions.noResolve) {
let addedGlobalFileReference = false;
forEach(root.referencedFiles, fileReference => {
const referencedFile = tryResolveScriptReference(host, root, fileReference);
forEach(sourceFile.referencedFiles, fileReference => {
const referencedFile = tryResolveScriptReference(host, sourceFile, fileReference);
// All the references that are not going to be part of same file
if (referencedFile && ((referencedFile.flags & NodeFlags.DeclarationFile) || // This is a declare file reference
shouldEmitToOwnFile(referencedFile, compilerOptions) || // This is referenced file is emitting its own js file
!addedGlobalFileReference)) { // Or the global out file corresponding to this reference was not added
writeReferencePath(referencedFile);
if (!isExternalModuleOrDeclarationFile(referencedFile)) {
// Emit reference in dts, if the file reference was not already emitted
if (referencedFile && !contains(emittedReferencedFiles, referencedFile)) {
// Add a reference to generated dts file,
// global file reference is added only
// - if it is not bundled emit (because otherwise it would be self reference)
// - and it is not already added
if (writeReferencePath(referencedFile, !isBundledEmit && !addedGlobalFileReference)) {
addedGlobalFileReference = true;
}
emittedReferencedFiles.push(referencedFile);
}
});
}
emitSourceFile(root);
if (!isBundledEmit || !isExternalModule(sourceFile)) {
noDeclare = false;
emitSourceFile(sourceFile);
}
else if (isExternalModule(sourceFile)) {
noDeclare = true;
write(`declare module "${getResolvedExternalModuleName(host, sourceFile)}" {`);
writeLine();
increaseIndent();
emitSourceFile(sourceFile);
decreaseIndent();
write("}");
writeLine();
}
// create asynchronous output for the importDeclarations
if (moduleElementDeclarationEmitInfo.length) {
const oldWriter = writer;
forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => {
if (aliasEmitInfo.isVisible) {
if (aliasEmitInfo.isVisible && !aliasEmitInfo.asynchronousOutput) {
Debug.assert(aliasEmitInfo.node.kind === SyntaxKind.ImportDeclaration);
createAndSetNewTextWriterWithSymbolWriter();
Debug.assert(aliasEmitInfo.indent === 0);
Debug.assert(aliasEmitInfo.indent === 0 || (aliasEmitInfo.indent === 1 && isBundledEmit));
for (let i = 0; i < aliasEmitInfo.indent; i++) {
increaseIndent();
}
writeImportDeclaration(<ImportDeclaration>aliasEmitInfo.node);
aliasEmitInfo.asynchronousOutput = writer.getText();
for (let i = 0; i < aliasEmitInfo.indent; i++) {
decreaseIndent();
}
}
});
setWriter(oldWriter);
allSourcesModuleElementDeclarationEmitInfo = allSourcesModuleElementDeclarationEmitInfo.concat(moduleElementDeclarationEmitInfo);
moduleElementDeclarationEmitInfo = [];
}
}
else {
// Emit references corresponding to this file
const emittedReferencedFiles: SourceFile[] = [];
forEach(host.getSourceFiles(), sourceFile => {
if (!isExternalModuleOrDeclarationFile(sourceFile)) {
// Check what references need to be added
if (!compilerOptions.noResolve) {
forEach(sourceFile.referencedFiles, fileReference => {
const referencedFile = tryResolveScriptReference(host, sourceFile, fileReference);
// If the reference file is a declaration file or an external module, emit that reference
if (referencedFile && (isExternalModuleOrDeclarationFile(referencedFile) &&
!contains(emittedReferencedFiles, referencedFile))) { // If the file reference was not already emitted
writeReferencePath(referencedFile);
emittedReferencedFiles.push(referencedFile);
}
});
}
emitSourceFile(sourceFile);
}
});
}
});
return {
reportedDeclarationError,
moduleElementDeclarationEmitInfo,
moduleElementDeclarationEmitInfo: allSourcesModuleElementDeclarationEmitInfo,
synchronousDeclarationOutput: writer.getText(),
referencePathsOutput,
};
@@ -243,14 +255,14 @@ namespace ts {
const errorInfo = writer.getSymbolAccessibilityDiagnostic(symbolAccesibilityResult);
if (errorInfo) {
if (errorInfo.typeName) {
diagnostics.push(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
emitterDiagnostics.add(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
errorInfo.diagnosticMessage,
getTextOfNodeFromSourceText(currentText, errorInfo.typeName),
symbolAccesibilityResult.errorSymbolName,
symbolAccesibilityResult.errorModuleName));
}
else {
diagnostics.push(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
emitterDiagnostics.add(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
errorInfo.diagnosticMessage,
symbolAccesibilityResult.errorSymbolName,
symbolAccesibilityResult.errorModuleName));
@@ -265,7 +277,8 @@ namespace ts {
function reportInaccessibleThisError() {
if (errorNameNode) {
diagnostics.push(createDiagnosticForNode(errorNameNode, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_this_type_A_type_annotation_is_necessary,
reportedDeclarationError = true;
emitterDiagnostics.add(createDiagnosticForNode(errorNameNode, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_this_type_A_type_annotation_is_necessary,
declarationNameToString(errorNameNode)));
}
}
@@ -343,7 +356,7 @@ namespace ts {
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.ThisKeyword:
case SyntaxKind.ThisType:
case SyntaxKind.StringLiteral:
return writeTextOfNode(currentText, type);
case SyntaxKind.ExpressionWithTypeArguments:
@@ -607,7 +620,7 @@ namespace ts {
if (node.flags & NodeFlags.Default) {
write("default ");
}
else if (node.kind !== SyntaxKind.InterfaceDeclaration) {
else if (node.kind !== SyntaxKind.InterfaceDeclaration && !noDeclare) {
write("declare ");
}
}
@@ -702,11 +715,25 @@ namespace ts {
}
write(" from ");
}
writeTextOfNode(currentText, node.moduleSpecifier);
emitExternalModuleSpecifier(node.moduleSpecifier);
write(";");
writer.writeLine();
}
function emitExternalModuleSpecifier(moduleSpecifier: Expression) {
if (moduleSpecifier.kind === SyntaxKind.StringLiteral && isBundledEmit) {
const moduleName = getExternalModuleNameFromDeclaration(host, resolver, moduleSpecifier.parent as (ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration));
if (moduleName) {
write("\"");
write(moduleName);
write("\"");
return;
}
}
writeTextOfNode(currentText, moduleSpecifier);
}
function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) {
if (node.propertyName) {
writeTextOfNode(currentText, node.propertyName);
@@ -738,7 +765,7 @@ namespace ts {
}
if (node.moduleSpecifier) {
write(" from ");
writeTextOfNode(currentText, node.moduleSpecifier);
emitExternalModuleSpecifier(node.moduleSpecifier);
}
write(";");
writer.writeLine();
@@ -1594,34 +1621,58 @@ namespace ts {
}
}
function writeReferencePath(referencedFile: SourceFile) {
let declFileName = referencedFile.flags & NodeFlags.DeclarationFile
? referencedFile.fileName // Declaration file, use declaration file name
: shouldEmitToOwnFile(referencedFile, compilerOptions)
? getOwnEmitOutputFilePath(referencedFile, host, ".d.ts") // Own output file so get the .d.ts file
: removeFileExtension(compilerOptions.outFile || compilerOptions.out) + ".d.ts"; // Global out file
/**
* Adds the reference to referenced file, returns true if global file reference was emitted
* @param referencedFile
* @param addBundledFileReference Determines if global file reference corresponding to bundled file should be emitted or not
*/
function writeReferencePath(referencedFile: SourceFile, addBundledFileReference: boolean): boolean {
let declFileName: string;
let addedBundledEmitReference = false;
if (isDeclarationFile(referencedFile)) {
// Declaration file, use declaration file name
declFileName = referencedFile.fileName;
}
else {
// Get the declaration file path
forEachExpectedEmitFile(host, getDeclFileName, referencedFile);
}
declFileName = getRelativePathToDirectoryOrUrl(
getDirectoryPath(normalizeSlashes(jsFilePath)),
declFileName,
host.getCurrentDirectory(),
host.getCanonicalFileName,
/*isAbsolutePathAnUrl*/ false);
if (declFileName) {
declFileName = getRelativePathToDirectoryOrUrl(
getDirectoryPath(normalizeSlashes(declarationFilePath)),
declFileName,
host.getCurrentDirectory(),
host.getCanonicalFileName,
/*isAbsolutePathAnUrl*/ false);
referencePathsOutput += "/// <reference path=\"" + declFileName + "\" />" + newLine;
referencePathsOutput += "/// <reference path=\"" + declFileName + "\" />" + newLine;
}
return addedBundledEmitReference;
function getDeclFileName(emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) {
// Dont add reference path to this file if it is a bundled emit and caller asked not emit bundled file path
if (isBundledEmit && !addBundledFileReference) {
return;
}
Debug.assert(!!emitFileNames.declarationFilePath || isSourceFileJavaScript(referencedFile), "Declaration file is not present only for javascript files");
declFileName = emitFileNames.declarationFilePath || emitFileNames.jsFilePath;
addedBundledEmitReference = isBundledEmit;
}
}
}
/* @internal */
export function writeDeclarationFile(jsFilePath: string, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[]) {
const emitDeclarationResult = emitDeclarations(host, resolver, diagnostics, jsFilePath, sourceFile);
// TODO(shkamat): Should we not write any declaration file if any of them can produce error,
// or should we just not write this file like we are doing now
if (!emitDeclarationResult.reportedDeclarationError) {
export function writeDeclarationFile(declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection) {
const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFiles, isBundledEmit);
const emitSkipped = emitDeclarationResult.reportedDeclarationError || host.isEmitBlocked(declarationFilePath);
if (!emitSkipped) {
const declarationOutput = emitDeclarationResult.referencePathsOutput
+ getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo);
writeFile(host, diagnostics, removeFileExtension(jsFilePath) + ".d.ts", declarationOutput, host.getCompilerOptions().emitBOM);
writeFile(host, emitterDiagnostics, declarationFilePath, declarationOutput, host.getCompilerOptions().emitBOM);
}
return emitSkipped;
function getDeclarationOutput(synchronousDeclarationOutput: string, moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[]) {
let appliedSyncOutputPos = 0;
+16 -1
View File
@@ -2060,6 +2060,14 @@
"category": "Error",
"code": 5054
},
"Cannot write file '{0}' because it would overwrite input file.": {
"category": "Error",
"code": 5055
},
"Cannot write file '{0}' because it would be overwritten by multiple input files.": {
"category": "Error",
"code": 5056
},
"Concatenate and emit output to single file.": {
"category": "Message",
@@ -2314,7 +2322,6 @@
"category": "Message",
"code": 6078
},
"Specify JSX code generation: 'preserve' or 'react'": {
"category": "Message",
"code": 6080
@@ -2323,6 +2330,14 @@
"category": "Message",
"code": 6081
},
"Only 'amd' and 'system' modules are supported alongside --{0}.": {
"category": "Error",
"code": 6082
},
"Allow javascript files to be compiled.": {
"category": "Message",
"code": 6083
},
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
+169 -140
View File
@@ -3,8 +3,16 @@
/* @internal */
namespace ts {
export function isExternalModuleOrDeclarationFile(sourceFile: SourceFile) {
return isExternalModule(sourceFile) || isDeclarationFile(sourceFile);
export function getResolvedExternalModuleName(host: EmitHost, file: SourceFile): string {
return file.moduleName || getExternalModuleNameFromPath(host, file.fileName);
}
export function getExternalModuleNameFromDeclaration(host: EmitHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration): string {
const file = resolver.getExternalModuleFileFromDeclaration(declaration);
if (!file || isDeclarationFile(file)) {
return undefined;
}
return getResolvedExternalModuleName(host, file);
}
type DependencyGroup = Array<ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration>;
@@ -325,45 +333,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
};`;
const compilerOptions = host.getCompilerOptions();
const languageVersion = compilerOptions.target || ScriptTarget.ES3;
const modulekind = compilerOptions.module ? compilerOptions.module : languageVersion === ScriptTarget.ES6 ? ModuleKind.ES6 : ModuleKind.None;
const languageVersion = getEmitScriptTarget(compilerOptions);
const modulekind = getEmitModuleKind(compilerOptions);
const sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? [] : undefined;
let diagnostics: Diagnostic[] = [];
const emitterDiagnostics = createDiagnosticCollection();
let emitSkipped = false;
const newLine = host.getNewLine();
const jsxDesugaring = host.getCompilerOptions().jsx !== JsxEmit.Preserve;
const shouldEmitJsx = (s: SourceFile) => (s.languageVariant === LanguageVariant.JSX && !jsxDesugaring);
const emitJavaScript = createFileEmitter();
if (targetSourceFile === undefined) {
forEach(host.getSourceFiles(), sourceFile => {
if (shouldEmitToOwnFile(sourceFile, compilerOptions)) {
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, shouldEmitJsx(sourceFile) ? ".jsx" : ".js");
emitFile(jsFilePath, sourceFile);
}
});
if (compilerOptions.outFile || compilerOptions.out) {
emitFile(compilerOptions.outFile || compilerOptions.out);
}
}
else {
// targetSourceFile is specified (e.g calling emitter from language service or calling getSemanticDiagnostic from language service)
if (shouldEmitToOwnFile(targetSourceFile, compilerOptions)) {
const jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, host, shouldEmitJsx(targetSourceFile) ? ".jsx" : ".js");
emitFile(jsFilePath, targetSourceFile);
}
else if (!isDeclarationFile(targetSourceFile) && (compilerOptions.outFile || compilerOptions.out)) {
emitFile(compilerOptions.outFile || compilerOptions.out);
}
}
// Sort and make the unique list of diagnostics
diagnostics = sortAndDeduplicateDiagnostics(diagnostics);
forEachExpectedEmitFile(host, emitFile, targetSourceFile);
return {
emitSkipped: false,
diagnostics,
emitSkipped,
diagnostics: emitterDiagnostics.getDiagnostics(),
sourceMaps: sourceMapDataList
};
@@ -414,7 +396,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
* var loop = function(x) { <code where 'arguments' is replaced witg 'arguments_1'> }
* var arguments_1 = arguments
* for (var x;;) loop(x);
* otherwise semantics of the code will be different since 'arguments' inside converted loop body
* otherwise semantics of the code will be different since 'arguments' inside converted loop body
* will refer to function that holds converted loop.
* This value is set on demand.
*/
@@ -422,10 +404,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
/*
* list of non-block scoped variable declarations that appear inside converted loop
* such variable declarations should be moved outside the loop body
* such variable declarations should be moved outside the loop body
* for (let x;;) {
* var y = 1;
* ...
* ...
* }
* should be converted to
* var loop = function(x) {
@@ -472,8 +454,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
}
function createFileEmitter(): (jsFilePath: string, root?: SourceFile) => void {
const writer: EmitTextWriter = createTextWriter(newLine);
function createFileEmitter(): (jsFilePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) => void {
const writer = createTextWriter(newLine);
const { write, writeTextOfNode, writeLine, increaseIndent, decreaseIndent } = writer;
let currentSourceFile: SourceFile;
@@ -502,7 +484,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
let decorateEmitted: boolean;
let paramEmitted: boolean;
let awaiterEmitted: boolean;
let tempFlags: TempFlags;
let tempFlags: TempFlags = 0;
let tempVariables: Identifier[];
let tempParameters: Identifier[];
let externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[];
@@ -545,10 +527,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
/** Sourcemap data that will get encoded */
let sourceMapData: SourceMapData;
/** Is the file being emitted into its own file */
let isOwnFileEmit: boolean;
/** If removeComments is true, no leading-comments needed to be emitted **/
const emitLeadingCommentsOfPosition = compilerOptions.removeComments ? function (pos: number) { } : emitLeadingCommentsOfPositionWorker;
const moduleEmitDelegates: Map<(node: SourceFile) => void> = {
const moduleEmitDelegates: Map<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void> = {
[ModuleKind.ES6]: emitES6Module,
[ModuleKind.AMD]: emitAMDModule,
[ModuleKind.System]: emitSystemModule,
@@ -556,20 +541,47 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
[ModuleKind.CommonJS]: emitCommonJSModule,
};
const bundleEmitDelegates: Map<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void> = {
[ModuleKind.ES6]() {},
[ModuleKind.AMD]: emitAMDModule,
[ModuleKind.System]: emitSystemModule,
[ModuleKind.UMD]() {},
[ModuleKind.CommonJS]() {},
};
return doEmit;
function doEmit(jsFilePath: string, root?: SourceFile) {
function doEmit(jsFilePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
generatedNameSet = {};
nodeToGeneratedName = [];
isOwnFileEmit = !isBundledEmit;
if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) {
initializeEmitterWithSourceMaps(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
}
// Emit helpers from all the files
if (isBundledEmit && modulekind) {
forEach(sourceFiles, emitEmitHelpers);
}
// Do not call emit directly. It does not set the currentSourceFile.
forEach(sourceFiles, emitSourceFile);
writeLine();
writeEmittedFiles(writer.getText(), jsFilePath, /*writeByteOrderMark*/ compilerOptions.emitBOM);
// reset the state
writer.reset();
currentSourceFile = undefined;
currentText = undefined;
currentLineMap = undefined;
exportFunctionForFile = undefined;
generatedNameSet = {};
nodeToGeneratedName = [];
generatedNameSet = undefined;
nodeToGeneratedName = undefined;
computedPropertyNamesToGeneratedNames = undefined;
convertedLoopState = undefined;
extendsEmitted = false;
decorateEmitted = false;
paramEmitted = false;
@@ -586,25 +598,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
isEs6Module = false;
renamedDependencies = undefined;
isCurrentFileExternalModule = false;
if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) {
initializeEmitterWithSourceMaps(jsFilePath, root);
}
if (root) {
// Do not call emit directly. It does not set the currentSourceFile.
emitSourceFile(root);
}
else {
forEach(host.getSourceFiles(), sourceFile => {
if (!isExternalModuleOrDeclarationFile(sourceFile)) {
emitSourceFile(sourceFile);
}
});
}
writeLine();
writeEmittedFiles(writer.getText(), jsFilePath, /*writeByteOrderMark*/ compilerOptions.emitBOM);
}
function emitSourceFile(sourceFile: SourceFile): void {
@@ -715,7 +708,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
return nodeToGeneratedName[id] || (nodeToGeneratedName[id] = unescapeIdentifier(generateNameForNode(node)));
}
function initializeEmitterWithSourceMaps(jsFilePath: string, root?: SourceFile) {
function initializeEmitterWithSourceMaps(jsFilePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
let sourceMapDir: string; // The directory in which sourcemap will be
// Current source map file and its index in the sources list
@@ -1016,24 +1009,23 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
if (compilerOptions.inlineSourceMap) {
// Encode the sourceMap into the sourceMap url
const base64SourceMapText = convertToBase64(sourceMapText);
sourceMapUrl = `//# sourceMappingURL=data:application/json;base64,${base64SourceMapText}`;
sourceMapData.jsSourceMappingURL = `data:application/json;base64,${base64SourceMapText}`;
}
else {
// Write source map file
writeFile(host, diagnostics, sourceMapData.sourceMapFilePath, sourceMapText, /*writeByteOrderMark*/ false);
sourceMapUrl = `//# sourceMappingURL=${sourceMapData.jsSourceMappingURL}`;
writeFile(host, emitterDiagnostics, sourceMapData.sourceMapFilePath, sourceMapText, /*writeByteOrderMark*/ false);
}
sourceMapUrl = `//# sourceMappingURL=${sourceMapData.jsSourceMappingURL}`;
// Write sourcemap url to the js file and write the js file
writeJavaScriptFile(emitOutput + sourceMapUrl, jsFilePath, writeByteOrderMark);
}
// Initialize source map data
const sourceMapJsFile = getBaseFileName(normalizeSlashes(jsFilePath));
sourceMapData = {
sourceMapFilePath: jsFilePath + ".map",
jsSourceMappingURL: sourceMapJsFile + ".map",
sourceMapFile: sourceMapJsFile,
sourceMapFilePath: sourceMapFilePath,
jsSourceMappingURL: !compilerOptions.inlineSourceMap ? getBaseFileName(normalizeSlashes(sourceMapFilePath)) : undefined,
sourceMapFile: getBaseFileName(normalizeSlashes(jsFilePath)),
sourceMapSourceRoot: compilerOptions.sourceRoot || "",
sourceMapSources: [],
inputSourceFileNames: [],
@@ -1052,10 +1044,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
if (compilerOptions.mapRoot) {
sourceMapDir = normalizeSlashes(compilerOptions.mapRoot);
if (root) { // emitting single module file
if (!isBundledEmit) { // emitting single module file
Debug.assert(sourceFiles.length === 1);
// For modules or multiple emit files the mapRoot will have directory structure like the sources
// So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map
sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(root, host, sourceMapDir));
sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(sourceFiles[0], host, sourceMapDir));
}
if (!isRootedDiskPath(sourceMapDir) && !isUrl(sourceMapDir)) {
@@ -1108,7 +1101,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
function writeJavaScriptFile(emitOutput: string, jsFilePath: string, writeByteOrderMark: boolean) {
writeFile(host, diagnostics, jsFilePath, emitOutput, writeByteOrderMark);
writeFile(host, emitterDiagnostics, jsFilePath, emitOutput, writeByteOrderMark);
}
// Create a temporary variable with a unique unused name.
@@ -1263,7 +1256,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
function emitCommaList(nodes: Node[]) {
if (nodes) {
emitList(nodes, 0, nodes.length, /*multiline*/ false, /*trailingComma*/ false);
emitList(nodes, 0, nodes.length, /*multiLine*/ false, /*trailingComma*/ false);
}
}
@@ -1563,13 +1556,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
/// these emit into an object literal property name, we don't need to be worried
/// about keywords, just non-identifier characters
function emitAttributeName(name: Identifier) {
if (/[A-Za-z_]+[\w*]/.test(name.text)) {
write("\"");
if (/^[A-Za-z_]\w*$/.test(name.text)) {
emit(name);
write("\"");
}
else {
write("\"");
emit(name);
write("\"");
}
}
@@ -2162,7 +2155,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
else if (languageVersion >= ScriptTarget.ES6 || !forEach(elements, isSpreadElementExpression)) {
write("[");
emitLinePreservingList(node, node.elements, elements.hasTrailingComma, /*spacesBetweenBraces:*/ false);
emitLinePreservingList(node, node.elements, elements.hasTrailingComma, /*spacesBetweenBraces*/ false);
write("]");
}
else {
@@ -2186,7 +2179,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
// then try to preserve the original shape of the object literal.
// Otherwise just try to preserve the formatting.
if (numElements === properties.length) {
emitLinePreservingList(node, properties, /* allowTrailingComma */ languageVersion >= ScriptTarget.ES5, /* spacesBetweenBraces */ true);
emitLinePreservingList(node, properties, /*allowTrailingComma*/ languageVersion >= ScriptTarget.ES5, /*spacesBetweenBraces*/ true);
}
else {
const multiLine = (node.flags & NodeFlags.MultiLine) !== 0;
@@ -2461,7 +2454,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
// let obj = { y };
// }
// Here we need to emit obj = { y : m.y } regardless of the output target.
if (languageVersion < ScriptTarget.ES6 || isNamespaceExportReference(node.name)) {
if (modulekind !== ModuleKind.ES6 || isNamespaceExportReference(node.name)) {
// Emit identifier as an identifier
write(": ");
emit(node.name);
@@ -2736,7 +2729,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(".bind.apply(");
emit(target);
write(", [void 0].concat(");
emitListWithSpread(node.arguments, /*needsUniqueCopy*/ false, /*multiline*/ false, /*trailingComma*/ false, /*useConcat*/ false);
emitListWithSpread(node.arguments, /*needsUniqueCopy*/ false, /*multiLine*/ false, /*trailingComma*/ false, /*useConcat*/ false);
write(")))");
write("()");
}
@@ -2953,7 +2946,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
synthesizedLHS = <ElementAccessExpression>createSynthesizedNode(SyntaxKind.ElementAccessExpression, /*startsOnNewLine*/ false);
const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldEmitCommaBeforeAssignment*/ false);
const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefineTempVariablesInPlace*/ false, /*shouldEmitCommaBeforeAssignment*/ false);
synthesizedLHS.expression = identifier;
if (leftHandSideExpression.argumentExpression.kind !== SyntaxKind.NumericLiteral &&
@@ -2972,7 +2965,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write("(");
synthesizedLHS = <PropertyAccessExpression>createSynthesizedNode(SyntaxKind.PropertyAccessExpression, /*startsOnNewLine*/ false);
const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldemitCommaBeforeAssignment*/ false);
const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefineTempVariablesInPlace*/ false, /*shouldEmitCommaBeforeAssignment*/ false);
synthesizedLHS.expression = identifier;
(<PropertyAccessExpression>synthesizedLHS).dotToken = leftHandSideExpression.dotToken;
@@ -3152,10 +3145,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
function emitDoStatementWorker(node: DoStatement, loop: ConvertedLoop) {
write("do");
if (loop) {
emitConvertedLoopCall(loop, /* emitAsBlock */ true);
emitConvertedLoopCall(loop, /*emitAsBlock*/ true);
}
else {
emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true);
emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true);
}
if (node.statement.kind === SyntaxKind.Block) {
write(" ");
@@ -3178,10 +3171,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(")");
if (loop) {
emitConvertedLoopCall(loop, /* emitAsBlock */ true);
emitConvertedLoopCall(loop, /*emitAsBlock*/ true);
}
else {
emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true);
emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true);
}
}
@@ -3197,7 +3190,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
if (convertedLoopState && (getCombinedNodeFlags(decl) & NodeFlags.BlockScoped) === 0) {
// we are inside a converted loop - this can only happen in downlevel scenarios
// we are inside a converted loop - this can only happen in downlevel scenarios
// record names for all variable declarations
for (const varDecl of decl.declarations) {
hoistVariableDeclarationFromLoop(convertedLoopState, varDecl);
@@ -3503,8 +3496,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(`switch(${loopResultVariable}) {`);
increaseIndent();
emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalBreaks, /* isBreak */ true, loopResultVariable, outerLoop);
emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalContinues, /* isBreak */ false, loopResultVariable, outerLoop);
emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalBreaks, /*isBreak*/ true, loopResultVariable, outerLoop);
emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalContinues, /*isBreak*/ false, loopResultVariable, outerLoop);
decreaseIndent();
writeLine();
@@ -3522,7 +3515,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(`case "${labelMarker}": `);
// if there are no outer converted loop or outer label in question is located inside outer converted loop
// then emit labeled break\continue
// otherwise propagate pair 'label -> marker' to outer converted loop and emit 'return labelMarker' so outer loop can later decide what to do
// otherwise propagate pair 'label -> marker' to outer converted loop and emit 'return labelMarker' so outer loop can later decide what to do
if (!outerLoop || (outerLoop.labels && outerLoop.labels[labelText])) {
if (isBreak) {
write("break ");
@@ -3568,10 +3561,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(")");
if (loop) {
emitConvertedLoopCall(loop, /* emitAsBlock */ true);
emitConvertedLoopCall(loop, /*emitAsBlock*/ true);
}
else {
emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true);
emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true);
}
}
@@ -3609,10 +3602,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
emitToken(SyntaxKind.CloseParenToken, node.expression.end);
if (loop) {
emitConvertedLoopCall(loop, /* emitAsBlock */ true);
emitConvertedLoopCall(loop, /*emitAsBlock*/ true);
}
else {
emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true);
emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true);
}
}
@@ -3752,10 +3745,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
if (loop) {
writeLine();
emitConvertedLoopCall(loop, /* emitAsBlock */ false);
emitConvertedLoopCall(loop, /*emitAsBlock*/ false);
}
else {
emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ false);
emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ false);
}
writeLine();
@@ -3789,11 +3782,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
let labelMarker: string;
if (node.kind === SyntaxKind.BreakStatement) {
labelMarker = `break-${node.label.text}`;
setLabeledJump(convertedLoopState, /* isBreak */ true, node.label.text, labelMarker);
setLabeledJump(convertedLoopState, /*isBreak*/ true, node.label.text, labelMarker);
}
else {
labelMarker = `continue-${node.label.text}`;
setLabeledJump(convertedLoopState, /* isBreak */ false, node.label.text, labelMarker);
setLabeledJump(convertedLoopState, /*isBreak*/ false, node.label.text, labelMarker);
}
write(`return "${labelMarker}";`);
}
@@ -4215,15 +4208,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
return node;
}
function createPropertyAccessForDestructuringProperty(object: Expression, propName: Identifier | LiteralExpression): Expression {
// We create a synthetic copy of the identifier in order to avoid the rewriting that might
// otherwise occur when the identifier is emitted.
const syntheticName = <Identifier | LiteralExpression>createSynthesizedNode(propName.kind);
syntheticName.text = propName.text;
if (syntheticName.kind !== SyntaxKind.Identifier) {
return createElementAccessExpression(object, syntheticName);
function createPropertyAccessForDestructuringProperty(object: Expression, propName: PropertyName): Expression {
let index: Expression;
const nameIsComputed = propName.kind === SyntaxKind.ComputedPropertyName;
if (nameIsComputed) {
index = ensureIdentifier((<ComputedPropertyName>propName).expression, /*reuseIdentifierExpressions*/ false);
}
return createPropertyAccessExpression(object, syntheticName);
else {
// We create a synthetic copy of the identifier in order to avoid the rewriting that might
// otherwise occur when the identifier is emitted.
index = <Identifier | LiteralExpression>createSynthesizedNode(propName.kind);
(<Identifier | LiteralExpression>index).text = (<Identifier | LiteralExpression>propName).text;
}
return !nameIsComputed && index.kind === SyntaxKind.Identifier
? createPropertyAccessExpression(object, <Identifier>index)
: createElementAccessExpression(object, index);
}
function createSliceCall(value: Expression, sliceIndex: number): CallExpression {
@@ -4967,8 +4967,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
increaseIndent();
writeLine();
emitLeadingComments(node.body);
emitStart(body);
write("return ");
emit(body);
emitEnd(body);
write(";");
emitTrailingComments(node.body);
@@ -5342,7 +5344,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
emitEnd(baseTypeElement);
}
}
emitPropertyDeclarations(node, getInitializedProperties(node, /*static:*/ false));
emitPropertyDeclarations(node, getInitializedProperties(node, /*isStatic*/ false));
if (ctor) {
let statements: Node[] = (<Block>ctor.body).statements;
if (superCall) {
@@ -5464,7 +5466,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
//
// This keeps the expression as an expression, while ensuring that the static parts
// of it have been initialized by the time it is used.
const staticProperties = getInitializedProperties(node, /*static:*/ true);
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
const isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === SyntaxKind.ClassExpression;
let tempVariable: Identifier;
@@ -5526,7 +5528,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
for (var property of staticProperties) {
write(",");
writeLine();
emitPropertyDeclaration(node, property, /*receiver:*/ tempVariable, /*isExpression:*/ true);
emitPropertyDeclaration(node, property, /*receiver*/ tempVariable, /*isExpression*/ true);
}
write(",");
writeLine();
@@ -5600,7 +5602,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
writeLine();
emitConstructor(node, baseTypeNode);
emitMemberFunctionsForES5AndLower(node);
emitPropertyDeclarations(node, getInitializedProperties(node, /*static:*/ true));
emitPropertyDeclarations(node, getInitializedProperties(node, /*isStatic*/ true));
writeLine();
emitDecoratorsOfClass(node);
writeLine();
@@ -5970,6 +5972,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
case SyntaxKind.AnyKeyword:
case SyntaxKind.ThisType:
break;
default:
@@ -5988,9 +5991,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
// Clone the type name and parent it to a location outside of the current declaration.
const typeName = cloneEntityName(node.typeName);
typeName.parent = location;
const typeName = cloneEntityName(node.typeName, location);
const result = resolver.getTypeReferenceSerializationKind(typeName);
switch (result) {
case TypeReferenceSerializationKind.Unknown:
@@ -7297,7 +7298,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write("}"); // execute
}
function emitSystemModule(node: SourceFile): void {
function writeModuleName(node: SourceFile, emitRelativePathAsModuleName?: boolean): void {
let moduleName = node.moduleName;
if (moduleName || (emitRelativePathAsModuleName && (moduleName = getResolvedExternalModuleName(host, node)))) {
write(`"${moduleName}", `);
}
}
function emitSystemModule(node: SourceFile, emitRelativePathAsModuleName?: boolean): void {
collectExternalModuleInfo(node);
// System modules has the following shape
// System.register(['dep-1', ... 'dep-n'], function(exports) {/* module body function */})
@@ -7312,16 +7320,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
exportFunctionForFile = makeUniqueName("exports");
writeLine();
write("System.register(");
if (node.moduleName) {
write(`"${node.moduleName}", `);
}
writeModuleName(node, emitRelativePathAsModuleName);
write("[");
const groupIndices: Map<number> = {};
const dependencyGroups: DependencyGroup[] = [];
for (let i = 0; i < externalImports.length; ++i) {
const text = getExternalModuleNameText(externalImports[i]);
let text = getExternalModuleNameText(externalImports[i]);
if (hasProperty(groupIndices, text)) {
// deduplicate/group entries in dependency list by the dependency name
const groupIndex = groupIndices[text];
@@ -7337,6 +7343,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(", ");
}
if (emitRelativePathAsModuleName) {
const name = getExternalModuleNameFromDeclaration(host, resolver, externalImports[i]);
if (name) {
text = `"${name}"`;
}
}
write(text);
}
write(`], function(${exportFunctionForFile}) {`);
@@ -7357,7 +7369,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
importAliasNames: string[];
}
function getAMDDependencyNames(node: SourceFile, includeNonAmdDependencies: boolean): AMDDependencyNames {
function getAMDDependencyNames(node: SourceFile, includeNonAmdDependencies: boolean, emitRelativePathAsModuleName?: boolean): AMDDependencyNames {
// names of modules with corresponding parameter in the factory function
const aliasedModuleNames: string[] = [];
// names of modules with no corresponding parameters in factory function
@@ -7379,7 +7391,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
for (const importNode of externalImports) {
// Find the name of the external module
const externalModuleName = getExternalModuleNameText(importNode);
let externalModuleName = getExternalModuleNameText(importNode);
if (emitRelativePathAsModuleName) {
const name = getExternalModuleNameFromDeclaration(host, resolver, importNode);
if (name) {
externalModuleName = `"${name}"`;
}
}
// Find the name of the module alias, if there is one
const importAliasName = getLocalNameForExternalImport(importNode);
@@ -7395,7 +7414,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
return { aliasedModuleNames, unaliasedModuleNames, importAliasNames };
}
function emitAMDDependencies(node: SourceFile, includeNonAmdDependencies: boolean) {
function emitAMDDependencies(node: SourceFile, includeNonAmdDependencies: boolean, emitRelativePathAsModuleName?: boolean) {
// An AMD define function has the following shape:
// define(id?, dependencies?, factory);
//
@@ -7408,7 +7427,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
// `import "module"` or `<amd-dependency path= "a.css" />`
// we need to add modules without alias names to the end of the dependencies list
const dependencyNames = getAMDDependencyNames(node, includeNonAmdDependencies);
const dependencyNames = getAMDDependencyNames(node, includeNonAmdDependencies, emitRelativePathAsModuleName);
emitAMDDependencyList(dependencyNames);
write(", ");
emitAMDFactoryHeader(dependencyNames);
@@ -7436,16 +7455,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(") {");
}
function emitAMDModule(node: SourceFile) {
function emitAMDModule(node: SourceFile, emitRelativePathAsModuleName?: boolean) {
emitEmitHelpers(node);
collectExternalModuleInfo(node);
writeLine();
write("define(");
if (node.moduleName) {
write("\"" + node.moduleName + "\", ");
}
emitAMDDependencies(node, /*includeNonAmdDependencies*/ true);
writeModuleName(node, emitRelativePathAsModuleName);
emitAMDDependencies(node, /*includeNonAmdDependencies*/ true, emitRelativePathAsModuleName);
increaseIndent();
const startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ true);
emitExportStarHelper();
@@ -7694,8 +7711,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
emitDetachedCommentsAndUpdateCommentsInfo(node);
if (isExternalModule(node) || compilerOptions.isolatedModules) {
const emitModule = moduleEmitDelegates[modulekind] || moduleEmitDelegates[ModuleKind.CommonJS];
emitModule(node);
if (isOwnFileEmit || (!isExternalModule(node) && compilerOptions.isolatedModules)) {
const emitModule = moduleEmitDelegates[modulekind] || moduleEmitDelegates[ModuleKind.CommonJS];
emitModule(node);
}
else {
bundleEmitDelegates[modulekind](node, /*emitRelativePathAsModuleName*/true);
}
}
else {
// emit prologue directives prior to __extends
@@ -8035,11 +8057,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
* Emit comments associated with node that will not be emitted into JS file
*/
function emitCommentsOnNotEmittedNode(node: Node) {
emitLeadingCommentsWorker(node, /*isEmittedNode:*/ false);
emitLeadingCommentsWorker(node, /*isEmittedNode*/ false);
}
function emitLeadingComments(node: Node) {
return emitLeadingCommentsWorker(node, /*isEmittedNode:*/ true);
return emitLeadingCommentsWorker(node, /*isEmittedNode*/ true);
}
function emitLeadingCommentsWorker(node: Node, isEmittedNode: boolean) {
@@ -8068,7 +8090,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
emitNewLineBeforeLeadingComments(currentLineMap, writer, node, leadingComments);
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator:*/ true, newLine, writeComment);
emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment);
}
function emitTrailingComments(node: Node) {
@@ -8141,11 +8163,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
}
function emitFile(jsFilePath: string, sourceFile?: SourceFile) {
emitJavaScript(jsFilePath, sourceFile);
function emitFile({ jsFilePath, sourceMapFilePath, declarationFilePath}: { jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string },
sourceFiles: SourceFile[], isBundledEmit: boolean) {
// Make sure not to write js File and source map file if any of them cannot be written
if (!host.isEmitBlocked(jsFilePath)) {
emitJavaScript(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
}
else {
emitSkipped = true;
}
if (compilerOptions.declaration) {
writeDeclarationFile(jsFilePath, sourceFile, host, resolver, diagnostics);
if (declarationFilePath) {
emitSkipped = writeDeclarationFile(declarationFilePath, sourceFiles, isBundledEmit, host, resolver, emitterDiagnostics) || emitSkipped;
}
}
}
+84 -66
View File
@@ -1,5 +1,5 @@
/// <reference path="scanner.ts"/>
/// <reference path="utilities.ts"/>
/// <reference path="scanner.ts"/>
namespace ts {
/* @internal */ export let parseTime = 0;
@@ -534,7 +534,8 @@ namespace ts {
let parseErrorBeforeNextFinishedNode = false;
export function parseSourceFile(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, setParentNodes?: boolean): SourceFile {
initializeState(fileName, _sourceText, languageVersion, _syntaxCursor);
const isJavaScriptFile = hasJavaScriptFileExtension(fileName) || _sourceText.lastIndexOf("// @language=javascript", 0) === 0;
initializeState(fileName, _sourceText, languageVersion, isJavaScriptFile, _syntaxCursor);
const result = parseSourceFileWorker(fileName, languageVersion, setParentNodes);
@@ -543,7 +544,12 @@ namespace ts {
return result;
}
function initializeState(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor) {
function getLanguageVariant(fileName: string) {
// .tsx and .jsx files are treated as jsx language variant.
return fileExtensionIs(fileName, ".tsx") || fileExtensionIs(fileName, ".jsx") ? LanguageVariant.JSX : LanguageVariant.Standard;
}
function initializeState(fileName: string, _sourceText: string, languageVersion: ScriptTarget, isJavaScriptFile: boolean, _syntaxCursor: IncrementalParser.SyntaxCursor) {
NodeConstructor = objectAllocator.getNodeConstructor();
SourceFileConstructor = objectAllocator.getSourceFileConstructor();
@@ -556,14 +562,14 @@ namespace ts {
identifierCount = 0;
nodeCount = 0;
contextFlags = isJavaScript(fileName) ? ParserContextFlags.JavaScriptFile : ParserContextFlags.None;
contextFlags = isJavaScriptFile ? ParserContextFlags.JavaScriptFile : ParserContextFlags.None;
parseErrorBeforeNextFinishedNode = false;
// Initialize and prime the scanner before parsing the source elements.
scanner.setText(sourceText);
scanner.setOnError(scanError);
scanner.setScriptTarget(languageVersion);
scanner.setLanguageVariant(isTsx(fileName) ? LanguageVariant.JSX : LanguageVariant.Standard);
scanner.setLanguageVariant(getLanguageVariant(fileName));
}
function clearState() {
@@ -582,6 +588,10 @@ namespace ts {
function parseSourceFileWorker(fileName: string, languageVersion: ScriptTarget, setParentNodes: boolean): SourceFile {
sourceFile = createSourceFile(fileName, languageVersion);
if (contextFlags & ParserContextFlags.JavaScriptFile) {
sourceFile.parserContextFlags = ParserContextFlags.JavaScriptFile;
}
// Prime the scanner.
token = nextToken();
processReferenceComments(sourceFile);
@@ -604,7 +614,7 @@ namespace ts {
// If this is a javascript file, proactively see if we can get JSDoc comments for
// relevant nodes in the file. We'll use these to provide typing informaion if they're
// available.
if (isJavaScript(fileName)) {
if (isSourceFileJavaScript(sourceFile)) {
addJSDocComments();
}
@@ -677,7 +687,7 @@ namespace ts {
sourceFile.languageVersion = languageVersion;
sourceFile.fileName = normalizePath(fileName);
sourceFile.flags = fileExtensionIs(sourceFile.fileName, ".d.ts") ? NodeFlags.DeclarationFile : 0;
sourceFile.languageVariant = isTsx(sourceFile.fileName) ? LanguageVariant.JSX : LanguageVariant.Standard;
sourceFile.languageVariant = getLanguageVariant(sourceFile.fileName);
return sourceFile;
}
@@ -717,10 +727,10 @@ namespace ts {
const contextFlagsToClear = context & contextFlags;
if (contextFlagsToClear) {
// clear the requested context flags
setContextFlag(false, contextFlagsToClear);
setContextFlag(/*val*/ false, contextFlagsToClear);
const result = func();
// restore the context flags we just cleared
setContextFlag(true, contextFlagsToClear);
setContextFlag(/*val*/ true, contextFlagsToClear);
return result;
}
@@ -738,10 +748,10 @@ namespace ts {
const contextFlagsToSet = context & ~contextFlags;
if (contextFlagsToSet) {
// set the requested context flags
setContextFlag(true, contextFlagsToSet);
setContextFlag(/*val*/ true, contextFlagsToSet);
const result = func();
// reset the context flags we just set
setContextFlag(false, contextFlagsToSet);
setContextFlag(/*val*/ false, contextFlagsToSet);
return result;
}
@@ -1082,7 +1092,7 @@ namespace ts {
token === SyntaxKind.NumericLiteral;
}
function parsePropertyNameWorker(allowComputedPropertyNames: boolean): DeclarationName {
function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName {
if (token === SyntaxKind.StringLiteral || token === SyntaxKind.NumericLiteral) {
return parseLiteralNode(/*internName*/ true);
}
@@ -1092,12 +1102,12 @@ namespace ts {
return parseIdentifierName();
}
function parsePropertyName(): DeclarationName {
return parsePropertyNameWorker(/*allowComputedPropertyNames:*/ true);
function parsePropertyName(): PropertyName {
return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true);
}
function parseSimplePropertyName(): Identifier | LiteralExpression {
return <Identifier | LiteralExpression>parsePropertyNameWorker(/*allowComputedPropertyNames:*/ false);
return <Identifier | LiteralExpression>parsePropertyNameWorker(/*allowComputedPropertyNames*/ false);
}
function isSimplePropertyName() {
@@ -1152,7 +1162,7 @@ namespace ts {
}
function parseAnyContextualModifier(): boolean {
return isModifier(token) && tryParse(nextTokenCanFollowModifier);
return isModifierKind(token) && tryParse(nextTokenCanFollowModifier);
}
function canFollowModifier(): boolean {
@@ -1202,7 +1212,7 @@ namespace ts {
case ParsingContext.ObjectLiteralMembers:
return token === SyntaxKind.OpenBracketToken || token === SyntaxKind.AsteriskToken || isLiteralPropertyName();
case ParsingContext.ObjectBindingElements:
return isLiteralPropertyName();
return token === SyntaxKind.OpenBracketToken || isLiteralPropertyName();
case ParsingContext.HeritageClauseElement:
// If we see { } then only consume it as an expression if it is followed by , or {
// That way we won't consume the body of a class in its heritage clause.
@@ -1380,7 +1390,7 @@ namespace ts {
function isInSomeParsingContext(): boolean {
for (let kind = 0; kind < ParsingContext.Count; kind++) {
if (parsingContext & (1 << kind)) {
if (isListElement(kind, /* inErrorRecovery */ true) || isListTerminator(kind)) {
if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) {
return true;
}
}
@@ -1397,7 +1407,7 @@ namespace ts {
result.pos = getNodePos();
while (!isListTerminator(kind)) {
if (isListElement(kind, /* inErrorRecovery */ false)) {
if (isListElement(kind, /*inErrorRecovery*/ false)) {
const element = parseListElement(kind, parseElement);
result.push(element);
@@ -1746,7 +1756,7 @@ namespace ts {
let commaStart = -1; // Meaning the previous token was not a comma
while (true) {
if (isListElement(kind, /* inErrorRecovery */ false)) {
if (isListElement(kind, /*inErrorRecovery*/ false)) {
result.push(parseListElement(kind, parseElement));
commaStart = scanner.getTokenPos();
if (parseOptional(SyntaxKind.CommaToken)) {
@@ -1854,7 +1864,7 @@ namespace ts {
// Report that we need an identifier. However, report it right after the dot,
// and not on the next token. This is because the next token might actually
// be an identifier and the error would be quite confusing.
return <Identifier>createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentToken*/ true, Diagnostics.Identifier_expected);
return <Identifier>createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
}
}
@@ -1951,6 +1961,12 @@ namespace ts {
return finishNode(node);
}
function parseThisTypeNode(): TypeNode {
const node = <TypeNode>createNode(SyntaxKind.ThisType);
nextToken();
return finishNode(node);
}
function parseTypeQuery(): TypeQueryNode {
const node = <TypeQueryNode>createNode(SyntaxKind.TypeQuery);
parseExpected(SyntaxKind.TypeOfKeyword);
@@ -1992,16 +2008,14 @@ namespace ts {
function parseParameterType(): TypeNode {
if (parseOptional(SyntaxKind.ColonToken)) {
return token === SyntaxKind.StringLiteral
? <StringLiteral>parseLiteralNode(/*internName*/ true)
: parseType();
return parseType();
}
return undefined;
}
function isStartOfParameter(): boolean {
return token === SyntaxKind.DotDotDotToken || isIdentifierOrPattern() || isModifier(token) || token === SyntaxKind.AtToken;
return token === SyntaxKind.DotDotDotToken || isIdentifierOrPattern() || isModifierKind(token) || token === SyntaxKind.AtToken;
}
function setModifiers(node: Node, modifiers: ModifiersArray) {
@@ -2022,7 +2036,7 @@ namespace ts {
node.name = parseIdentifierOrPattern();
if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifier(token)) {
if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifierKind(token)) {
// in cases like
// 'use strict'
// function foo(static)
@@ -2129,8 +2143,8 @@ namespace ts {
parseSemicolon();
}
function parseSignatureMember(kind: SyntaxKind): SignatureDeclaration {
const node = <SignatureDeclaration>createNode(kind);
function parseSignatureMember(kind: SyntaxKind): CallSignatureDeclaration | ConstructSignatureDeclaration {
const node = <CallSignatureDeclaration | ConstructSignatureDeclaration>createNode(kind);
if (kind === SyntaxKind.ConstructSignature) {
parseExpected(SyntaxKind.NewKeyword);
}
@@ -2169,7 +2183,7 @@ namespace ts {
return true;
}
if (isModifier(token)) {
if (isModifierKind(token)) {
nextToken();
if (isIdentifier()) {
return true;
@@ -2212,13 +2226,13 @@ namespace ts {
return finishNode(node);
}
function parsePropertyOrMethodSignature(): Declaration {
function parsePropertyOrMethodSignature(): PropertySignature | MethodSignature {
const fullStart = scanner.getStartPos();
const name = parsePropertyName();
const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) {
const method = <MethodDeclaration>createNode(SyntaxKind.MethodSignature, fullStart);
const method = <MethodSignature>createNode(SyntaxKind.MethodSignature, fullStart);
method.name = name;
method.questionToken = questionToken;
@@ -2229,7 +2243,7 @@ namespace ts {
return finishNode(method);
}
else {
const property = <PropertyDeclaration>createNode(SyntaxKind.PropertySignature, fullStart);
const property = <PropertySignature>createNode(SyntaxKind.PropertySignature, fullStart);
property.name = name;
property.questionToken = questionToken;
property.type = parseTypeAnnotation();
@@ -2245,7 +2259,7 @@ namespace ts {
case SyntaxKind.OpenBracketToken: // Both for indexers and computed properties
return true;
default:
if (isModifier(token)) {
if (isModifierKind(token)) {
const result = lookAhead(isStartOfIndexSignatureDeclaration);
if (result) {
return result;
@@ -2257,7 +2271,7 @@ namespace ts {
}
function isStartOfIndexSignatureDeclaration() {
while (isModifier(token)) {
while (isModifierKind(token)) {
nextToken();
}
@@ -2273,7 +2287,7 @@ namespace ts {
canParseSemicolon();
}
function parseTypeMember(): Declaration {
function parseTypeMember(): TypeElement {
switch (token) {
case SyntaxKind.OpenParenToken:
case SyntaxKind.LessThanToken:
@@ -2298,7 +2312,7 @@ namespace ts {
// when incrementally parsing as the parser will produce the Index declaration
// if it has the same text regardless of whether it is inside a class or an
// object type.
if (isModifier(token)) {
if (isModifierKind(token)) {
const result = tryParse(parseIndexSignatureWithModifiers);
if (result) {
return result;
@@ -2331,14 +2345,14 @@ namespace ts {
return finishNode(node);
}
function parseObjectTypeMembers(): NodeArray<Declaration> {
let members: NodeArray<Declaration>;
function parseObjectTypeMembers(): NodeArray<TypeElement> {
let members: NodeArray<TypeElement>;
if (parseExpected(SyntaxKind.OpenBraceToken)) {
members = parseList(ParsingContext.TypeMembers, parseTypeMember);
parseExpected(SyntaxKind.CloseBraceToken);
}
else {
members = createMissingList<Declaration>();
members = createMissingList<TypeElement>();
}
return members;
@@ -2382,9 +2396,12 @@ namespace ts {
// If these are followed by a dot, then parse these out as a dotted type reference instead.
const node = tryParse(parseKeywordAndNoDot);
return node || parseTypeReferenceOrTypePredicate();
case SyntaxKind.StringLiteral:
return <StringLiteral>parseLiteralNode(/*internName*/ true);
case SyntaxKind.VoidKeyword:
case SyntaxKind.ThisKeyword:
return parseTokenNode<TypeNode>();
case SyntaxKind.ThisKeyword:
return parseThisTypeNode();
case SyntaxKind.TypeOfKeyword:
return parseTypeQuery();
case SyntaxKind.OpenBraceToken:
@@ -2412,6 +2429,7 @@ namespace ts {
case SyntaxKind.OpenBracketToken:
case SyntaxKind.LessThanToken:
case SyntaxKind.NewKeyword:
case SyntaxKind.StringLiteral:
return true;
case SyntaxKind.OpenParenToken:
// Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier,
@@ -2477,11 +2495,11 @@ namespace ts {
// ( ...
return true;
}
if (isIdentifier() || isModifier(token)) {
if (isIdentifier() || isModifierKind(token)) {
nextToken();
if (token === SyntaxKind.ColonToken || token === SyntaxKind.CommaToken ||
token === SyntaxKind.QuestionToken || token === SyntaxKind.EqualsToken ||
isIdentifier() || isModifier(token)) {
isIdentifier() || isModifierKind(token)) {
// ( id :
// ( id ,
// ( id ?
@@ -2603,7 +2621,7 @@ namespace ts {
// clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator
const saveDecoratorContext = inDecoratorContext();
if (saveDecoratorContext) {
setDecoratorContext(false);
setDecoratorContext(/*val*/ false);
}
let expr = parseAssignmentExpressionOrHigher();
@@ -2613,7 +2631,7 @@ namespace ts {
}
if (saveDecoratorContext) {
setDecoratorContext(true);
setDecoratorContext(/*val*/ true);
}
return expr;
}
@@ -2767,7 +2785,7 @@ namespace ts {
node.parameters.pos = parameter.pos;
node.parameters.end = parameter.end;
node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>");
node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>");
node.body = parseArrowFunctionExpressionBody(/*isAsync*/ false);
return finishNode(node);
@@ -2888,7 +2906,7 @@ namespace ts {
}
// This *could* be a parenthesized arrow function.
// Return Unknown to const the caller know.
// Return Unknown to let the caller know.
return Tristate.Unknown;
}
else {
@@ -2987,7 +3005,7 @@ namespace ts {
// user meant to supply a block. For example, if the user wrote:
//
// a =>
// const v = 0;
// let v = 0;
// }
//
// they may be missing an open brace. Check to see if that's the case so we can
@@ -3214,7 +3232,7 @@ namespace ts {
/**
* Parse ES7 unary expression and await expression
*
*
* ES7 UnaryExpression:
* 1) SimpleUnaryExpression[?yield]
* 2) IncrementExpression[?yield] ** UnaryExpression[?yield]
@@ -3567,7 +3585,7 @@ namespace ts {
parseExpected(SyntaxKind.GreaterThanToken);
}
else {
parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*advance*/ false);
parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false);
scanJsxText();
}
node = <JsxSelfClosingElement>createNode(SyntaxKind.JsxSelfClosingElement, fullStart);
@@ -3603,7 +3621,7 @@ namespace ts {
parseExpected(SyntaxKind.CloseBraceToken);
}
else {
parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*advance*/ false);
parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false);
scanJsxText();
}
@@ -3648,7 +3666,7 @@ namespace ts {
parseExpected(SyntaxKind.GreaterThanToken);
}
else {
parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*advance*/ false);
parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false);
scanJsxText();
}
return finishNode(node);
@@ -3967,7 +3985,7 @@ namespace ts {
// function BindingIdentifier[opt](FormalParameters){ FunctionBody }
const saveDecoratorContext = inDecoratorContext();
if (saveDecoratorContext) {
setDecoratorContext(false);
setDecoratorContext(/*val*/ false);
}
const node = <FunctionExpression>createNode(SyntaxKind.FunctionExpression);
@@ -3987,7 +4005,7 @@ namespace ts {
node.body = parseFunctionBlock(/*allowYield*/ isGenerator, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ false);
if (saveDecoratorContext) {
setDecoratorContext(true);
setDecoratorContext(/*val*/ true);
}
return finishNode(node);
@@ -4033,13 +4051,13 @@ namespace ts {
// arrow function. The body of the function is not in [Decorator] context.
const saveDecoratorContext = inDecoratorContext();
if (saveDecoratorContext) {
setDecoratorContext(false);
setDecoratorContext(/*val*/ false);
}
const block = parseBlock(ignoreMissingOpenBrace, diagnosticMessage);
if (saveDecoratorContext) {
setDecoratorContext(true);
setDecoratorContext(/*val*/ true);
}
setYieldContext(savedYieldContext);
@@ -4581,7 +4599,6 @@ namespace ts {
function parseObjectBindingElement(): BindingElement {
const node = <BindingElement>createNode(SyntaxKind.BindingElement);
// TODO(andersh): Handle computed properties
const tokenIsIdentifier = isIdentifier();
const propertyName = parsePropertyName();
if (tokenIsIdentifier && token !== SyntaxKind.ColonToken) {
@@ -4589,7 +4606,7 @@ namespace ts {
}
else {
parseExpected(SyntaxKind.ColonToken);
node.propertyName = <Identifier>propertyName;
node.propertyName = propertyName;
node.name = parseIdentifierOrPattern();
}
node.initializer = parseBindingElementInitializer(/*inParameter*/ false);
@@ -4715,7 +4732,7 @@ namespace ts {
return finishNode(node);
}
function parseMethodDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray, asteriskToken: Node, name: DeclarationName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration {
function parseMethodDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray, asteriskToken: Node, name: PropertyName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration {
const method = <MethodDeclaration>createNode(SyntaxKind.MethodDeclaration, fullStart);
method.decorators = decorators;
setModifiers(method, modifiers);
@@ -4729,7 +4746,7 @@ namespace ts {
return finishNode(method);
}
function parsePropertyDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray, name: DeclarationName, questionToken: Node): ClassElement {
function parsePropertyDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray, name: PropertyName, questionToken: Node): ClassElement {
const property = <PropertyDeclaration>createNode(SyntaxKind.PropertyDeclaration, fullStart);
property.decorators = decorators;
setModifiers(property, modifiers);
@@ -4803,7 +4820,7 @@ namespace ts {
}
// Eat up all modifiers, but hold on to the last one in case it is actually an identifier.
while (isModifier(token)) {
while (isModifierKind(token)) {
idToken = token;
// If the idToken is a class modifier (protected, private, public, and static), it is
// certain that we are starting to parse class member. This allows better error recovery
@@ -5013,8 +5030,8 @@ namespace ts {
// implements is a future reserved word so
// 'class implements' might mean either
// - class expression with omitted name, 'implements' starts heritage clause
// - class with name 'implements'
// 'isImplementsClause' helps to disambiguate between these two cases
// - class with name 'implements'
// 'isImplementsClause' helps to disambiguate between these two cases
return isIdentifier() && !isImplementsClause()
? parseIdentifier()
: undefined;
@@ -5518,7 +5535,7 @@ namespace ts {
}
export function parseJSDocTypeExpressionForTests(content: string, start: number, length: number) {
initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined);
initializeState("file.js", content, ScriptTarget.Latest, /*isJavaScriptFile*/ true, /*_syntaxCursor:*/ undefined);
const jsDocTypeExpression = parseJSDocTypeExpression(start, length);
const diagnostics = parseDiagnostics;
clearState();
@@ -5629,6 +5646,7 @@ namespace ts {
return parseTokenNode<JSDocType>();
}
// TODO (drosen): Parse string literal types in JSDoc as well.
return parseJSDocTypeReference();
}
@@ -5838,7 +5856,7 @@ namespace ts {
}
export function parseIsolatedJSDocComment(content: string, start: number, length: number) {
initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined);
initializeState("file.js", content, ScriptTarget.Latest, /*isJavaScriptFile*/ true, /*_syntaxCursor:*/ undefined);
const jsDocComment = parseJSDocComment(/*parent:*/ undefined, start, length);
const diagnostics = parseDiagnostics;
clearState();
@@ -6156,7 +6174,7 @@ namespace ts {
if (sourceFile.statements.length === 0) {
// If we don't have any statements in the current source file, then there's no real
// way to incrementally parse. So just do a full parse instead.
return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setNodeParents*/ true);
return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true);
}
// Make sure we're not trying to incrementally update a source file more than once. Once
@@ -6220,7 +6238,7 @@ namespace ts {
// inconsistent tree. Setting the parents on the new tree should be very fast. We
// will immediately bail out of walking any subtrees when we can see that their parents
// are already correct.
const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /* setParentNode */ true);
const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true);
return result;
}
+322 -77
View File
@@ -14,10 +14,10 @@ namespace ts {
export const version = "1.8.0";
export function findConfigFile(searchPath: string): string {
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean): string {
let fileName = "tsconfig.json";
while (true) {
if (sys.fileExists(fileName)) {
if (fileExists(fileName)) {
return fileName;
}
const parentPath = getDirectoryPath(searchPath);
@@ -42,24 +42,24 @@ namespace ts {
: compilerOptions.module === ModuleKind.CommonJS ? ModuleResolutionKind.NodeJs : ModuleResolutionKind.Classic;
switch (moduleResolution) {
case ModuleResolutionKind.NodeJs: return nodeModuleNameResolver(moduleName, containingFile, host);
case ModuleResolutionKind.NodeJs: return nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host);
case ModuleResolutionKind.Classic: return classicNameResolver(moduleName, containingFile, compilerOptions, host);
}
}
export function nodeModuleNameResolver(moduleName: string, containingFile: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
const containingDirectory = getDirectoryPath(containingFile);
const supportedExtensions = getSupportedExtensions(compilerOptions);
if (getRootLength(moduleName) !== 0 || nameStartsWithDotSlashOrDotDotSlash(moduleName)) {
const failedLookupLocations: string[] = [];
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
let resolvedFileName = loadNodeModuleFromFile(candidate, failedLookupLocations, host);
let resolvedFileName = loadNodeModuleFromFile(supportedExtensions, candidate, failedLookupLocations, host);
if (resolvedFileName) {
return { resolvedModule: { resolvedFileName }, failedLookupLocations };
}
resolvedFileName = loadNodeModuleFromDirectory(candidate, failedLookupLocations, host);
resolvedFileName = loadNodeModuleFromDirectory(supportedExtensions, candidate, failedLookupLocations, host);
return resolvedFileName
? { resolvedModule: { resolvedFileName }, failedLookupLocations }
: { resolvedModule: undefined, failedLookupLocations };
@@ -69,8 +69,8 @@ namespace ts {
}
}
function loadNodeModuleFromFile(candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string {
return forEach(moduleFileExtensions, tryLoad);
function loadNodeModuleFromFile(extensions: string[], candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string {
return forEach(extensions, tryLoad);
function tryLoad(ext: string): string {
const fileName = fileExtensionIs(candidate, ext) ? candidate : candidate + ext;
@@ -84,7 +84,7 @@ namespace ts {
}
}
function loadNodeModuleFromDirectory(candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string {
function loadNodeModuleFromDirectory(extensions: string[], candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string {
const packageJsonPath = combinePaths(candidate, "package.json");
if (host.fileExists(packageJsonPath)) {
@@ -100,7 +100,7 @@ namespace ts {
}
if (jsonContent.typings) {
const result = loadNodeModuleFromFile(normalizePath(combinePaths(candidate, jsonContent.typings)), failedLookupLocation, host);
const result = loadNodeModuleFromFile(extensions, normalizePath(combinePaths(candidate, jsonContent.typings)), failedLookupLocation, host);
if (result) {
return result;
}
@@ -111,7 +111,7 @@ namespace ts {
failedLookupLocation.push(packageJsonPath);
}
return loadNodeModuleFromFile(combinePaths(candidate, "index"), failedLookupLocation, host);
return loadNodeModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocation, host);
}
function loadModuleFromNodeModules(moduleName: string, directory: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
@@ -122,12 +122,13 @@ namespace ts {
if (baseName !== "node_modules") {
const nodeModulesFolder = combinePaths(directory, "node_modules");
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
let result = loadNodeModuleFromFile(candidate, failedLookupLocations, host);
// Load only typescript files irrespective of allowJs option if loading from node modules
let result = loadNodeModuleFromFile(supportedTypeScriptExtensions, candidate, failedLookupLocations, host);
if (result) {
return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations };
}
result = loadNodeModuleFromDirectory(candidate, failedLookupLocations, host);
result = loadNodeModuleFromDirectory(supportedTypeScriptExtensions, candidate, failedLookupLocations, host);
if (result) {
return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations };
}
@@ -162,6 +163,7 @@ namespace ts {
const failedLookupLocations: string[] = [];
let referencedSourceFile: string;
const supportedExtensions = getSupportedExtensions(compilerOptions);
while (true) {
searchName = normalizePath(combinePaths(searchPath, moduleName));
referencedSourceFile = forEach(supportedExtensions, extension => {
@@ -284,13 +286,13 @@ namespace ts {
}
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[] {
const diagnostics = program.getOptionsDiagnostics(cancellationToken).concat(
let diagnostics = program.getOptionsDiagnostics(cancellationToken).concat(
program.getSyntacticDiagnostics(sourceFile, cancellationToken),
program.getGlobalDiagnostics(cancellationToken),
program.getSemanticDiagnostics(sourceFile, cancellationToken));
if (program.getCompilerOptions().declaration) {
diagnostics.concat(program.getDeclarationDiagnostics(sourceFile, cancellationToken));
diagnostics = diagnostics.concat(program.getDeclarationDiagnostics(sourceFile, cancellationToken));
}
return sortAndDeduplicateDiagnostics(diagnostics);
@@ -334,10 +336,13 @@ namespace ts {
let classifiableNames: Map<string>;
let skipDefaultLib = options.noLib;
const supportedExtensions = getSupportedExtensions(options);
const start = new Date().getTime();
host = host || createCompilerHost(options);
// Map storing if there is emit blocking diagnostics for given input
const hasEmitBlockingDiagnostics = createFileMap<boolean>(getCanonicalFileName);
const currentDirectory = host.getCurrentDirectory();
const resolveModuleNamesWorker = host.resolveModuleNames
@@ -357,29 +362,26 @@ namespace ts {
(oldOptions.noResolve !== options.noResolve) ||
(oldOptions.target !== options.target) ||
(oldOptions.noLib !== options.noLib) ||
(oldOptions.jsx !== options.jsx)) {
(oldOptions.jsx !== options.jsx) ||
(oldOptions.allowJs !== options.allowJs)) {
oldProgram = undefined;
}
}
if (!tryReuseStructureFromOldProgram()) {
forEach(rootNames, name => processRootFile(name, false));
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false));
// Do not process the default library if:
// - The '--noLib' flag is used.
// - A 'no-default-lib' reference comment is encountered in
// processing the root files.
if (!skipDefaultLib) {
processRootFile(host.getDefaultLibFileName(options), true);
processRootFile(host.getDefaultLibFileName(options), /*isDefaultLib*/ true);
}
}
verifyCompilerOptions();
// unconditionally set oldProgram to undefined to prevent it from being captured in closure
oldProgram = undefined;
programTime += new Date().getTime() - start;
program = {
getRootFileNames: () => rootNames,
getSourceFile,
@@ -402,6 +404,11 @@ namespace ts {
getTypeCount: () => getDiagnosticsProducingTypeChecker().getTypeCount(),
getFileProcessingDiagnostics: () => fileProcessingDiagnostics
};
verifyCompilerOptions();
programTime += new Date().getTime() - start;
return program;
function getClassifiableNames() {
@@ -523,6 +530,7 @@ namespace ts {
getSourceFiles: program.getSourceFiles,
writeFile: writeFileCallback || (
(fileName, data, writeByteOrderMark, onError) => host.writeFile(fileName, data, writeByteOrderMark, onError)),
isEmitBlocked,
};
}
@@ -538,6 +546,10 @@ namespace ts {
return runWithCancellationToken(() => emitWorker(this, sourceFile, writeFileCallback, cancellationToken));
}
function isEmitBlocked(emitFileName: string): boolean {
return hasEmitBlockingDiagnostics.contains(toPath(emitFileName, currentDirectory, getCanonicalFileName));
}
function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken): EmitResult {
// If the noEmitOnError flag is set, then check if we have any errors so far. If so,
// immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we
@@ -630,6 +642,13 @@ namespace ts {
}
function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
// 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
// JavaScript file.
if (isSourceFileJavaScript(sourceFile)) {
return getJavaScriptSemanticDiagnosticsForFile(sourceFile, cancellationToken);
}
return runWithCancellationToken(() => {
const typeChecker = getDiagnosticsProducingTypeChecker();
@@ -643,6 +662,165 @@ namespace ts {
});
}
function getJavaScriptSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
return runWithCancellationToken(() => {
const diagnostics: Diagnostic[] = [];
walk(sourceFile);
return diagnostics;
function walk(node: Node): boolean {
if (!node) {
return false;
}
switch (node.kind) {
case SyntaxKind.ImportEqualsDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.ExportAssignment:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.ClassDeclaration:
let classDeclaration = <ClassDeclaration>node;
if (checkModifiers(classDeclaration.modifiers) ||
checkTypeParameters(classDeclaration.typeParameters)) {
return true;
}
break;
case SyntaxKind.HeritageClause:
let heritageClause = <HeritageClause>node;
if (heritageClause.token === SyntaxKind.ImplementsKeyword) {
diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_a_ts_file));
return true;
}
break;
case SyntaxKind.InterfaceDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.interface_declarations_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.ModuleDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.module_declarations_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.TypeAliasDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.type_aliases_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ArrowFunction:
case SyntaxKind.FunctionDeclaration:
const functionDeclaration = <FunctionLikeDeclaration>node;
if (checkModifiers(functionDeclaration.modifiers) ||
checkTypeParameters(functionDeclaration.typeParameters) ||
checkTypeAnnotation(functionDeclaration.type)) {
return true;
}
break;
case SyntaxKind.VariableStatement:
const variableStatement = <VariableStatement>node;
if (checkModifiers(variableStatement.modifiers)) {
return true;
}
break;
case SyntaxKind.VariableDeclaration:
const variableDeclaration = <VariableDeclaration>node;
if (checkTypeAnnotation(variableDeclaration.type)) {
return true;
}
break;
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
const expression = <CallExpression>node;
if (expression.typeArguments && expression.typeArguments.length > 0) {
const start = expression.typeArguments.pos;
diagnostics.push(createFileDiagnostic(sourceFile, start, expression.typeArguments.end - start,
Diagnostics.type_arguments_can_only_be_used_in_a_ts_file));
return true;
}
break;
case SyntaxKind.Parameter:
const parameter = <ParameterDeclaration>node;
if (parameter.modifiers) {
const start = parameter.modifiers.pos;
diagnostics.push(createFileDiagnostic(sourceFile, start, parameter.modifiers.end - start,
Diagnostics.parameter_modifiers_can_only_be_used_in_a_ts_file));
return true;
}
if (parameter.questionToken) {
diagnostics.push(createDiagnosticForNode(parameter.questionToken, Diagnostics._0_can_only_be_used_in_a_ts_file, "?"));
return true;
}
if (parameter.type) {
diagnostics.push(createDiagnosticForNode(parameter.type, Diagnostics.types_can_only_be_used_in_a_ts_file));
return true;
}
break;
case SyntaxKind.PropertyDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.property_declarations_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.EnumDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.TypeAssertionExpression:
let typeAssertionExpression = <TypeAssertion>node;
diagnostics.push(createDiagnosticForNode(typeAssertionExpression.type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.Decorator:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.decorators_can_only_be_used_in_a_ts_file));
return true;
}
return forEachChild(node, walk);
}
function checkTypeParameters(typeParameters: NodeArray<TypeParameterDeclaration>): boolean {
if (typeParameters) {
const start = typeParameters.pos;
diagnostics.push(createFileDiagnostic(sourceFile, start, typeParameters.end - start, Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file));
return true;
}
return false;
}
function checkTypeAnnotation(type: TypeNode): boolean {
if (type) {
diagnostics.push(createDiagnosticForNode(type, Diagnostics.types_can_only_be_used_in_a_ts_file));
return true;
}
return false;
}
function checkModifiers(modifiers: ModifiersArray): boolean {
if (modifiers) {
for (const modifier of modifiers) {
switch (modifier.kind) {
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.DeclareKeyword:
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
return true;
// These are all legal modifiers.
case SyntaxKind.StaticKeyword:
case SyntaxKind.ExportKeyword:
case SyntaxKind.ConstKeyword:
case SyntaxKind.DefaultKeyword:
case SyntaxKind.AbstractKeyword:
}
}
}
return false;
}
});
}
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
return runWithCancellationToken(() => {
if (!isDeclarationFile(sourceFile)) {
@@ -688,45 +866,60 @@ namespace ts {
return;
}
const isJavaScriptFile = isSourceFileJavaScript(file);
let imports: LiteralExpression[];
for (const node of file.statements) {
collect(node, /* allowRelativeModuleNames */ true);
collect(node, /*allowRelativeModuleNames*/ true, /*collectOnlyRequireCalls*/ false);
}
file.imports = imports || emptyArray;
function collect(node: Node, allowRelativeModuleNames: boolean): void {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ExportDeclaration:
let moduleNameExpr = getExternalModuleName(node);
if (!moduleNameExpr || moduleNameExpr.kind !== SyntaxKind.StringLiteral) {
break;
}
if (!(<LiteralExpression>moduleNameExpr).text) {
break;
}
return;
if (allowRelativeModuleNames || !isExternalModuleNameRelative((<LiteralExpression>moduleNameExpr).text)) {
(imports || (imports = [])).push(<LiteralExpression>moduleNameExpr);
}
break;
case SyntaxKind.ModuleDeclaration:
if ((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral && (node.flags & NodeFlags.Ambient || isDeclarationFile(file))) {
// TypeScript 1.0 spec (April 2014): 12.1.6
// An AmbientExternalModuleDeclaration declares an external module.
// This type of declaration is permitted only in the global module.
// The StringLiteral must specify a top - level external module name.
// Relative external module names are not permitted
forEachChild((<ModuleDeclaration>node).body, node => {
function collect(node: Node, allowRelativeModuleNames: boolean, collectOnlyRequireCalls: boolean): void {
if (!collectOnlyRequireCalls) {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ExportDeclaration:
let moduleNameExpr = getExternalModuleName(node);
if (!moduleNameExpr || moduleNameExpr.kind !== SyntaxKind.StringLiteral) {
break;
}
if (!(<LiteralExpression>moduleNameExpr).text) {
break;
}
if (allowRelativeModuleNames || !isExternalModuleNameRelative((<LiteralExpression>moduleNameExpr).text)) {
(imports || (imports = [])).push(<LiteralExpression>moduleNameExpr);
}
break;
case SyntaxKind.ModuleDeclaration:
if ((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral && (node.flags & NodeFlags.Ambient || isDeclarationFile(file))) {
// TypeScript 1.0 spec (April 2014): 12.1.6
// An ExternalImportDeclaration in anAmbientExternalModuleDeclaration may reference other external modules
// only through top - level external module names. Relative external module names are not permitted.
collect(node, /* allowRelativeModuleNames */ false);
});
}
break;
// An AmbientExternalModuleDeclaration declares an external module.
// This type of declaration is permitted only in the global module.
// The StringLiteral must specify a top - level external module name.
// Relative external module names are not permitted
forEachChild((<ModuleDeclaration>node).body, node => {
// TypeScript 1.0 spec (April 2014): 12.1.6
// An ExternalImportDeclaration in anAmbientExternalModuleDeclaration may reference other external modules
// only through top - level external module names. Relative external module names are not permitted.
collect(node, /*allowRelativeModuleNames*/ false, collectOnlyRequireCalls);
});
}
break;
}
}
if (isJavaScriptFile) {
if (isRequireCall(node)) {
(imports || (imports = [])).push(<StringLiteral>(<CallExpression>node).arguments[0]);
}
else {
forEachChild(node, node => collect(node, allowRelativeModuleNames, /*collectOnlyRequireCalls*/ true));
}
}
}
}
@@ -784,12 +977,12 @@ namespace ts {
}
// Get source file from normalized fileName
function findSourceFile(fileName: string, normalizedAbsolutePath: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
if (filesByName.contains(normalizedAbsolutePath)) {
const file = filesByName.get(normalizedAbsolutePath);
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
if (filesByName.contains(path)) {
const file = filesByName.get(path);
// try to check if we've already seen this file but with a different casing in path
// NOTE: this only makes sense for case-insensitive file systems
if (file && options.forceConsistentCasingInFileNames && getNormalizedAbsolutePath(file.fileName, currentDirectory) !== normalizedAbsolutePath) {
if (file && options.forceConsistentCasingInFileNames && getNormalizedAbsolutePath(file.fileName, currentDirectory) !== getNormalizedAbsolutePath(fileName, currentDirectory)) {
reportFileNamesDifferOnlyInCasingError(fileName, file.fileName, refFile, refPos, refEnd);
}
@@ -807,18 +1000,18 @@ namespace ts {
}
});
filesByName.set(normalizedAbsolutePath, file);
filesByName.set(path, file);
if (file) {
file.path = normalizedAbsolutePath;
file.path = path;
if (host.useCaseSensitiveFileNames()) {
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
const existingFile = filesByNameIgnoreCase.get(normalizedAbsolutePath);
const existingFile = filesByNameIgnoreCase.get(path);
if (existingFile) {
reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile, refPos, refEnd);
}
else {
filesByNameIgnoreCase.set(normalizedAbsolutePath, file);
filesByNameIgnoreCase.set(path, file);
}
}
@@ -833,7 +1026,6 @@ namespace ts {
processImportedModules(file, basePath);
if (isDefaultLib) {
file.isDefaultLib = true;
files.unshift(file);
}
else {
@@ -847,7 +1039,7 @@ namespace ts {
function processReferencedFiles(file: SourceFile, basePath: string) {
forEach(file.referencedFiles, ref => {
const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName);
processSourceFile(referencedFileName, /* isDefaultLib */ false, file, ref.pos, ref.end);
processSourceFile(referencedFileName, /*isDefaultLib*/ false, file, ref.pos, ref.end);
});
}
@@ -865,7 +1057,7 @@ namespace ts {
const resolution = resolutions[i];
setResolvedModule(file, moduleNames[i], resolution);
if (resolution && !options.noResolve) {
const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /* isDefaultLib */ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);
const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /*isDefaultLib*/ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);
if (importedFile && resolution.isExternalLibraryImport) {
if (!isExternalModule(importedFile)) {
@@ -889,7 +1081,7 @@ namespace ts {
function computeCommonSourceDirectory(sourceFiles: SourceFile[]): string {
let commonPathComponents: string[];
forEach(files, sourceFile => {
const failed = forEach(files, sourceFile => {
// Each file contributes into common source file path
if (isDeclarationFile(sourceFile)) {
return;
@@ -905,10 +1097,10 @@ namespace ts {
}
for (let i = 0, n = Math.min(commonPathComponents.length, sourcePathComponents.length); i < n; i++) {
if (commonPathComponents[i] !== sourcePathComponents[i]) {
if (getCanonicalFileName(commonPathComponents[i]) !== getCanonicalFileName(sourcePathComponents[i])) {
if (i === 0) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files));
return;
// Failed to find any common path component
return true;
}
// New common path found that is 0 -> i-1
@@ -923,6 +1115,15 @@ namespace ts {
}
});
// A common path can not be found when paths span multiple drives on windows, for example
if (failed) {
return "";
}
if (!commonPathComponents) { // Can happen when all input files are .d.ts files
return currentDirectory;
}
return getNormalizedPathFromPathComponents(commonPathComponents);
}
@@ -971,16 +1172,15 @@ namespace ts {
if (options.mapRoot) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap"));
}
if (options.sourceRoot) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceRoot", "inlineSourceMap"));
}
}
if (options.inlineSources) {
if (!options.sourceMap && !options.inlineSourceMap) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_inlineSources_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided));
}
if (options.sourceRoot) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceRoot", "inlineSources"));
}
}
if (options.out && options.outFile) {
@@ -992,10 +1192,9 @@ namespace ts {
if (options.mapRoot) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "mapRoot", "sourceMap"));
}
if (options.sourceRoot) {
if (options.sourceRoot && !options.inlineSourceMap) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "sourceRoot", "sourceMap"));
}
return;
}
const languageVersion = options.target || ScriptTarget.ES3;
@@ -1024,12 +1223,16 @@ namespace ts {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_compile_modules_into_es2015_when_targeting_ES5_or_lower));
}
// Cannot specify module gen that isn't amd or system with --out
if (outFile && options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile"));
}
// there has to be common source directory if user specified --outdir || --sourceRoot
// if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted
if (options.outDir || // there is --outDir specified
options.sourceRoot || // there is --sourceRoot specified
(options.mapRoot && // there is --mapRoot specified and there would be multiple js files generated
(!outFile || firstExternalModuleSourceFile !== undefined))) {
options.mapRoot) { // there is --mapRoot specified
if (options.rootDir && checkSourceFilesBelongToPath(files, options.rootDir)) {
// If a rootDir is specified and is valid use it as the commonSourceDirectory
@@ -1038,6 +1241,10 @@ namespace ts {
else {
// Compute the commonSourceDirectory from the input files
commonSourceDirectory = computeCommonSourceDirectory(files);
// If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure
if (options.outDir && commonSourceDirectory === "" && forEach(files, file => getRootLength(file.fileName) > 1)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files));
}
}
if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== directorySeparator) {
@@ -1065,11 +1272,49 @@ namespace ts {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmit", "declaration"));
}
}
else if (options.allowJs && options.declaration) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration"));
}
if (options.emitDecoratorMetadata &&
!options.experimentalDecorators) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDecoratorMetadata", "experimentalDecorators"));
}
// If the emit is enabled make sure that every output file is unique and not overwriting any of the input files
if (!options.noEmit) {
const emitHost = getEmitHost();
const emitFilesSeen = createFileMap<boolean>(!host.useCaseSensitiveFileNames() ? key => key.toLocaleLowerCase() : undefined);
forEachExpectedEmitFile(emitHost, (emitFileNames, sourceFiles, isBundledEmit) => {
verifyEmitFilePath(emitFileNames.jsFilePath, emitFilesSeen);
verifyEmitFilePath(emitFileNames.declarationFilePath, emitFilesSeen);
});
}
// Verify that all the emit files are unique and don't overwrite input files
function verifyEmitFilePath(emitFileName: string, emitFilesSeen: FileMap<boolean>) {
if (emitFileName) {
const emitFilePath = toPath(emitFileName, currentDirectory, getCanonicalFileName);
// Report error if the output overwrites input file
if (filesByName.contains(emitFilePath)) {
createEmitBlockingDiagnostics(emitFileName, emitFilePath, Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file);
}
// Report error if multiple files write into same file
if (emitFilesSeen.contains(emitFilePath)) {
// Already seen the same emit file - report error
createEmitBlockingDiagnostics(emitFileName, emitFilePath, Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files);
}
else {
emitFilesSeen.set(emitFilePath, true);
}
}
}
}
function createEmitBlockingDiagnostics(emitFileName: string, emitFilePath: Path, message: DiagnosticMessage) {
hasEmitBlockingDiagnostics.set(toPath(emitFileName, currentDirectory, getCanonicalFileName), true);
programDiagnostics.add(createCompilerDiagnostic(message, emitFileName));
}
}
}
+2 -2
View File
@@ -1634,11 +1634,11 @@ namespace ts {
}
function lookAhead<T>(callback: () => T): T {
return speculationHelper(callback, /*isLookahead:*/ true);
return speculationHelper(callback, /*isLookahead*/ true);
}
function tryScan<T>(callback: () => T): T {
return speculationHelper(callback, /*isLookahead:*/ false);
return speculationHelper(callback, /*isLookahead*/ false);
}
function setText(newText: string, start: number, length: number) {
+16 -5
View File
@@ -280,7 +280,7 @@ namespace ts {
}
if (commandLine.options.version) {
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Version_0, ts.version), /* compilerHost */ undefined);
printVersion();
return sys.exit(ExitStatus.Success);
}
@@ -303,7 +303,7 @@ namespace ts {
}
else if (commandLine.fileNames.length === 0 && isJSONSupported()) {
const searchPath = normalizePath(sys.getCurrentDirectory());
configFileName = findConfigFile(searchPath);
configFileName = findConfigFile(searchPath, sys.fileExists);
}
if (commandLine.fileNames.length === 0 && !configFileName) {
@@ -346,10 +346,21 @@ namespace ts {
return;
}
}
if (!cachedConfigFileText) {
const error = createCompilerDiagnostic(Diagnostics.File_0_not_found, configFileName);
reportDiagnostics([error], /* compilerHost */ undefined);
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
return;
}
const result = parseConfigFileTextToJson(configFileName, cachedConfigFileText);
const configObject = result.config;
const configParseResult = parseJsonConfigFileContent(configObject, sys, getDirectoryPath(configFileName));
if (!configObject) {
reportDiagnostics([result.error], /* compilerHost */ undefined);
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
return;
}
const configParseResult = parseJsonConfigFileContent(configObject, sys, getDirectoryPath(configFileName), commandLine.options);
if (configParseResult.errors.length > 0) {
reportDiagnostics(configParseResult.errors, /* compilerHost */ undefined);
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
@@ -365,7 +376,7 @@ namespace ts {
if (configFileName) {
const configParseResult = parseConfigFile();
rootFileNames = configParseResult.fileNames;
compilerOptions = extend(commandLine.options, configParseResult.options);
compilerOptions = configParseResult.options;
}
else {
rootFileNames = commandLine.fileNames;
@@ -458,7 +469,7 @@ namespace ts {
}
function watchedDirectoryChanged(fileName: string) {
if (fileName && !ts.isSupportedSourceFileName(fileName)) {
if (fileName && !ts.isSupportedSourceFileName(fileName, commandLine.options)) {
return;
}
+310 -58
View File
File diff suppressed because it is too large Load Diff
+206 -38
View File
@@ -1,4 +1,3 @@
/// <reference path="binder.ts" />
/// <reference path="sys.ts" />
/* @internal */
@@ -39,6 +38,8 @@ namespace ts {
getCanonicalFileName(fileName: string): string;
getNewLine(): string;
isEmitBlocked(emitFileName: string): boolean;
writeFile: WriteFileCallback;
}
@@ -362,6 +363,10 @@ namespace ts {
return file.externalModuleIndicator !== undefined;
}
export function isExternalOrCommonJsModule(file: SourceFile): boolean {
return (file.externalModuleIndicator || file.commonJsModuleIndicator) !== undefined;
}
export function isDeclarationFile(file: SourceFile): boolean {
return (file.flags & NodeFlags.DeclarationFile) !== 0;
}
@@ -1056,6 +1061,57 @@ namespace ts {
return node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind !== SyntaxKind.ExternalModuleReference;
}
export function isSourceFileJavaScript(file: SourceFile): boolean {
return isInJavaScriptFile(file);
}
export function isInJavaScriptFile(node: Node): boolean {
return node && !!(node.parserContextFlags & ParserContextFlags.JavaScriptFile);
}
/**
* Returns true if the node is a CallExpression to the identifier 'require' with
* exactly one string literal argument.
* This function does not test if the node is in a JavaScript file or not.
*/
export function isRequireCall(expression: Node): expression is CallExpression {
// of the form 'require("name")'
return expression.kind === SyntaxKind.CallExpression &&
(<CallExpression>expression).expression.kind === SyntaxKind.Identifier &&
(<Identifier>(<CallExpression>expression).expression).text === "require" &&
(<CallExpression>expression).arguments.length === 1 &&
(<CallExpression>expression).arguments[0].kind === SyntaxKind.StringLiteral;
}
/**
* Returns true if the node is an assignment to a property on the identifier 'exports'.
* This function does not test if the node is in a JavaScript file or not.
*/
export function isExportsPropertyAssignment(expression: Node): boolean {
// of the form 'exports.name = expr' where 'name' and 'expr' are arbitrary
return isInJavaScriptFile(expression) &&
(expression.kind === SyntaxKind.BinaryExpression) &&
((<BinaryExpression>expression).operatorToken.kind === SyntaxKind.EqualsToken) &&
((<BinaryExpression>expression).left.kind === SyntaxKind.PropertyAccessExpression) &&
((<PropertyAccessExpression>(<BinaryExpression>expression).left).expression.kind === SyntaxKind.Identifier) &&
((<Identifier>((<PropertyAccessExpression>(<BinaryExpression>expression).left).expression)).text === "exports");
}
/**
* Returns true if the node is an assignment to the property access expression 'module.exports'.
* This function does not test if the node is in a JavaScript file or not.
*/
export function isModuleExportsAssignment(expression: Node): boolean {
// of the form 'module.exports = expr' where 'expr' is arbitrary
return isInJavaScriptFile(expression) &&
(expression.kind === SyntaxKind.BinaryExpression) &&
((<BinaryExpression>expression).operatorToken.kind === SyntaxKind.EqualsToken) &&
((<BinaryExpression>expression).left.kind === SyntaxKind.PropertyAccessExpression) &&
((<PropertyAccessExpression>(<BinaryExpression>expression).left).expression.kind === SyntaxKind.Identifier) &&
((<Identifier>((<PropertyAccessExpression>(<BinaryExpression>expression).left).expression)).text === "module") &&
((<PropertyAccessExpression>(<BinaryExpression>expression).left).name.text === "exports");
}
export function getExternalModuleName(node: Node): Expression {
if (node.kind === SyntaxKind.ImportDeclaration) {
return (<ImportDeclaration>node).moduleSpecifier;
@@ -1273,7 +1329,7 @@ namespace ts {
}
// True if the given identifier, string literal, or number literal is the name of a declaration node
export function isDeclarationName(name: Node): boolean {
export function isDeclarationName(name: Node): name is Identifier | StringLiteral | LiteralExpression {
if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.StringLiteral && name.kind !== SyntaxKind.NumericLiteral) {
return false;
}
@@ -1435,6 +1491,10 @@ namespace ts {
return isFunctionLike(node) && (node.flags & NodeFlags.Async) !== 0 && !isAccessor(node);
}
export function isStringOrNumericLiteral(kind: SyntaxKind): boolean {
return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NumericLiteral;
}
/**
* A declaration has a dynamic name if both of the following are true:
* 1. The declaration has a computed property name
@@ -1443,9 +1503,13 @@ namespace ts {
* Symbol.
*/
export function hasDynamicName(declaration: Declaration): boolean {
return declaration.name &&
declaration.name.kind === SyntaxKind.ComputedPropertyName &&
!isWellKnownSymbolSyntactically((<ComputedPropertyName>declaration.name).expression);
return declaration.name && isDynamicName(declaration.name);
}
export function isDynamicName(name: DeclarationName): boolean {
return name.kind === SyntaxKind.ComputedPropertyName &&
!isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind) &&
!isWellKnownSymbolSyntactically((<ComputedPropertyName>name).expression);
}
/**
@@ -1483,7 +1547,7 @@ namespace ts {
return node.kind === SyntaxKind.Identifier && (<Identifier>node).text === "Symbol";
}
export function isModifier(token: SyntaxKind): boolean {
export function isModifierKind(token: SyntaxKind): boolean {
switch (token) {
case SyntaxKind.AbstractKeyword:
case SyntaxKind.AsyncKeyword:
@@ -1516,20 +1580,60 @@ namespace ts {
return isFunctionLike(n) || n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.SourceFile;
}
export function cloneEntityName(node: EntityName): EntityName {
if (node.kind === SyntaxKind.Identifier) {
const clone = <Identifier>createSynthesizedNode(SyntaxKind.Identifier);
clone.text = (<Identifier>node).text;
return clone;
/**
* Creates a shallow, memberwise clone of a node. The "kind", "pos", "end", "flags", and "parent"
* properties are excluded by default, and can be provided via the "location", "flags", and
* "parent" parameters.
* @param node The node to clone.
* @param location An optional TextRange to use to supply the new position.
* @param flags The NodeFlags to use for the cloned node.
* @param parent The parent for the new node.
*/
export function cloneNode<T extends Node>(node: T, location?: TextRange, flags?: NodeFlags, parent?: Node): T {
// We don't use "clone" from core.ts here, as we need to preserve the prototype chain of
// the original node. We also need to exclude specific properties and only include own-
// properties (to skip members already defined on the shared prototype).
const clone = location !== undefined
? <T>createNode(node.kind, location.pos, location.end)
: <T>createSynthesizedNode(node.kind);
for (const key in node) {
if (clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) {
continue;
}
(<any>clone)[key] = (<any>node)[key];
}
else {
const clone = <QualifiedName>createSynthesizedNode(SyntaxKind.QualifiedName);
clone.left = cloneEntityName((<QualifiedName>node).left);
clone.left.parent = clone;
clone.right = <Identifier>cloneEntityName((<QualifiedName>node).right);
clone.right.parent = clone;
return clone;
if (flags !== undefined) {
clone.flags = flags;
}
if (parent !== undefined) {
clone.parent = parent;
}
return clone;
}
/**
* Creates a deep clone of an EntityName, with new parent pointers.
* @param node The EntityName to clone.
* @param parent The parent for the cloned node.
*/
export function cloneEntityName(node: EntityName, parent?: Node): EntityName {
const clone = cloneNode(node, node, node.flags, parent);
if (isQualifiedName(clone)) {
const { left, right } = clone;
clone.left = cloneEntityName(left, clone);
clone.right = cloneNode(right, right, right.flags, parent);
}
return clone;
}
export function isQualifiedName(node: Node): node is QualifiedName {
return node.kind === SyntaxKind.QualifiedName;
}
export function nodeIsSynthesized(node: Node): boolean {
@@ -1660,6 +1764,7 @@ namespace ts {
"\u0085": "\\u0085" // nextLine
};
/**
* Based heavily on the abstract 'Quote'/'QuoteJSONString' operation from ECMA-262 (24.3.2.2),
* but augmented for a few select characters (e.g. lineSeparator, paragraphSeparator, nextLine)
@@ -1800,6 +1905,15 @@ namespace ts {
};
}
/**
* Resolves a local path to a path which is absolute to the base of the emit
*/
export function getExternalModuleNameFromPath(host: EmitHost, fileName: string): string {
const dir = host.getCurrentDirectory();
const relativePath = getRelativePathToDirectoryOrUrl(dir, fileName, dir, f => host.getCanonicalFileName(f), /*isAbsolutePathAnUrl*/ false);
return removeFileExtension(relativePath);
}
export function getOwnEmitOutputFilePath(sourceFile: SourceFile, host: EmitHost, extension: string) {
const compilerOptions = host.getCompilerOptions();
let emitOutputFilePathWithoutExtension: string;
@@ -1813,15 +1927,85 @@ namespace ts {
return emitOutputFilePathWithoutExtension + extension;
}
export function getEmitScriptTarget(compilerOptions: CompilerOptions) {
return compilerOptions.target || ScriptTarget.ES3;
}
export function getEmitModuleKind(compilerOptions: CompilerOptions) {
return compilerOptions.module ?
compilerOptions.module :
getEmitScriptTarget(compilerOptions) === ScriptTarget.ES6 ? ModuleKind.ES6 : ModuleKind.None;
}
export interface EmitFileNames {
jsFilePath: string;
sourceMapFilePath: string;
declarationFilePath: string;
}
export function forEachExpectedEmitFile(host: EmitHost,
action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) => void,
targetSourceFile?: SourceFile) {
const options = host.getCompilerOptions();
// Emit on each source file
if (options.outFile || options.out) {
onBundledEmit(host);
}
else {
const sourceFiles = targetSourceFile === undefined ? host.getSourceFiles() : [targetSourceFile];
for (const sourceFile of sourceFiles) {
if (!isDeclarationFile(sourceFile)) {
onSingleFileEmit(host, sourceFile);
}
}
}
function onSingleFileEmit(host: EmitHost, sourceFile: SourceFile) {
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host,
sourceFile.languageVariant === LanguageVariant.JSX && options.jsx === JsxEmit.Preserve ? ".jsx" : ".js");
const emitFileNames: EmitFileNames = {
jsFilePath,
sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
declarationFilePath: !isSourceFileJavaScript(sourceFile) ? getDeclarationEmitFilePath(jsFilePath, options) : undefined
};
action(emitFileNames, [sourceFile], /*isBundledEmit*/false);
}
function onBundledEmit(host: EmitHost) {
// Can emit only sources that are not declaration file and are either non module code or module with --module or --target es6 specified
const bundledSources = filter(host.getSourceFiles(),
sourceFile => !isDeclarationFile(sourceFile) && // Not a declaration file
(!isExternalModule(sourceFile) || // non module file
(getEmitModuleKind(options) && isExternalModule(sourceFile)))); // module that can emit - note falsy value from getEmitModuleKind means the module kind that shouldn't be emitted
if (bundledSources.length) {
const jsFilePath = options.outFile || options.out;
const emitFileNames: EmitFileNames = {
jsFilePath,
sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
declarationFilePath: getDeclarationEmitFilePath(jsFilePath, options)
};
action(emitFileNames, bundledSources, /*isBundledEmit*/true);
}
}
function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
return options.sourceMap ? jsFilePath + ".map" : undefined;
}
function getDeclarationEmitFilePath(jsFilePath: string, options: CompilerOptions) {
return options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined;
}
}
export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {
let sourceFilePath = getNormalizedAbsolutePath(sourceFile.fileName, host.getCurrentDirectory());
sourceFilePath = sourceFilePath.replace(host.getCommonSourceDirectory(), "");
return combinePaths(newDirPath, sourceFilePath);
}
export function writeFile(host: EmitHost, diagnostics: Diagnostic[], fileName: string, data: string, writeByteOrderMark: boolean) {
export function writeFile(host: EmitHost, diagnostics: DiagnosticCollection, fileName: string, data: string, writeByteOrderMark: boolean) {
host.writeFile(fileName, data, writeByteOrderMark, hostErrorMessage => {
diagnostics.push(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage));
diagnostics.add(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage));
});
}
@@ -1845,18 +2029,6 @@ namespace ts {
return accessor && accessor.parameters.length > 0 && accessor.parameters[0].type;
}
export function shouldEmitToOwnFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean {
if (!isDeclarationFile(sourceFile)) {
if ((isExternalModule(sourceFile) || !(compilerOptions.outFile || compilerOptions.out))) {
// 1. in-browser single file compilation scenario
// 2. non .js file
return compilerOptions.isolatedModules || !fileExtensionIs(sourceFile.fileName, ".js");
}
return false;
}
return false;
}
export function getAllAccessorDeclarations(declarations: NodeArray<Declaration>, accessor: AccessorDeclaration) {
let firstAccessor: AccessorDeclaration;
let secondAccessor: AccessorDeclaration;
@@ -2200,12 +2372,8 @@ namespace ts {
return symbol && symbol.valueDeclaration && (symbol.valueDeclaration.flags & NodeFlags.Default) ? symbol.valueDeclaration.localSymbol : undefined;
}
export function isJavaScript(fileName: string) {
return fileExtensionIs(fileName, ".js");
}
export function isTsx(fileName: string) {
return fileExtensionIs(fileName, ".tsx");
export function hasJavaScriptFileExtension(fileName: string) {
return forEach(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
}
/**
+33 -43
View File
@@ -40,89 +40,79 @@ class CompilerBaselineRunner extends RunnerBase {
this.basePath += "/" + this.testSuiteName;
}
private makeUnitName(name: string, root: string) {
return ts.isRootedDiskPath(name) ? name : ts.combinePaths(root, name);
};
public checkTestCodeOutput(fileName: string) {
describe("compiler tests for " + fileName, () => {
// Mocha holds onto the closure environment of the describe callback even after the test is done.
// Everything declared here should be cleared out in the "after" callback.
let justName: string;
let content: string;
let testCaseContent: { settings: Harness.TestCaseParser.CompilerSettings; testUnitData: Harness.TestCaseParser.TestUnitData[]; };
let units: Harness.TestCaseParser.TestUnitData[];
let tcSettings: Harness.TestCaseParser.CompilerSettings;
let lastUnit: Harness.TestCaseParser.TestUnitData;
let rootDir: string;
let harnessSettings: Harness.TestCaseParser.CompilerSettings;
let hasNonDtsFiles: boolean;
let result: Harness.Compiler.CompilerResult;
let program: ts.Program;
let options: ts.CompilerOptions;
// equivalent to the files that will be passed on the command line
let toBeCompiled: { unitName: string; content: string }[];
let toBeCompiled: Harness.Compiler.TestFile[];
// equivalent to other files on the file system not directly passed to the compiler (ie things that are referenced by other files)
let otherFiles: { unitName: string; content: string }[];
let harnessCompiler: Harness.Compiler.HarnessCompiler;
let otherFiles: Harness.Compiler.TestFile[];
before(() => {
justName = fileName.replace(/^.*[\\\/]/, ""); // strips the fileName from the path.
content = Harness.IO.readFile(fileName);
testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, fileName);
units = testCaseContent.testUnitData;
tcSettings = testCaseContent.settings;
const content = Harness.IO.readFile(fileName);
const testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, fileName);
const units = testCaseContent.testUnitData;
harnessSettings = testCaseContent.settings;
lastUnit = units[units.length - 1];
rootDir = lastUnit.originalFilePath.indexOf("conformance") === -1 ? "tests/cases/compiler/" : lastUnit.originalFilePath.substring(0, lastUnit.originalFilePath.lastIndexOf("/")) + "/";
harnessCompiler = Harness.Compiler.getCompiler();
hasNonDtsFiles = ts.forEach(units, unit => !ts.fileExtensionIs(unit.name, ".d.ts"));
const rootDir = lastUnit.originalFilePath.indexOf("conformance") === -1 ? "tests/cases/compiler/" : lastUnit.originalFilePath.substring(0, lastUnit.originalFilePath.lastIndexOf("/")) + "/";
// We need to assemble the list of input files for the compiler and other related files on the 'filesystem' (ie in a multi-file test)
// If the last file in a test uses require or a triple slash reference we'll assume all other files will be brought in via references,
// otherwise, assume all files are just meant to be in the same compilation session without explicit references to one another.
toBeCompiled = [];
otherFiles = [];
if (/require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) {
toBeCompiled.push({ unitName: rootDir + lastUnit.name, content: lastUnit.content });
toBeCompiled.push({ unitName: this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content });
units.forEach(unit => {
if (unit.name !== lastUnit.name) {
otherFiles.push({ unitName: rootDir + unit.name, content: unit.content });
otherFiles.push({ unitName: this.makeUnitName(unit.name, rootDir), content: unit.content });
}
});
}
else {
toBeCompiled = units.map(unit => {
return { unitName: rootDir + unit.name, content: unit.content };
return { unitName: this.makeUnitName(unit.name, rootDir), content: unit.content };
});
}
options = harnessCompiler.compileFiles(toBeCompiled, otherFiles, function (compileResult, _program) {
result = compileResult;
// The program will be used by typeWriter
program = _program;
}, function (settings) {
harnessCompiler.setCompilerSettings(tcSettings);
});
const output = Harness.Compiler.compileFiles(
toBeCompiled, otherFiles, harnessSettings, /* options */ undefined, /* currentDirectory */ undefined);
options = output.options;
result = output.result;
});
after(() => {
// Mocha holds onto the closure environment of the describe callback even after the test is done.
// Therefore we have to clean out large objects after the test is done.
justName = undefined;
content = undefined;
testCaseContent = undefined;
units = undefined;
tcSettings = undefined;
lastUnit = undefined;
rootDir = undefined;
hasNonDtsFiles = undefined;
result = undefined;
program = undefined;
options = undefined;
toBeCompiled = undefined;
otherFiles = undefined;
harnessCompiler = undefined;
});
function getByteOrderMarkText(file: Harness.Compiler.GeneratedFile): string {
return file.writeByteOrderMark ? "\u00EF\u00BB\u00BF" : "";
}
function getErrorBaseline(toBeCompiled: { unitName: string; content: string }[], otherFiles: { unitName: string; content: string }[], result: Harness.Compiler.CompilerResult) {
function getErrorBaseline(toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], result: Harness.Compiler.CompilerResult) {
return Harness.Compiler.getErrorBaseline(toBeCompiled.concat(otherFiles), result.errors);
}
@@ -151,7 +141,7 @@ class CompilerBaselineRunner extends RunnerBase {
});
it("Correct JS output for " + fileName, () => {
if (!ts.fileExtensionIs(lastUnit.name, ".d.ts") && this.emit) {
if (hasNonDtsFiles && this.emit) {
if (result.files.length === 0 && result.errors.length === 0) {
throw new Error("Expected at least one js file to be emitted or at least one error to be created.");
}
@@ -184,9 +174,9 @@ class CompilerBaselineRunner extends RunnerBase {
}
}
const declFileCompilationResult = harnessCompiler.compileDeclarationFiles(toBeCompiled, otherFiles, result, function (settings) {
harnessCompiler.setCompilerSettings(tcSettings);
}, options);
const declFileCompilationResult =
Harness.Compiler.compileDeclarationFiles(
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined);
if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) {
jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
@@ -257,10 +247,11 @@ class CompilerBaselineRunner extends RunnerBase {
// These types are equivalent, but depend on what order the compiler observed
// certain parts of the program.
const program = result.program;
const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName));
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ true);
const pullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ false);
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
const pullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ false);
const fullResults: ts.Map<TypeWriterResult[]> = {};
const pullResults: ts.Map<TypeWriterResult[]> = {};
@@ -274,14 +265,14 @@ class CompilerBaselineRunner extends RunnerBase {
// The second gives symbols for all identifiers.
let e1: Error, e2: Error;
try {
checkBaseLines(/*isSymbolBaseLine:*/ false);
checkBaseLines(/*isSymbolBaseLine*/ false);
}
catch (e) {
e1 = e;
}
try {
checkBaseLines(/*isSymbolBaseLine:*/ true);
checkBaseLines(/*isSymbolBaseLine*/ true);
}
catch (e) {
e2 = e;
@@ -367,7 +358,6 @@ class CompilerBaselineRunner extends RunnerBase {
public initializeTests() {
describe(this.testSuiteName + " tests", () => {
describe("Setup compiler for compiler baselines", () => {
const harnessCompiler = Harness.Compiler.getCompiler();
this.parseOptions();
});
+733 -286
View File
File diff suppressed because it is too large Load Diff
-50
View File
@@ -58,56 +58,6 @@ class FourSlashRunner extends RunnerBase {
}
});
});
describe("Generate Tao XML", () => {
const invalidReasons: any = {};
FourSlash.xmlData.forEach(xml => {
if (xml.invalidReason !== null) {
invalidReasons[xml.invalidReason] = (invalidReasons[xml.invalidReason] || 0) + 1;
}
});
const invalidReport: { reason: string; count: number }[] = [];
for (const reason in invalidReasons) {
if (invalidReasons.hasOwnProperty(reason)) {
invalidReport.push({ reason: reason, count: invalidReasons[reason] });
}
}
invalidReport.sort((lhs, rhs) => lhs.count > rhs.count ? -1 : lhs.count === rhs.count ? 0 : 1);
const lines: string[] = [];
lines.push("<!-- Blocked Test Report");
invalidReport.forEach((reasonAndCount) => {
lines.push(reasonAndCount.count + " tests blocked by " + reasonAndCount.reason);
});
lines.push("-->");
lines.push("<TaoTest xmlns=\"http://microsoft.com/schemas/VSLanguages/TAO\">");
lines.push(" <InitTest>");
lines.push(" <StartTarget />");
lines.push(" </InitTest>");
lines.push(" <ScenarioList>");
FourSlash.xmlData.forEach(xml => {
if (xml.invalidReason !== null) {
lines.push("<!-- Skipped " + xml.originalName + ", reason: " + xml.invalidReason + " -->");
}
else {
lines.push(" <Scenario Name=\"" + xml.originalName + "\">");
xml.actions.forEach(action => {
lines.push(" " + action);
});
lines.push(" </Scenario>");
}
});
lines.push(" </ScenarioList>");
lines.push(" <CleanupScenario>");
lines.push(" <CloseAllDocuments />");
lines.push(" <CleanupCreatedFiles />");
lines.push(" </CleanupScenario>");
lines.push(" <CleanupTest>");
lines.push(" <CloseTarget />");
lines.push(" </CleanupTest>");
lines.push("</TaoTest>");
Harness.IO.writeFile("built/local/fourslash.xml", lines.join("\r\n"));
});
});
}
}
+152 -271
View File
@@ -176,7 +176,9 @@ namespace Utils {
ts.forEachChild(node, child => { childNodesAndArrays.push(child); }, array => { childNodesAndArrays.push(array); });
for (const childName in node) {
if (childName === "parent" || childName === "nextContainer" || childName === "modifiers" || childName === "externalModuleIndicator") {
if (childName === "parent" || childName === "nextContainer" || childName === "modifiers" || childName === "externalModuleIndicator" ||
// for now ignore jsdoc comments
childName === "jsDocComment") {
continue;
}
const child = (<any>node)[childName];
@@ -628,7 +630,7 @@ namespace Harness {
function getResolvedPathFromServer(path: string) {
const xhr = new XMLHttpRequest();
try {
xhr.open("GET", path + "?resolve", false);
xhr.open("GET", path + "?resolve", /*async*/ false);
xhr.send();
}
catch (e) {
@@ -647,7 +649,7 @@ namespace Harness {
export function getFileFromServerSync(url: string): XHRResponse {
const xhr = new XMLHttpRequest();
try {
xhr.open("GET", url, false);
xhr.open("GET", url, /*async*/ false);
xhr.send();
}
catch (e) {
@@ -662,7 +664,7 @@ namespace Harness {
const xhr = new XMLHttpRequest();
try {
const actionMsg = "?action=" + action;
xhr.open("POST", url + actionMsg, false);
xhr.open("POST", url + actionMsg, /*async*/ false);
xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
xhr.send(contents);
}
@@ -767,26 +769,9 @@ namespace Harness {
}
namespace Harness {
let tcServicesFileName = "typescriptServices.js";
export let libFolder: string;
switch (Utils.getExecutionEnvironment()) {
case Utils.ExecutionEnvironment.CScript:
libFolder = "built/local/";
tcServicesFileName = "built/local/typescriptServices.js";
break;
case Utils.ExecutionEnvironment.Node:
libFolder = "built/local/";
tcServicesFileName = "built/local/typescriptServices.js";
break;
case Utils.ExecutionEnvironment.Browser:
libFolder = "built/local/";
tcServicesFileName = "built/local/typescriptServices.js";
break;
default:
throw new Error("Unknown context");
}
export let tcServicesFile = IO.readFile(tcServicesFileName);
export const libFolder = "built/local/";
const tcServicesFileName = ts.combinePaths(libFolder, "typescriptServices.js");
export const tcServicesFile = IO.readFile(tcServicesFileName);
export interface SourceMapEmitterCallback {
(emittedFile: string, emittedLine: number, emittedColumn: number, sourceFile: string, sourceLine: number, sourceColumn: number, sourceName: string): void;
@@ -827,57 +812,14 @@ namespace Harness {
}
}
export interface IEmitterIOHost {
writeFile(path: string, contents: string, writeByteOrderMark: boolean): void;
resolvePath(path: string): string;
}
/** Mimics having multiple files, later concatenated to a single file. */
export class EmitterIOHost implements IEmitterIOHost {
private fileCollection: any = {};
/** create file gets the whole path to create, so this works as expected with the --out parameter */
public writeFile(s: string, contents: string, writeByteOrderMark: boolean): void {
let writer: ITextWriter;
if (this.fileCollection[s]) {
writer = <ITextWriter>this.fileCollection[s];
}
else {
writer = new Harness.Compiler.WriterAggregator();
this.fileCollection[s] = writer;
}
writer.Write(contents);
writer.Close();
}
public resolvePath(s: string) { return s; }
public reset() { this.fileCollection = {}; }
public toArray(): { fileName: string; file: WriterAggregator; }[] {
const result: { fileName: string; file: WriterAggregator; }[] = [];
for (const p in this.fileCollection) {
if (this.fileCollection.hasOwnProperty(p)) {
const current = <Harness.Compiler.WriterAggregator>this.fileCollection[p];
if (current.lines.length > 0) {
if (p.indexOf(".d.ts") !== -1) { current.lines.unshift(["////[", Path.getFileName(p), "]"].join("")); }
result.push({ fileName: p, file: this.fileCollection[p] });
}
}
}
return result;
}
}
export function createSourceFileAndAssertInvariants(
fileName: string,
sourceText: string,
languageVersion: ts.ScriptTarget) {
// We'll only assert inletiants outside of light mode.
// We'll only assert invariants outside of light mode.
const shouldAssertInvariants = !Harness.lightMode;
// Only set the parent nodes if we're asserting inletiants. We don't need them otherwise.
// Only set the parent nodes if we're asserting invariants. We don't need them otherwise.
const result = ts.createSourceFile(fileName, sourceText, languageVersion, /*setParentNodes:*/ shouldAssertInvariants);
if (shouldAssertInvariants) {
@@ -890,12 +832,12 @@ namespace Harness {
const carriageReturnLineFeed = "\r\n";
const lineFeed = "\n";
export let defaultLibFileName = "lib.d.ts";
export let defaultLibSourceFile = createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.core.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest);
export let defaultES6LibSourceFile = createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.core.es6.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest);
export const defaultLibFileName = "lib.d.ts";
export const defaultLibSourceFile = createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.core.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest);
export const defaultES6LibSourceFile = createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.core.es6.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest);
// Cache these between executions so we don't have to re-parse them for every test
export let fourslashFileName = "fourslash.ts";
export const fourslashFileName = "fourslash.ts";
export let fourslashSourceFile: ts.SourceFile;
export function getCanonicalFileName(fileName: string): string {
@@ -903,41 +845,32 @@ namespace Harness {
}
export function createCompilerHost(
inputFiles: { unitName: string; content: string; }[],
inputFiles: TestFile[],
writeFile: (fn: string, contents: string, writeByteOrderMark: boolean) => void,
scriptTarget: ts.ScriptTarget,
useCaseSensitiveFileNames: boolean,
// the currentDirectory is needed for rwcRunner to passed in specified current directory to compiler host
currentDirectory?: string,
currentDirectory: string,
newLineKind?: ts.NewLineKind): ts.CompilerHost {
// Local get canonical file name function, that depends on passed in parameter for useCaseSensitiveFileNames
function getCanonicalFileName(fileName: string): string {
return useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
}
const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames);
const filemap: { [fileName: string]: ts.SourceFile; } = {};
const getCurrentDirectory = currentDirectory === undefined ? Harness.IO.getCurrentDirectory : () => currentDirectory;
// Register input files
function register(file: { unitName: string; content: string; }) {
const fileMap: ts.FileMap<ts.SourceFile> = ts.createFileMap<ts.SourceFile>();
for (const file of inputFiles) {
if (file.content !== undefined) {
const fileName = ts.normalizePath(file.unitName);
const sourceFile = createSourceFileAndAssertInvariants(fileName, file.content, scriptTarget);
filemap[getCanonicalFileName(fileName)] = sourceFile;
filemap[getCanonicalFileName(ts.getNormalizedAbsolutePath(fileName, getCurrentDirectory()))] = sourceFile;
const path = ts.toPath(file.unitName, currentDirectory, getCanonicalFileName);
fileMap.set(path, sourceFile);
}
};
inputFiles.forEach(register);
}
function getSourceFile(fn: string, languageVersion: ts.ScriptTarget) {
fn = ts.normalizePath(fn);
if (Object.prototype.hasOwnProperty.call(filemap, getCanonicalFileName(fn))) {
return filemap[getCanonicalFileName(fn)];
}
else if (currentDirectory) {
const canonicalAbsolutePath = getCanonicalFileName(ts.getNormalizedAbsolutePath(fn, currentDirectory));
return Object.prototype.hasOwnProperty.call(filemap, getCanonicalFileName(canonicalAbsolutePath)) ? filemap[canonicalAbsolutePath] : undefined;
const path = ts.toPath(fn, currentDirectory, getCanonicalFileName);
if (fileMap.contains(path)) {
return fileMap.get(path);
}
else if (fn === fourslashFileName) {
const tsFn = "tests/cases/fourslash/" + fourslashFileName;
@@ -959,7 +892,7 @@ namespace Harness {
Harness.IO.newLine();
return {
getCurrentDirectory,
getCurrentDirectory: () => currentDirectory,
getSourceFile,
getDefaultLibFileName: options => defaultLibFileName,
writeFile,
@@ -1034,177 +967,138 @@ namespace Harness {
}
}
export class HarnessCompiler {
private inputFiles: { unitName: string; content: string }[] = [];
private compileOptions: ts.CompilerOptions;
private settings: Harness.TestCaseParser.CompilerSettings = {};
export interface TestFile {
unitName: string;
content: string;
}
private lastErrors: ts.Diagnostic[];
export interface CompilationOutput {
result: CompilerResult;
options: ts.CompilerOptions & HarnessOptions;
}
public reset() {
this.inputFiles = [];
this.settings = {};
this.lastErrors = [];
export function compileFiles(
inputFiles: TestFile[],
otherFiles: TestFile[],
harnessSettings: TestCaseParser.CompilerSettings,
compilerOptions: ts.CompilerOptions,
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
currentDirectory: string): CompilationOutput {
const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.clone(compilerOptions) : { noResolve: false };
options.target = options.target || ts.ScriptTarget.ES3;
options.module = options.module || ts.ModuleKind.None;
options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed;
options.noErrorTruncation = true;
options.skipDefaultLibCheck = true;
currentDirectory = currentDirectory || Harness.IO.getCurrentDirectory();
// Parse settings
let useCaseSensitiveFileNames = Harness.IO.useCaseSensitiveFileNames();
if (harnessSettings) {
setCompilerOptionsFromHarnessSetting(harnessSettings, options);
}
if (options.useCaseSensitiveFileNames !== undefined) {
useCaseSensitiveFileNames = options.useCaseSensitiveFileNames;
}
public reportCompilationErrors() {
return this.lastErrors;
const programFiles: TestFile[] = inputFiles.slice();
// Files from built\local that are requested by test "@includeBuiltFiles" to be in the context.
// Treat them as library files, so include them in build, but not in baselines.
if (options.includeBuiltFile) {
const builtFileName = ts.combinePaths(libFolder, options.includeBuiltFile);
const builtFile: TestFile = {
unitName: builtFileName,
content: normalizeLineEndings(IO.readFile(builtFileName), Harness.IO.newLine()),
};
programFiles.push(builtFile);
}
public setCompilerSettings(tcSettings: Harness.TestCaseParser.CompilerSettings) {
this.settings = tcSettings;
const fileOutputs: GeneratedFile[] = [];
const programFileNames = programFiles.map(file => file.unitName);
const compilerHost = createCompilerHost(
programFiles.concat(otherFiles),
(fileName, code, writeByteOrderMark) => fileOutputs.push({ fileName, code, writeByteOrderMark }),
options.target,
useCaseSensitiveFileNames,
currentDirectory,
options.newLine);
const program = ts.createProgram(programFileNames, options, compilerHost);
const emitResult = program.emit();
const errors = ts.getPreEmitDiagnostics(program);
const result = new CompilerResult(fileOutputs, errors, program, Harness.IO.getCurrentDirectory(), emitResult.sourceMaps);
return { result, options };
}
export function compileDeclarationFiles(inputFiles: TestFile[],
otherFiles: TestFile[],
result: CompilerResult,
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions,
options: ts.CompilerOptions,
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
currentDirectory: string) {
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) {
throw new Error("There were no errors and declFiles generated did not match number of js files generated");
}
public addInputFiles(files: { unitName: string; content: string }[]) {
files.forEach(file => this.addInputFile(file));
const declInputFiles: TestFile[] = [];
const declOtherFiles: TestFile[] = [];
// if the .d.ts is non-empty, confirm it compiles correctly as well
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) {
ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles));
ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles));
const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory);
return { declInputFiles, declOtherFiles, declResult: output.result };
}
public addInputFile(file: { unitName: string; content: string }) {
this.inputFiles.push(file);
}
public setCompilerOptions(options?: ts.CompilerOptions) {
this.compileOptions = options || { noResolve: false };
}
public emitAll(ioHost?: IEmitterIOHost) {
this.compileFiles(this.inputFiles,
/*otherFiles*/ [],
/*onComplete*/ result => {
result.files.forEach(writeFile);
result.declFilesCode.forEach(writeFile);
result.sourceMaps.forEach(writeFile);
},
/*settingsCallback*/ () => { },
this.compileOptions);
function writeFile(file: GeneratedFile) {
ioHost.writeFile(file.fileName, file.code, false);
function addDtsFile(file: TestFile, dtsFiles: TestFile[]) {
if (isDTS(file.unitName)) {
dtsFiles.push(file);
}
}
public compileFiles(inputFiles: { unitName: string; content: string }[],
otherFiles: { unitName: string; content: string }[],
onComplete: (result: CompilerResult, program: ts.Program) => void,
settingsCallback?: (settings: ts.CompilerOptions) => void,
options?: ts.CompilerOptions & HarnessOptions,
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
currentDirectory?: string) {
options = options || { noResolve: false };
options.target = options.target || ts.ScriptTarget.ES3;
options.module = options.module || ts.ModuleKind.None;
options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed;
options.noErrorTruncation = true;
options.skipDefaultLibCheck = true;
if (settingsCallback) {
settingsCallback(null);
}
const newLine = "\r\n";
// Parse settings
setCompilerOptionsFromHarnessSetting(this.settings, options);
// Files from built\local that are requested by test "@includeBuiltFiles" to be in the context.
// Treat them as library files, so include them in build, but not in baselines.
const includeBuiltFiles: { unitName: string; content: string }[] = [];
if (options.includeBuiltFile) {
const builtFileName = libFolder + options.includeBuiltFile;
includeBuiltFiles.push({ unitName: builtFileName, content: normalizeLineEndings(IO.readFile(builtFileName), newLine) });
}
const useCaseSensitiveFileNames = options.useCaseSensitiveFileNames !== undefined ? options.useCaseSensitiveFileNames : Harness.IO.useCaseSensitiveFileNames();
const fileOutputs: GeneratedFile[] = [];
const programFiles = inputFiles.concat(includeBuiltFiles).map(file => file.unitName);
const compilerHost = createCompilerHost(
inputFiles.concat(includeBuiltFiles).concat(otherFiles),
(fn, contents, writeByteOrderMark) => fileOutputs.push({ fileName: fn, code: contents, writeByteOrderMark: writeByteOrderMark }),
options.target, useCaseSensitiveFileNames, currentDirectory, options.newLine);
const program = ts.createProgram(programFiles, options, compilerHost);
const emitResult = program.emit();
const errors = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
this.lastErrors = errors;
const result = new CompilerResult(fileOutputs, errors, program, Harness.IO.getCurrentDirectory(), emitResult.sourceMaps);
onComplete(result, program);
return options;
}
public compileDeclarationFiles(inputFiles: { unitName: string; content: string; }[],
otherFiles: { unitName: string; content: string; }[],
result: CompilerResult,
settingsCallback?: (settings: ts.CompilerOptions) => void,
options?: ts.CompilerOptions,
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
currentDirectory?: string) {
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) {
throw new Error("There were no errors and declFiles generated did not match number of js files generated");
}
const declInputFiles: { unitName: string; content: string }[] = [];
const declOtherFiles: { unitName: string; content: string }[] = [];
let declResult: Harness.Compiler.CompilerResult;
// if the .d.ts is non-empty, confirm it compiles correctly as well
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) {
ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles));
ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles));
this.compileFiles(declInputFiles, declOtherFiles, function (compileResult) { declResult = compileResult; },
settingsCallback, options, currentDirectory);
return { declInputFiles, declOtherFiles, declResult };
}
function addDtsFile(file: { unitName: string; content: string }, dtsFiles: { unitName: string; content: string }[]) {
if (isDTS(file.unitName)) {
dtsFiles.push(file);
}
else if (isTS(file.unitName)) {
const declFile = findResultCodeFile(file.unitName);
if (!findUnit(declFile.fileName, declInputFiles) && !findUnit(declFile.fileName, declOtherFiles)) {
dtsFiles.push({ unitName: declFile.fileName, content: declFile.code });
}
}
function findResultCodeFile(fileName: string) {
const sourceFile = result.program.getSourceFile(fileName);
assert(sourceFile, "Program has no source file with name '" + fileName + "'");
// Is this file going to be emitted separately
let sourceFileName: string;
const outFile = options.outFile || options.out;
if (ts.isExternalModule(sourceFile) || !outFile) {
if (options.outDir) {
let sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.fileName, result.currentDirectoryForProgram);
sourceFilePath = sourceFilePath.replace(result.program.getCommonSourceDirectory(), "");
sourceFileName = ts.combinePaths(options.outDir, sourceFilePath);
}
else {
sourceFileName = sourceFile.fileName;
}
}
else {
// Goes to single --out file
sourceFileName = outFile;
}
const dTsFileName = ts.removeFileExtension(sourceFileName) + ".d.ts";
return ts.forEach(result.declFilesCode, declFile => declFile.fileName === dTsFileName ? declFile : undefined);
}
function findUnit(fileName: string, units: { unitName: string; content: string; }[]) {
return ts.forEach(units, unit => unit.unitName === fileName ? unit : undefined);
else if (isTS(file.unitName)) {
const declFile = findResultCodeFile(file.unitName);
if (declFile && !findUnit(declFile.fileName, declInputFiles) && !findUnit(declFile.fileName, declOtherFiles)) {
dtsFiles.push({ unitName: declFile.fileName, content: declFile.code });
}
}
}
function findResultCodeFile(fileName: string) {
const sourceFile = result.program.getSourceFile(fileName);
assert(sourceFile, "Program has no source file with name '" + fileName + "'");
// Is this file going to be emitted separately
let sourceFileName: string;
const outFile = options.outFile || options.out;
if (!outFile) {
if (options.outDir) {
let sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.fileName, result.currentDirectoryForProgram);
sourceFilePath = sourceFilePath.replace(result.program.getCommonSourceDirectory(), "");
sourceFileName = ts.combinePaths(options.outDir, sourceFilePath);
}
else {
sourceFileName = sourceFile.fileName;
}
}
else {
// Goes to single --out file
sourceFileName = outFile;
}
const dTsFileName = ts.removeFileExtension(sourceFileName) + ".d.ts";
return ts.forEach(result.declFilesCode, declFile => declFile.fileName === dTsFileName ? declFile : undefined);
}
function findUnit(fileName: string, units: TestFile[]) {
return ts.forEach(units, unit => unit.unitName === fileName ? unit : undefined);
}
}
function normalizeLineEndings(text: string, lineEnding: string): string {
@@ -1230,7 +1124,7 @@ namespace Harness {
return errorOutput;
}
export function getErrorBaseline(inputFiles: { unitName: string; content: string }[], diagnostics: ts.Diagnostic[]) {
export function getErrorBaseline(inputFiles: TestFile[], diagnostics: ts.Diagnostic[]) {
diagnostics.sort(ts.compareDiagnostics);
const outputLines: string[] = [];
// Count up all errors that were found in files other than lib.d.ts so we don't miss any
@@ -1371,16 +1265,6 @@ namespace Harness {
}
}
/** The harness' compiler instance used when tests are actually run. Reseting or changing settings of this compiler instance must be done within a test case (i.e., describe/it) */
let harnessCompiler: HarnessCompiler;
/** Returns the singleton harness compiler instance for generating and running tests.
If required a fresh compiler instance will be created, otherwise the existing singleton will be re-used.
*/
export function getCompiler() {
return harnessCompiler = harnessCompiler || new HarnessCompiler();
}
// This does not need to exist strictly speaking, but many tests will need to be updated if it's removed
export function compileString(code: string, unitName: string, callback: (result: CompilerResult) => void) {
// NEWTODO: Re-implement 'compileString'
@@ -1431,7 +1315,7 @@ namespace Harness {
constructor(fileResults: GeneratedFile[], errors: ts.Diagnostic[], public program: ts.Program,
public currentDirectoryForProgram: string, private sourceMapData: ts.SourceMapData[]) {
fileResults.forEach(emittedFile => {
for (const emittedFile of fileResults) {
if (isDTS(emittedFile.fileName)) {
// .d.ts file, add to declFiles emit
this.declFilesCode.push(emittedFile);
@@ -1446,7 +1330,7 @@ namespace Harness {
else {
throw new Error("Unrecognized file extension for file " + emittedFile.fileName);
}
});
}
this.errors = errors;
}
@@ -1555,7 +1439,7 @@ namespace Harness {
}
// normalize the fileName for the single file case
currentFileName = testUnitData.length > 0 ? currentFileName : Path.getFileName(fileName);
currentFileName = testUnitData.length > 0 || currentFileName ? currentFileName : Path.getFileName(fileName);
// EOF, push whatever remains
const newTestFile2 = {
@@ -1674,7 +1558,7 @@ namespace Harness {
const encoded_actual = Utils.encodeString(actual);
if (expected != encoded_actual) {
// Overwrite & issue error
const errMsg = "The baseline file " + relativeFileName + " has changed";
const errMsg = "The baseline file " + relativeFileName + " has changed.";
throw new Error(errMsg);
}
}
@@ -1711,12 +1595,9 @@ namespace Harness {
return filePath.indexOf(Harness.libFolder) === 0;
}
export function getDefaultLibraryFile(io: Harness.IO): { unitName: string, content: string } {
export function getDefaultLibraryFile(io: Harness.IO): Harness.Compiler.TestFile {
const libFile = Harness.userSpecifiedRoot + Harness.libFolder + "lib.d.ts";
return {
unitName: libFile,
content: io.readFile(libFile)
};
return { unitName: libFile, content: io.readFile(libFile) };
}
if (Error) (<any>Error).stackTraceLimit = 1;
+12 -8
View File
@@ -7,7 +7,7 @@ namespace Harness.LanguageService {
export class ScriptInfo {
public version: number = 1;
public editRanges: { length: number; textChangeRange: ts.TextChangeRange; }[] = [];
public lineMap: number[] = undefined;
private lineMap: number[] = undefined;
constructor(public fileName: string, public content: string) {
this.setContent(content);
@@ -15,7 +15,11 @@ namespace Harness.LanguageService {
private setContent(content: string): void {
this.content = content;
this.lineMap = ts.computeLineStarts(content);
this.lineMap = undefined;
}
public getLineMap(): number[] {
return this.lineMap || (this.lineMap = ts.computeLineStarts(this.content));
}
public updateContent(content: string): void {
@@ -153,7 +157,7 @@ namespace Harness.LanguageService {
throw new Error("No script with name '" + fileName + "'");
}
public openFile(fileName: string): void {
public openFile(fileName: string, content?: string): void {
}
/**
@@ -164,7 +168,7 @@ namespace Harness.LanguageService {
const script: ScriptInfo = this.fileNameToScript[fileName];
assert.isNotNull(script);
return ts.computeLineAndCharacterOfPosition(script.lineMap, position);
return ts.computeLineAndCharacterOfPosition(script.getLineMap(), position);
}
}
@@ -197,7 +201,7 @@ namespace Harness.LanguageService {
getHost() { return this.host; }
getLanguageService(): ts.LanguageService { return ts.createLanguageService(this.host); }
getClassifier(): ts.Classifier { return ts.createClassifier(); }
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents); }
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents, /* readImportFiles */ true, ts.hasJavaScriptFileExtension(fileName)); }
}
/// Shim adapter
@@ -493,9 +497,9 @@ namespace Harness.LanguageService {
this.client = client;
}
openFile(fileName: string): void {
super.openFile(fileName);
this.client.openFile(fileName);
openFile(fileName: string, content?: string): void {
super.openFile(fileName, content);
this.client.openFile(fileName, content);
}
editScript(fileName: string, start: number, end: number, newText: string) {
+1 -1
View File
@@ -174,7 +174,7 @@ namespace Playback {
return true;
}
else {
return findResultByFields(replayLog.fileExists, { path }, false);
return findResultByFields(replayLog.fileExists, { path }, /*defaultValue*/ false);
}
})
);
+124 -69
View File
@@ -7,19 +7,11 @@ interface ProjectRunnerTestCase {
scenario: string;
projectRoot: string; // project where it lives - this also is the current directory when compiling
inputFiles: string[]; // list of input files to be given to program
out?: string; // --out
outDir?: string; // --outDir
sourceMap?: boolean; // --map
mapRoot?: string; // --mapRoot
resolveMapRoot?: boolean; // should we resolve this map root and give compiler the absolute disk path as map root?
sourceRoot?: string; // --sourceRoot
resolveSourceRoot?: boolean; // should we resolve this source root and give compiler the absolute disk path as map root?
declaration?: boolean; // --d
baselineCheck?: boolean; // Verify the baselines of output files, if this is false, we will write to output to the disk but there is no verification of baselines
runTest?: boolean; // Run the resulting test
bug?: string; // If there is any bug associated with this test case
noResolve?: boolean;
rootDir?: string; // --rootDir
}
interface ProjectRunnerTestCaseResolutionInfo extends ProjectRunnerTestCase {
@@ -34,14 +26,14 @@ interface BatchCompileProjectTestCaseEmittedFile extends Harness.Compiler.Genera
interface CompileProjectFilesResult {
moduleKind: ts.ModuleKind;
program: ts.Program;
program?: ts.Program;
compilerOptions?: ts.CompilerOptions;
errors: ts.Diagnostic[];
sourceMapData: ts.SourceMapData[];
sourceMapData?: ts.SourceMapData[];
}
interface BatchCompileProjectTestCaseResult extends CompileProjectFilesResult {
outputFiles: BatchCompileProjectTestCaseEmittedFile[];
nonSubfolderDiskFiles: number;
outputFiles?: BatchCompileProjectTestCaseEmittedFile[];
}
class ProjectRunner extends RunnerBase {
@@ -59,7 +51,7 @@ class ProjectRunner extends RunnerBase {
}
private runProjectTestCase(testCaseFileName: string) {
let testCase: ProjectRunnerTestCase;
let testCase: ProjectRunnerTestCase & ts.CompilerOptions;
let testFileText: string = null;
try {
@@ -70,7 +62,7 @@ class ProjectRunner extends RunnerBase {
}
try {
testCase = <ProjectRunnerTestCase>JSON.parse(testFileText);
testCase = <ProjectRunnerTestCase & ts.CompilerOptions>JSON.parse(testFileText);
}
catch (e) {
assert(false, "Testcase: " + testCaseFileName + " does not contain valid json format: " + e.message);
@@ -128,9 +120,10 @@ class ProjectRunner extends RunnerBase {
function compileProjectFiles(moduleKind: ts.ModuleKind, getInputFiles: () => string[],
getSourceFileTextImpl: (fileName: string) => string,
writeFile: (fileName: string, data: string, writeByteOrderMark: boolean) => void): CompileProjectFilesResult {
writeFile: (fileName: string, data: string, writeByteOrderMark: boolean) => void,
compilerOptions: ts.CompilerOptions): CompileProjectFilesResult {
const program = ts.createProgram(getInputFiles(), createCompilerOptions(), createCompilerHost());
const program = ts.createProgram(getInputFiles(), compilerOptions, createCompilerHost());
let errors = ts.getPreEmitDiagnostics(program);
const emitResult = program.emit();
@@ -155,21 +148,6 @@ class ProjectRunner extends RunnerBase {
sourceMapData
};
function createCompilerOptions(): ts.CompilerOptions {
return {
declaration: !!testCase.declaration,
sourceMap: !!testCase.sourceMap,
outFile: testCase.out,
outDir: testCase.outDir,
mapRoot: testCase.resolveMapRoot && testCase.mapRoot ? Harness.IO.resolvePath(testCase.mapRoot) : testCase.mapRoot,
sourceRoot: testCase.resolveSourceRoot && testCase.sourceRoot ? Harness.IO.resolvePath(testCase.sourceRoot) : testCase.sourceRoot,
module: moduleKind,
moduleResolution: ts.ModuleResolutionKind.Classic, // currently all tests use classic module resolution kind, this will change in the future
noResolve: testCase.noResolve,
rootDir: testCase.rootDir
};
}
function getSourceFileText(fileName: string): string {
const text = getSourceFileTextImpl(fileName);
return text !== undefined ? text : getSourceFileTextImpl(ts.getNormalizedAbsolutePath(fileName, getCurrentDirectory()));
@@ -209,23 +187,105 @@ class ProjectRunner extends RunnerBase {
let nonSubfolderDiskFiles = 0;
const outputFiles: BatchCompileProjectTestCaseEmittedFile[] = [];
let inputFiles = testCase.inputFiles;
let compilerOptions = createCompilerOptions();
const projectCompilerResult = compileProjectFiles(moduleKind, () => testCase.inputFiles, getSourceFileText, writeFile);
let configFileName: string;
if (compilerOptions.project) {
// Parse project
configFileName = ts.normalizePath(ts.combinePaths(compilerOptions.project, "tsconfig.json"));
assert(!inputFiles || inputFiles.length === 0, "cannot specify input files and project option together");
}
else if (!inputFiles || inputFiles.length === 0) {
configFileName = ts.findConfigFile("", fileExists);
}
if (configFileName) {
const result = ts.readConfigFile(configFileName, getSourceFileText);
if (result.error) {
return {
moduleKind,
errors: [result.error]
};
}
const configObject = result.config;
const configParseResult = ts.parseJsonConfigFileContent(configObject, { readDirectory }, ts.getDirectoryPath(configFileName), compilerOptions);
if (configParseResult.errors.length > 0) {
return {
moduleKind,
errors: configParseResult.errors
};
}
inputFiles = configParseResult.fileNames;
compilerOptions = configParseResult.options;
}
const projectCompilerResult = compileProjectFiles(moduleKind, () => inputFiles, getSourceFileText, writeFile, compilerOptions);
return {
moduleKind,
program: projectCompilerResult.program,
compilerOptions,
sourceMapData: projectCompilerResult.sourceMapData,
outputFiles,
errors: projectCompilerResult.errors,
nonSubfolderDiskFiles,
};
function createCompilerOptions() {
// Set the special options that depend on other testcase options
const compilerOptions: ts.CompilerOptions = {
mapRoot: testCase.resolveMapRoot && testCase.mapRoot ? Harness.IO.resolvePath(testCase.mapRoot) : testCase.mapRoot,
sourceRoot: testCase.resolveSourceRoot && testCase.sourceRoot ? Harness.IO.resolvePath(testCase.sourceRoot) : testCase.sourceRoot,
module: moduleKind,
moduleResolution: ts.ModuleResolutionKind.Classic, // currently all tests use classic module resolution kind, this will change in the future
};
// Set the values specified using json
const optionNameMap: ts.Map<ts.CommandLineOption> = {};
ts.forEach(ts.optionDeclarations, option => {
optionNameMap[option.name] = option;
});
for (const name in testCase) {
if (name !== "mapRoot" && name !== "sourceRoot" && ts.hasProperty(optionNameMap, name)) {
const option = optionNameMap[name];
const optType = option.type;
let value = <any>testCase[name];
if (typeof optType !== "string") {
const key = value.toLowerCase();
if (ts.hasProperty(optType, key)) {
value = optType[key];
}
}
compilerOptions[option.name] = value;
}
}
return compilerOptions;
}
function getFileNameInTheProjectTest(fileName: string): string {
return ts.isRootedDiskPath(fileName)
? fileName
: ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(fileName);
}
function readDirectory(rootDir: string, extension: string, exclude: string[]): string[] {
const harnessReadDirectoryResult = Harness.IO.readDirectory(getFileNameInTheProjectTest(rootDir), extension, exclude);
const result: string[] = [];
for (let i = 0; i < harnessReadDirectoryResult.length; i++) {
result[i] = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, harnessReadDirectoryResult[i],
getCurrentDirectory(), Harness.Compiler.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
}
return result;
}
function fileExists(fileName: string): boolean {
return Harness.IO.fileExists(getFileNameInTheProjectTest(fileName));
}
function getSourceFileText(fileName: string): string {
let text: string = undefined;
try {
text = Harness.IO.readFile(ts.isRootedDiskPath(fileName)
? fileName
: ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(fileName));
text = Harness.IO.readFile(getFileNameInTheProjectTest(fileName));
}
catch (e) {
// text doesn't get defined.
@@ -288,13 +348,16 @@ class ProjectRunner extends RunnerBase {
function compileCompileDTsFiles(compilerResult: BatchCompileProjectTestCaseResult) {
const allInputFiles: { emittedFileName: string; code: string; }[] = [];
if (!compilerResult.program) {
return;
}
const compilerOptions = compilerResult.program.getCompilerOptions();
ts.forEach(compilerResult.program.getSourceFiles(), sourceFile => {
if (Harness.Compiler.isDTS(sourceFile.fileName)) {
if (ts.isDeclarationFile(sourceFile)) {
allInputFiles.unshift({ emittedFileName: sourceFile.fileName, code: sourceFile.text });
}
else if (ts.shouldEmitToOwnFile(sourceFile, compilerResult.program.getCompilerOptions())) {
else if (!(compilerOptions.outFile || compilerOptions.out)) {
let emitOutputFilePathWithoutExtension: string = undefined;
if (compilerOptions.outDir) {
let sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.fileName, compilerResult.program.getCurrentDirectory());
@@ -306,7 +369,10 @@ class ProjectRunner extends RunnerBase {
}
const outputDtsFileName = emitOutputFilePathWithoutExtension + ".d.ts";
allInputFiles.unshift(findOutpuDtsFile(outputDtsFileName));
const file = findOutpuDtsFile(outputDtsFileName);
if (file) {
allInputFiles.unshift(file);
}
}
else {
const outputDtsFileName = ts.removeFileExtension(compilerOptions.outFile || compilerOptions.out) + ".d.ts";
@@ -317,7 +383,8 @@ class ProjectRunner extends RunnerBase {
}
});
return compileProjectFiles(compilerResult.moduleKind, getInputFiles, getSourceFileText, writeFile);
// Dont allow config files since we are compiling existing source options
return compileProjectFiles(compilerResult.moduleKind, getInputFiles, getSourceFileText, writeFile, compilerResult.compilerOptions);
function findOutpuDtsFile(fileName: string) {
return ts.forEach(compilerResult.outputFiles, outputFile => outputFile.emittedFileName === fileName ? outputFile : undefined);
@@ -343,11 +410,16 @@ class ProjectRunner extends RunnerBase {
}
function getErrorsBaseline(compilerResult: CompileProjectFilesResult) {
const inputFiles = ts.map(ts.filter(compilerResult.program.getSourceFiles(),
const inputFiles = compilerResult.program ? ts.map(ts.filter(compilerResult.program.getSourceFiles(),
sourceFile => sourceFile.fileName !== "lib.d.ts"),
sourceFile => {
return { unitName: sourceFile.fileName, content: sourceFile.text };
});
return {
unitName: ts.isRootedDiskPath(sourceFile.fileName) ?
RunnerBase.removeFullPaths(sourceFile.fileName) :
sourceFile.fileName,
content: sourceFile.text
};
}) : [];
return Harness.Compiler.getErrorBaseline(inputFiles, compilerResult.errors);
}
@@ -360,34 +432,17 @@ class ProjectRunner extends RunnerBase {
let compilerResult: BatchCompileProjectTestCaseResult;
function getCompilerResolutionInfo() {
const resolutionInfo: ProjectRunnerTestCaseResolutionInfo = {
scenario: testCase.scenario,
projectRoot: testCase.projectRoot,
inputFiles: testCase.inputFiles,
out: testCase.out,
outDir: testCase.outDir,
sourceMap: testCase.sourceMap,
mapRoot: testCase.mapRoot,
resolveMapRoot: testCase.resolveMapRoot,
sourceRoot: testCase.sourceRoot,
resolveSourceRoot: testCase.resolveSourceRoot,
declaration: testCase.declaration,
baselineCheck: testCase.baselineCheck,
runTest: testCase.runTest,
bug: testCase.bug,
rootDir: testCase.rootDir,
resolvedInputFiles: ts.map(compilerResult.program.getSourceFiles(), inputFile => {
return ts.convertToRelativePath(inputFile.fileName, getCurrentDirectory(), path => Harness.Compiler.getCanonicalFileName(path));
}),
emittedFiles: ts.map(compilerResult.outputFiles, outputFile => {
return ts.convertToRelativePath(outputFile.emittedFileName, getCurrentDirectory(), path => Harness.Compiler.getCanonicalFileName(path));
})
};
const resolutionInfo: ProjectRunnerTestCaseResolutionInfo & ts.CompilerOptions = JSON.parse(JSON.stringify(testCase));
resolutionInfo.resolvedInputFiles = ts.map(compilerResult.program.getSourceFiles(), inputFile => {
return ts.convertToRelativePath(inputFile.fileName, getCurrentDirectory(), path => Harness.Compiler.getCanonicalFileName(path));
});
resolutionInfo.emittedFiles = ts.map(compilerResult.outputFiles, outputFile => {
return ts.convertToRelativePath(outputFile.emittedFileName, getCurrentDirectory(), path => Harness.Compiler.getCanonicalFileName(path));
});
return resolutionInfo;
}
it(name + ": " + moduleNameToString(moduleKind) , () => {
it(name + ": " + moduleNameToString(moduleKind), () => {
// Compile using node
compilerResult = batchCompilerProjectTestCase(moduleKind);
});
@@ -439,7 +494,7 @@ class ProjectRunner extends RunnerBase {
it("Errors in generated Dts files for (" + moduleNameToString(moduleKind) + "): " + testCaseFileName, () => {
if (!compilerResult.errors.length && testCase.declaration) {
const dTsCompileResult = compileCompileDTsFiles(compilerResult);
if (dTsCompileResult.errors.length) {
if (dTsCompileResult && dTsCompileResult.errors.length) {
Harness.Baseline.runBaseline("Errors in generated Dts files for (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".dts.errors.txt", () => {
return getErrorsBaseline(dTsCompileResult);
});
+13 -11
View File
@@ -27,8 +27,8 @@ namespace RWC {
export function runRWCTest(jsonPath: string) {
describe("Testing a RWC project: " + jsonPath, () => {
let inputFiles: { unitName: string; content: string; }[] = [];
let otherFiles: { unitName: string; content: string; }[] = [];
let inputFiles: Harness.Compiler.TestFile[] = [];
let otherFiles: Harness.Compiler.TestFile[] = [];
let compilerResult: Harness.Compiler.CompilerResult;
let compilerOptions: ts.CompilerOptions;
let baselineOpts: Harness.Baseline.BaselineOptions = {
@@ -55,7 +55,6 @@ namespace RWC {
});
it("can compile", () => {
const harnessCompiler = Harness.Compiler.getCompiler();
let opts: ts.ParsedCommandLine;
const ioLog: IOLog = JSON.parse(Harness.IO.readFile(jsonPath));
@@ -71,8 +70,6 @@ namespace RWC {
});
runWithIOLog(ioLog, oldIO => {
harnessCompiler.reset();
let fileNames = opts.fileNames;
const tsconfigFile = ts.forEach(ioLog.filesRead, f => isTsConfigFile(f) ? f : undefined);
@@ -128,17 +125,21 @@ namespace RWC {
opts.options.noLib = true;
// Emit the results
compilerOptions = harnessCompiler.compileFiles(
compilerOptions = null;
const output = Harness.Compiler.compileFiles(
inputFiles,
otherFiles,
newCompilerResults => { compilerResult = newCompilerResults; },
/*settingsCallback*/ undefined, opts.options,
/* harnessOptions */ undefined,
opts.options,
// Since each RWC json file specifies its current directory in its json file, we need
// to pass this information in explicitly instead of acquiring it from the process.
currentDirectory);
compilerOptions = output.options;
compilerResult = output.result;
});
function getHarnessCompilerInputUnit(fileName: string) {
function getHarnessCompilerInputUnit(fileName: string): Harness.Compiler.TestFile {
const unitName = ts.normalizeSlashes(Harness.IO.resolvePath(fileName));
let content: string = null;
try {
@@ -201,8 +202,9 @@ namespace RWC {
it("has the expected errors in generated declaration files", () => {
if (compilerOptions.declaration && !compilerResult.errors.length) {
Harness.Baseline.runBaseline("has the expected errors in generated declaration files", baseName + ".dts.errors.txt", () => {
const declFileCompilationResult = Harness.Compiler.getCompiler().compileDeclarationFiles(inputFiles, otherFiles, compilerResult,
/*settingscallback*/ undefined, compilerOptions, currentDirectory);
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory);
if (declFileCompilationResult.declResult.errors.length === 0) {
return null;
}
+1 -1
View File
@@ -190,7 +190,7 @@ namespace Harness.SourceMapRecoder {
return { error: errorDecodeOfEncodedMapping, sourceMapSpan: decodeOfEncodedMapping };
}
createErrorIfCondition(true, "No encoded entry found");
createErrorIfCondition(/*condition*/ true, "No encoded entry found");
}
export function hasCompletedDecoding() {
+17 -14
View File
@@ -5,9 +5,9 @@
class Test262BaselineRunner extends RunnerBase {
private static basePath = "internal/cases/test262";
private static helpersFilePath = "tests/cases/test262-harness/helpers.d.ts";
private static helperFile = {
private static helperFile: Harness.Compiler.TestFile = {
unitName: Test262BaselineRunner.helpersFilePath,
content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath)
content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath),
};
private static testFileExtensionRegex = /\.js$/;
private static options: ts.CompilerOptions = {
@@ -31,8 +31,7 @@ class Test262BaselineRunner extends RunnerBase {
let testState: {
filename: string;
compilerResult: Harness.Compiler.CompilerResult;
inputFiles: { unitName: string; content: string }[];
program: ts.Program;
inputFiles: Harness.Compiler.TestFile[];
};
before(() => {
@@ -40,8 +39,9 @@ class Test262BaselineRunner extends RunnerBase {
const testFilename = ts.removeFileExtension(filePath).replace(/\//g, "_") + ".test";
const testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, testFilename);
const inputFiles = testCaseContent.testUnitData.map(unit => {
return { unitName: Test262BaselineRunner.getTestFilePath(unit.name), content: unit.content };
const inputFiles: Harness.Compiler.TestFile[] = testCaseContent.testUnitData.map(unit => {
const unitName = Test262BaselineRunner.getTestFilePath(unit.name);
return { unitName, content: unit.content };
});
// Emit the results
@@ -49,13 +49,16 @@ class Test262BaselineRunner extends RunnerBase {
filename: testFilename,
inputFiles: inputFiles,
compilerResult: undefined,
program: undefined,
};
Harness.Compiler.getCompiler().compileFiles([Test262BaselineRunner.helperFile].concat(inputFiles), /*otherFiles*/ [], (compilerResult, program) => {
testState.compilerResult = compilerResult;
testState.program = program;
}, /*settingsCallback*/ undefined, Test262BaselineRunner.options);
const output = Harness.Compiler.compileFiles(
[Test262BaselineRunner.helperFile].concat(inputFiles),
/*otherFiles*/ [],
/* harnessOptions */ undefined,
Test262BaselineRunner.options,
/* currentDirectory */ undefined
);
testState.compilerResult = output.result;
});
after(() => {
@@ -80,14 +83,14 @@ class Test262BaselineRunner extends RunnerBase {
}, false, Test262BaselineRunner.baselineOptions);
});
it("satisfies inletiants", () => {
const sourceFile = testState.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename));
it("satisfies invariants", () => {
const sourceFile = testState.compilerResult.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename));
Utils.assertInvariants(sourceFile, /*parent:*/ undefined);
});
it("has the expected AST", () => {
Harness.Baseline.runBaseline("has the expected AST", testState.filename + ".AST.txt", () => {
const sourceFile = testState.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename));
const sourceFile = testState.compilerResult.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename));
return Utils.sourceFileToJSON(sourceFile);
}, false, Test262BaselineRunner.baselineOptions);
});
+2 -2
View File
@@ -120,8 +120,8 @@ namespace ts.server {
return response;
}
openFile(fileName: string): void {
var args: protocol.FileRequestArgs = { file: fileName };
openFile(fileName: string, content?: string): void {
var args: protocol.OpenRequestArgs = { file: fileName, fileContent: content };
this.processRequest(CommandNames.Open, args);
}
+20 -8
View File
@@ -371,6 +371,10 @@ namespace ts.server {
openRefCount = 0;
constructor(public projectService: ProjectService, public projectOptions?: ProjectOptions) {
if (projectOptions && projectOptions.files) {
// If files are listed explicitly, allow all extensions
projectOptions.compilerOptions.allowNonTsExtensions = true;
}
this.compilerService = new CompilerService(this, projectOptions && projectOptions.compilerOptions);
}
@@ -384,7 +388,7 @@ namespace ts.server {
}
openReferencedFile(filename: string) {
return this.projectService.openFile(filename, false);
return this.projectService.openFile(filename, /*openedByClient*/ false);
}
getRootFiles() {
@@ -461,6 +465,7 @@ namespace ts.server {
setProjectOptions(projectOptions: ProjectOptions) {
this.projectOptions = projectOptions;
if (projectOptions.compilerOptions) {
projectOptions.compilerOptions.allowNonTsExtensions = true;
this.compilerService.setCompilerOptions(projectOptions.compilerOptions);
}
}
@@ -559,7 +564,7 @@ namespace ts.server {
// If a change was made inside "folder/file", node will trigger the callback twice:
// one with the fileName being "folder/file", and the other one with "folder".
// We don't respond to the second one.
if (fileName && !ts.isSupportedSourceFileName(fileName)) {
if (fileName && !ts.isSupportedSourceFileName(fileName, project.projectOptions ? project.projectOptions.compilerOptions : undefined)) {
return;
}
@@ -1001,14 +1006,15 @@ namespace ts.server {
/**
* @param filename is absolute pathname
* @param fileContent is a known version of the file content that is more up to date than the one on disk
*/
openFile(fileName: string, openedByClient: boolean) {
openFile(fileName: string, openedByClient: boolean, fileContent?: string) {
fileName = ts.normalizePath(fileName);
let info = ts.lookUp(this.filenameToScriptInfo, fileName);
if (!info) {
let content: string;
if (this.host.fileExists(fileName)) {
content = this.host.readFile(fileName);
content = fileContent || this.host.readFile(fileName);
}
if (!content) {
if (openedByClient) {
@@ -1025,6 +1031,9 @@ namespace ts.server {
}
}
if (info) {
if (fileContent) {
info.svc.reload(fileContent);
}
if (openedByClient) {
info.isOpen = true;
}
@@ -1055,10 +1064,11 @@ namespace ts.server {
/**
* Open file whose contents is managed by the client
* @param filename is absolute pathname
* @param fileContent is a known version of the file content that is more up to date than the one on disk
*/
openClientFile(fileName: string) {
openClientFile(fileName: string, fileContent?: string) {
this.openOrUpdateConfiguredProjectForFile(fileName);
const info = this.openFile(fileName, true);
const info = this.openFile(fileName, /*openedByClient*/ true, fileContent);
this.addOpenFile(info);
this.printProjects();
return info;
@@ -1267,7 +1277,7 @@ namespace ts.server {
for (const fileName of fileNamesToAdd) {
let info = this.getScriptInfo(fileName);
if (!info) {
info = this.openFile(fileName, false);
info = this.openFile(fileName, /*openedByClient*/ false);
}
else {
// if the root file was opened by client, it would belong to either
@@ -1316,7 +1326,9 @@ namespace ts.server {
this.setCompilerOptions(opt);
}
else {
this.setCompilerOptions(ts.getDefaultCompilerOptions());
const defaultOpts = ts.getDefaultCompilerOptions();
defaultOpts.allowNonTsExtensions = true;
this.setCompilerOptions(defaultOpts);
}
this.languageService = ts.createLanguageService(this.host, this.documentRegistry);
this.classifier = ts.createClassifier();
+5
View File
@@ -513,6 +513,11 @@ declare namespace ts.server.protocol {
* Information found in an "open" request.
*/
export interface OpenRequestArgs extends FileRequestArgs {
/**
* Used when a version of the file content is known to be more up to date than the one on disk.
* Then the known content will be used upon opening instead of the disk copy
*/
fileContent?: string;
}
/**
+8 -4
View File
@@ -532,9 +532,13 @@ namespace ts.server {
};
}
private openClientFile(fileName: string) {
/**
* @param fileName is the name of the file to be opened
* @param fileContent is a version of the file content that is known to be more up to date than the one on disk
*/
private openClientFile(fileName: string, fileContent?: string) {
const file = ts.normalizePath(fileName);
this.projectService.openClientFile(file);
this.projectService.openClientFile(file, fileContent);
}
private getQuickInfo(line: number, offset: number, fileName: string): protocol.QuickInfoResponseBody {
@@ -897,7 +901,7 @@ namespace ts.server {
}
getDiagnosticsForProject(delay: number, fileName: string) {
const { configFileName, fileNames } = this.getProjectInfo(fileName, true);
const { configFileName, fileNames } = this.getProjectInfo(fileName, /*needFileNameList*/ true);
// No need to analyze lib.d.ts
let fileNamesInProject = fileNames.filter((value, index, array) => value.indexOf("lib.d.ts") < 0);
@@ -968,7 +972,7 @@ namespace ts.server {
},
[CommandNames.Open]: (request: protocol.Request) => {
const openArgs = <protocol.OpenRequestArgs>request.arguments;
this.openClientFile(openArgs.file);
this.openClientFile(openArgs.file, openArgs.fileContent);
return {responseRequired: false};
},
[CommandNames.Quickinfo]: (request: protocol.Request) => {
+2 -2
View File
@@ -14,7 +14,7 @@ namespace ts.formatting {
constructor(from: SyntaxKind, to: SyntaxKind, except: SyntaxKind[]) {
this.tokens = [];
for (let token = from; token <= to; token++) {
if (except.indexOf(token) < 0) {
if (ts.indexOf(except, token) < 0) {
this.tokens.push(token);
}
}
@@ -123,4 +123,4 @@ namespace ts.formatting {
static TypeNames = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.SymbolKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]);
}
}
}
}
+1 -1
View File
@@ -2,7 +2,7 @@
/* @internal */
namespace ts.NavigationBar {
export function getNavigationBarItems(sourceFile: SourceFile): ts.NavigationBarItem[] {
export function getNavigationBarItems(sourceFile: SourceFile, compilerOptions: CompilerOptions): ts.NavigationBarItem[] {
// If the source file has any child items, then it included in the tree
// and takes lexical ownership of all other top-level items.
let hasGlobalNode = false;
+355 -394
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -956,7 +956,8 @@ namespace ts {
return this.forwardJSONCall(
"getPreProcessedFileInfo('" + fileName + "')",
() => {
var result = preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()));
// for now treat files as JavaScript
var result = preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()), /* readImportFiles */ true, /* detectJavaScriptImports */ true);
var convertResult = {
referencedFiles: <IFileReference[]>[],
importedFiles: <IFileReference[]>[],
+1 -1
View File
@@ -204,7 +204,7 @@ namespace ts.SignatureHelp {
if (!candidates.length) {
// We didn't have any sig help items produced by the TS compiler. If this is a JS
// file, then see if we can figure out anything better.
if (isJavaScript(sourceFile.fileName)) {
if (isSourceFileJavaScript(sourceFile)) {
return createJavaScriptSignatureHelpItems(argumentInfo);
}